diff options
19 files changed, 1450 insertions, 554 deletions
diff --git a/.classpath b/.classpath index bb012ba81..064f05938 100644 --- a/.classpath +++ b/.classpath @@ -31,6 +31,6 @@ <classpathentry combineaccessrules="false" kind="src" path="/gluegen"/> <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/Ant"/> <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/SWT"/> - <classpathentry kind="lib" path="/gluegen/make/lib/android-sdk/9/android.jar" sourcepath="/gluegen/make/lib/android-sdk/9/android-java-src.zip"/> + <classpathentry kind="lib" path="/gluegen/make/lib/android-sdk/15/android.jar" sourcepath="/gluegen/make/lib/android-sdk/15/android-java-src.zip"/> <classpathentry kind="output" path="build/eclipse-classes"/> </classpath> diff --git a/make/build-common.xml b/make/build-common.xml index c18cf89b4..dfe38a676 100644 --- a/make/build-common.xml +++ b/make/build-common.xml @@ -287,6 +287,7 @@ <property name="jogl.os.x11.jar" value="${build.jogl}/jogl.os.x11.jar" /> <property name="jogl.os.win.jar" value="${build.jogl}/jogl.os.win.jar" /> <property name="jogl.os.osx.jar" value="${build.jogl}/jogl.os.osx.jar" /> + <property name="jogl.os.android.jar" value="${build.jogl}/jogl.os.android.jar" /> <property name="jogl.gldesktop.jar" value="${build.jogl}/jogl.gldesktop.jar" /> <property name="jogl.gldesktop.dbg.jar" value="${build.jogl}/jogl.gldesktop.dbg.jar" /> <property name="jogl.glugldesktop.jar" value="${build.jogl}/jogl.glu.gldesktop.jar" /> @@ -343,6 +344,17 @@ <pathelement location="${jogl.util.fixedfuncemu.jar}" /> <pathelement location="${jogl.omx.jar}" /> </path> + <path id="jogl_all-android_atoms.classpath"> + <pathelement location="${jogl.core.jar}" /> + <pathelement location="${jogl.glmobile.jar}" /> + <pathelement location="${jogl.glmobile.dbg.jar}" /> + <pathelement location="${jogl.util.jar}" /> + <pathelement location="${jogl.glutess.jar}" /> + <pathelement location="${jogl.glumipmap.jar}" /> + <pathelement location="${jogl.util.fixedfuncemu.jar}" /> + <pathelement location="${jogl.os.android.jar}" /> + <pathelement location="${jogl.omx.jar}" /> + </path> <!-- ${jogl.core.jar} ${jogl.glutess.jar} ${jogl.glumipmap.jar} ${jogl.glugldesktop.jar} ${jogl.os.x11.jar} ${jogl.os.win.jar} ${jogl.os.osx.jar} ${jogl.gldesktop.jar} ${jogl.gldesktop.dbg.jar} ${jogl.glmobile.jar} ${jogl.glmobile.dbg.jar} ${jogl.omx.jar} ${jogl.util.jar} ${jogl.util.gldesktop.jar} ${jogl.util.awt.jar} ${jogl.util.fixedfuncemu.jar} ${jogl.sdk.jar} --> diff --git a/make/build-jogl.xml b/make/build-jogl.xml index 875fba709..ace272b74 100644 --- a/make/build-jogl.xml +++ b/make/build-jogl.xml @@ -108,7 +108,7 @@ value="jogamp/opengl/glu/gl2/** jogamp/opengl/glu/nurbs/** jogamp/opengl/glu/registry/** javax/media/opengl/glu/gl2/**"/> <property name="java.part.openmax" - value="com/jogamp/openmax/** jogamp/openmax/**"/> + value="jogamp/opengl/omx/**"/> <property name="java.part.sdk" value="com/jogamp/opengl/util/glsl/sdk/**"/> @@ -122,6 +122,9 @@ <property name="java.part.cgl" value="jogamp/opengl/macosx/cgl/*"/> + <property name="java.part.android" + value="jogamp/opengl/android/**"/> + <property name="java.part.gldesktop" value="jogamp/opengl/**/gl2/** jogamp/opengl/**/gl3/** jogamp/opengl/**/gl4/**"/> @@ -173,6 +176,9 @@ <property name="java.part.util.fixedfuncemu.shadercode" value="jogamp/opengl/util/glsl/fixedfunc/shaders/* jogamp/opengl/util/glsl/fixedfunc/shaders/bin/**"/> + <property name="java.part.util.av" + value="com/jogamp/opengl/av/** jogamp/opengl/av/**"/> + <property name="java.part.nonjava" value="${java.part.util.fixedfuncemu.shadercode} ${java.part.util.graph.shadercode} ${java.part.util.graph.fonts}"/> @@ -191,13 +197,20 @@ <isset property="setup.noSWT"/> </condition> + <condition property="java.excludes.android" + value="${java.part.android}"> + <not> + <isset property="isAndroid"/> + </not> + </condition> + <property name="java.excludes.javadoc.packagenames" value="jogamp.opengl.gl2.fixme.*,com.jogamp.audio.windows.waveout.TestSpatialization"/> <property name="java.excludes.fixme" value="jogamp/opengl/gl2/fixme/** com/jogamp/audio/windows/waveout/TestSpatialization.java" /> - <property name="java.excludes.all" value="${java.excludes.fixme} ${java.excludes.awt} ${java.excludes.swt}" /> + <property name="java.excludes.all" value="${java.excludes.fixme} ${java.excludes.awt} ${java.excludes.swt} ${java.excludes.android}" /> <echo message="java.excludes.all: ${java.excludes.all}" /> </target> @@ -1356,7 +1369,7 @@ <!-- FIXME: the Mixer should be moved to another library --> <!--include name="${rootrel.src.c}/Mixer.cpp" if="isWindows"/--> <include name="${rootrel.src.c.openmax}/omx_tool.c" if="setup.addNativeOpenMAX"/> - <include name="${rootrel.src.c.openmax}/com_jogamp_openmax_OMXInstance.c" if="setup.addNativeOpenMAX"/> + <include name="${rootrel.src.c.openmax}/jogamp_opengl_omx_OMXGLMediaPlayer.c" if="setup.addNativeOpenMAX"/> <include name="${rootrel.generated.c.jogl}/gl4/GL4bcImpl_JNI.c"/> <!--include name="${rootrel.generated.c.jogl}/GLU_JNI.c"/ EMPTY --> @@ -1372,7 +1385,7 @@ <include name="${rootrel.src.c}/GLDebugMessageHandler.c"/> <include name="${rootrel.src.c}/GLXGetProcAddressARB.c" if="isX11"/> <include name="${rootrel.src.c.openmax}/omx_tool.c" if="setup.addNativeOpenMAX"/> - <include name="${rootrel.src.c.openmax}/com_jogamp_openmax_OMXInstance.c" if="setup.addNativeOpenMAX"/> + <include name="${rootrel.src.c.openmax}/jogamp_opengl_omx_OMXGLMediaPlayer.c" if="setup.addNativeOpenMAX"/> <include name="${rootrel.generated.c.jogl}/egl/EGL_JNI.c"/> <include name="${rootrel.generated.c.jogl}/egl/EGLExtImpl_JNI.c"/> @@ -1466,7 +1479,7 @@ </macrodef> <target name="c.build.jogl.prepare.openMAX" if="setup.addNativeOpenMAX"> - <javah destdir="${src.generated.c.openmax}" classpath="${javah.classpath}" class="com.jogamp.openmax.OMXInstance" /> + <javah destdir="${src.generated.c.openmax}" classpath="${javah.classpath}" class="jogamp.opengl.omx.OMXGLMediaPlayer" /> </target> <target name="c.build.jogl.prepare" depends="c.build.jogl.prepare.openMAX"> @@ -1554,6 +1567,12 @@ </jar> </target> + <target name="build-jars-android" depends="setup-manifestfile" if="isAndroid"> + <jar manifest="${build.jogl}/manifest.mf" destfile="${jogl.os.android.jar}" filesonly="true"> + <fileset dir="${classes}" includes="${java.part.android}"/> + </jar> + </target> + <target name="build-jars-mobile-javase" depends="setup-manifestfile"> <jar manifest="${build.jogl}/manifest.mf" destfile="${jogl.glmobile.jar}" filesonly="true"> <fileset dir="${classes}" @@ -1608,7 +1627,8 @@ </jar> </target> - <target name="build-jars-javase" depends="setup-manifestfile, build-jars-mobile-javase, build-jars-desktop-javase, build-jars-awt-javase, build-jars-swt-javase"> + <target name="build-jars-javase" depends="setup-manifestfile, build-jars-android, build-jars-mobile-javase, + build-jars-desktop-javase, build-jars-awt-javase, build-jars-swt-javase"> <jar manifest="${build.jogl}/manifest.mf" destfile="${jogl.core.jar}" filesonly="true"> <fileset dir="${classes}" includes="${java.part.core}" @@ -1628,7 +1648,7 @@ </jar> <jar manifest="${build.jogl}/manifest.mf" destfile="${jogl.util.jar}" filesonly="true"> <fileset dir="${classes}" - includes="${java.part.util} ${java.part.util.glsl} ${java.part.util.graph}" + includes="${java.part.util} ${java.part.util.glsl} ${java.part.util.graph} ${java.part.util.av}" excludes="${java.part.util.awt} ${java.part.util.gldesktop} ${java.part.util.fixedfuncemu}"/> </jar> <jar manifest="${build.jogl}/manifest.mf" destfile="${jogl.util.fixedfuncemu.jar}" filesonly="true"> diff --git a/make/build.xml b/make/build.xml index 203132816..24670fcce 100644 --- a/make/build.xml +++ b/make/build.xml @@ -103,7 +103,7 @@ <archives> <zips> <path refid="nativewindow_core_atoms.classpath"/> - <path refid="jogl_all-mobile_atoms.classpath"/> + <path refid="jogl_all-android_atoms.classpath"/> <path refid="newt_all-android_atoms.classpath"/> </zips> </archives> diff --git a/src/jogl/classes/com/jogamp/opengl/av/GLMediaEventListener.java b/src/jogl/classes/com/jogamp/opengl/av/GLMediaEventListener.java new file mode 100644 index 000000000..a02c8a362 --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/av/GLMediaEventListener.java @@ -0,0 +1,17 @@ + +package com.jogamp.opengl.av; + +import com.jogamp.opengl.av.GLMediaPlayer.TextureFrame; + +public interface GLMediaEventListener { + + static final int EVENT_CHANGE_SIZE = 1<<0; + static final int EVENT_CHANGE_FPS = 1<<1; + static final int EVENT_CHANGE_BPS = 1<<2; + static final int EVENT_CHANGE_LENGTH = 1<<3; + + public void attributesChanges(GLMediaPlayer mp, int event_mask); + public void newFrameAvailable(GLMediaPlayer mp, TextureFrame frame); + +} + diff --git a/src/jogl/classes/com/jogamp/opengl/av/GLMediaPlayer.java b/src/jogl/classes/com/jogamp/opengl/av/GLMediaPlayer.java new file mode 100644 index 000000000..71e0e16d9 --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/av/GLMediaPlayer.java @@ -0,0 +1,90 @@ +package com.jogamp.opengl.av; + +import java.io.IOException; +import java.net.URL; + +import javax.media.opengl.GL; + +import com.jogamp.opengl.util.texture.Texture; + +/** + * Lifecycle of an GLMediaPlayer: + * <ul> + * <li>{@link #setStream(GL, URL)}</li> + * <li>{@link #start()}</li> + * <li>{@link #stop()}</li> + * <li>{@link #destroy(GL)}</li> + * </ul> + */ +public interface GLMediaPlayer { + + public static class TextureFrame { + public TextureFrame(Texture t) { + texture = t; + } + + public final Texture getTexture() { return texture; } + + public String toString() { + return "TextureFrame[" + texture + "]"; + } + protected final Texture texture; + } + + /** Sets the stream to be used. Initializes all stream related states and GL resources. */ + public void setStream(GL gl, URL url) throws IOException; + + /** Releases the GL and stream resources. */ + public void destroy(GL gl); + + public void setPlaySpeed(float rate); + + public float getPlaySpeed(); + + public void start(); + + public void pause(); + + public void stop(); + + /** + * @return time current position in milliseconds + **/ + public int getCurrentPosition(); + + /** + * @param msec absolute desired time position in milliseconds + * @return time current position in milliseconds, after seeking to the desired position + **/ + public int seek(int msec); + + public Texture getLastTextureID(); + + public Texture getNextTextureID(); + + public boolean isValid(); + + public URL getURL(); + + public String getVideoCodec(); + + public String getAudioCodec(); + + public long getTotalFrames(); + + public long getBitrate(); + + public int getFramerate(); + + public int getWidth(); + + public int getHeight(); + + public String toString(); + + public void addEventListener(GLMediaEventListener l); + + public void removeEventListener(GLMediaEventListener l); + + public GLMediaEventListener[] getEventListeners(); +} diff --git a/src/jogl/classes/com/jogamp/opengl/av/GLMediaPlayerFactory.java b/src/jogl/classes/com/jogamp/opengl/av/GLMediaPlayerFactory.java new file mode 100644 index 000000000..0025a70ba --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/av/GLMediaPlayerFactory.java @@ -0,0 +1,18 @@ +package com.jogamp.opengl.av; + +import com.jogamp.common.os.AndroidVersion; +import com.jogamp.common.os.Platform; +import com.jogamp.common.util.ReflectionUtil; + +public class GLMediaPlayerFactory { + private static final String AndroidGLMediaPlayerAPI14ClazzName = "jogamp.opengl.android.av.AndroidGLMediaPlayerAPI14"; + + public static GLMediaPlayer create() { + if(Platform.OS_TYPE.equals(Platform.OSType.ANDROID)) { + if(AndroidVersion.SDK_INT >= 14) { + return (GLMediaPlayer) ReflectionUtil.createInstance(AndroidGLMediaPlayerAPI14ClazzName, GLMediaPlayerFactory.class.getClassLoader()); + } + } + return null; + } +} diff --git a/src/jogl/classes/com/jogamp/openmax/OMXEventListener.java b/src/jogl/classes/com/jogamp/openmax/OMXEventListener.java deleted file mode 100644 index 08cfeccde..000000000 --- a/src/jogl/classes/com/jogamp/openmax/OMXEventListener.java +++ /dev/null @@ -1,14 +0,0 @@ - -package com.jogamp.openmax; - -public interface OMXEventListener { - - static final int EVENT_CHANGE_SIZE = 1<<0; - static final int EVENT_CHANGE_FPS = 1<<1; - static final int EVENT_CHANGE_BPS = 1<<2; - static final int EVENT_CHANGE_LENGTH = 1<<3; - - public void changedAttributes(OMXInstance omx, int event_mask); - -} - diff --git a/src/jogl/classes/com/jogamp/openmax/OMXInstance.java b/src/jogl/classes/com/jogamp/openmax/OMXInstance.java deleted file mode 100644 index 7c373a0ef..000000000 --- a/src/jogl/classes/com/jogamp/openmax/OMXInstance.java +++ /dev/null @@ -1,509 +0,0 @@ - -package com.jogamp.openmax; - -import javax.media.opengl.*; -import javax.media.opengl.glu.GLU; -import com.jogamp.opengl.util.texture.*; - -import jogamp.opengl.egl.EGL; -import jogamp.opengl.egl.EGLContext; -import jogamp.opengl.egl.EGLDrawable; -import jogamp.opengl.egl.EGLExt; - -import java.net.URL; -import java.nio.ByteBuffer; -import java.io.File; -import java.io.FileNotFoundException; -import java.util.*; - -public class OMXInstance { - private long moviePtr = 0; - - protected String path = null; - protected URL url = null; - - // *** Texture impl - protected Texture texture = null; // holds the last fetched texture - - protected float playSpeed = 1.0f; - - /** - * The following data is set by the setStream function, - * and may be set by the native OMX implementation, - * in case the stream attributes changes (see attributesUpdated) - */ - protected int width = 0; - protected int height = 0; - protected int fps = 0; // frames per seconds - protected long bps = 0; // bits per seconds - protected long totalFrames = 0; // duration in frames - protected String acodec = null; - protected String vcodec = null; - - /** - * Old stream values, before the last attributesUpdated) - */ - protected int o_width = 0; - protected int o_height = 0; - protected int o_fps = 0; // frames per seconds - protected long o_bps = 0; // bits per seconds - protected long o_totalFrames = 0; // duration in frames - - static class EGLImageTexture { - public EGLImageTexture(com.jogamp.opengl.util.texture.Texture t, long i, long s) { - texture = t; image = i; sync = s; - } - public String toString() { - return "EGLImageTexture[" + texture + ", image " + image + ", sync "+sync+"]"; - } - protected com.jogamp.opengl.util.texture.Texture texture; - protected long image; - protected long sync; - } - private EGLImageTexture[] eglImgTexs=null; - private HashMap eglImgTexsMap = new HashMap(); - protected int textureNum; - - private EGLExt eglExt = null; - private long eglSurface = 0; - private long eglDisplay = 0; - private long eglContext = 0; - private int sWidth=0, sHeight=0; - - private GL initGLData(GL gl) { - if(null==gl) { - throw new RuntimeException("No current GL"); - } - EGLContext eglCtx = (EGLContext) gl.getContext(); - if(null==eglCtx) { - throw new RuntimeException("No current EGL context"); - } - EGLDrawable eglDrawable = (EGLDrawable) eglCtx.getGLDrawable(); - if(null==eglDrawable) { - throw new RuntimeException("No valid drawable"); - } - eglContext = eglCtx.getHandle(); - eglDisplay = eglDrawable.getDisplay(); - eglSurface = eglDrawable.getHandle(); - eglExt = eglCtx.getEGLExt(); - if(null==eglExt) { - throw new RuntimeException("No valid EGLExt"); - } - - int iTmp[] = new int[1]; - EGL.eglQuerySurface(eglDisplay, eglSurface, EGL.EGL_WIDTH, iTmp, 0); - sWidth=iTmp[0]; - EGL.eglQuerySurface(eglDisplay, eglSurface, EGL.EGL_HEIGHT, iTmp, 0); - sHeight=iTmp[0]; - System.out.println("surface size: "+width+"x"+height); - System.out.println(eglDrawable); - System.out.println(eglCtx); - System.out.println("EGL Extensions : "+EGL.eglQueryString(eglDisplay, EGL.EGL_EXTENSIONS)); - System.out.println("EGL CLIENT APIs: "+EGL.eglQueryString(eglDisplay, EGL.EGL_CLIENT_APIS)); - return gl; - } - - public OMXInstance() { - moviePtr = _createInstance(); - if(0==moviePtr) { - throw new GLException("Couldn't create OMXInstance"); - } - } - native long _createInstance(); - - public synchronized void setStream(int textureNum, URL u) { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - this.textureNum=textureNum; - url = u; - if (url == null) { - System.out.println("setURL (null)"); - stop(); - return; - } - path=null; - if (url.getProtocol() == null || "file".equals(url.getProtocol())) { - // CV only accepts absolute paths - try { - File file = new File(url.getPath()); - if (!file.exists()) { - throw new RuntimeException(new FileNotFoundException(file.toString())); - } - path = file.getCanonicalPath(); - System.out.println("setURL: path "+path); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - path = replaceAll(path, "\\", "/").trim(); - if(null==path) { - throw new RuntimeException("Couldn't parse stream URL: "+url); - } - System.out.println("setURL: clean path "+path); - - System.out.println("setURL: p1 "+this); - _setStream(moviePtr, textureNum, path); - System.out.println("setURL: p2 "+this); - } - native void _setStream(long moviePtr, int textureNum, String path); - - public synchronized void setStreamAllEGLImageTexture2D(GL gl) { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - if(null==vcodec) { - return; - } - gl = initGLData(gl); - - if(null!=eglImgTexs) { - removeAllEGLImageTexture2D(gl); - } else { - eglImgTexs = new EGLImageTexture[textureNum]; - } - - int[] tmp = new int[1]; - int tex, e; - - errorCheckGL(gl, "i.1"); - gl.glEnable(gl.GL_TEXTURE_2D); - errorCheckGL(gl, "i.2"); - - for(int i=0; i<textureNum; i++) { - String s0 = String.valueOf(i); - gl.glGenTextures(1, tmp, 0); - tex=tmp[0]; - if( (e=gl.glGetError()) != GL.GL_NO_ERROR || 0>tex ) { - throw new RuntimeException("TextureName creation failed: "+e); - } - gl.glBindTexture(gl.GL_TEXTURE_2D, tex); - - // create space for buffer with a texture - gl.glTexImage2D( - gl.GL_TEXTURE_2D, // target - 0, // level - gl.GL_RGBA, // internal format - width, // width - height, // height - 0, // border - gl.GL_RGBA, // format - gl.GL_UNSIGNED_BYTE, // type - null); // pixels -- will be provided later - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST); - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST); - - long image=0, sync=0; - - // create EGLImage from texture - tmp[0] = EGL.EGL_NONE; - image = eglExt.eglCreateImageKHR( - eglDisplay, - eglContext, - eglExt.EGL_GL_TEXTURE_2D_KHR, - tex, - tmp, 0); - if (0==image) { - throw new RuntimeException("EGLImage creation failed: "+EGL.eglGetError()+", dpy "+eglDisplay+", ctx "+eglContext+", tex "+tex); - } - - // Create sync object so that we can be sure that gl has finished - // rendering the EGLImage texture before we tell OpenMAX to fill - // it with a new frame. - tmp[0] = EGL.EGL_NONE; - sync = eglExt.eglCreateSyncKHR( - eglDisplay, - eglExt.EGL_SYNC_FENCE_KHR, tmp, 0); - - _setStreamEGLImageTexture2D(moviePtr, i, tex, image, sync); - - eglImgTexs[i] = new EGLImageTexture( - com.jogamp.opengl.util.texture.TextureIO.newTexture(tex, - javax.media.opengl.GL2.GL_TEXTURE_2D, - width, - height, - width, - height, - true), - image, sync); - eglImgTexsMap.put(new Integer(tex), eglImgTexs[i]); - } - gl.glDisable(gl.GL_TEXTURE_2D); - } - native void _setStreamEGLImageTexture2D(long moviePtr, int i, int tex, long image, long sync); - - public synchronized void activateStream() { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - _activateStream(moviePtr); - } - native void _activateStream(long moviePtr); - - public synchronized void detachVideoRenderer() { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - _detachVideoRenderer(moviePtr); - } - native void _detachVideoRenderer(long moviePtr); // stop before - - public synchronized void attachVideoRenderer() { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - _attachVideoRenderer(moviePtr); - } - native void _attachVideoRenderer(long moviePtr); // detach before - - public synchronized void setPlaySpeed(float rate) { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - _setPlaySpeed(moviePtr, rate); - playSpeed = rate; - } - public synchronized float getPlaySpeed() { - return playSpeed; - } - native void _setPlaySpeed(long moviePtr, float rate); - - /** @return time position after issuing the command */ - public synchronized float play() { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - return _play(moviePtr); - } - native float _play(long moviePtr); - - /** @return time position after issuing the command */ - public synchronized float pause() { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - return _pause(moviePtr); - } - native float _pause(long moviePtr); - - /** @return time position after issuing the command */ - public synchronized float stop() { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - return _stop(moviePtr); - } - native float _stop(long moviePtr); - - /** @return time position after issuing the command */ - public synchronized float seek(float pos) { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - return _seek(moviePtr, pos); - } - native float _seek(long moviePtr, float position); - - public synchronized Texture getLastTextureID() { - return texture; - } - public synchronized Texture getNextTextureID() { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - texture=null; - EGLImageTexture eglImgTex = (EGLImageTexture) eglImgTexsMap.get(new Integer(_getNextTextureID(moviePtr))); - if(null!=eglImgTex) { - texture = eglImgTex.texture; - } - return texture; - } - native int _getNextTextureID(long moviePtr); - - public synchronized float getCurrentPosition() { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - return _getCurrentPosition(moviePtr); - } - native float _getCurrentPosition(long moviePtr); - - public synchronized void destroy(GL gl) { - removeAllEGLImageTexture2D(gl); - if (moviePtr != 0) { - long ptr = moviePtr; - moviePtr = 0; - _destroyInstance(ptr); - - eglExt=null; - eglSurface=0; - eglDisplay=0; - eglContext=0; - } - } - protected synchronized void finalize() { - if (moviePtr != 0) { - destroy(null); - } - } - native void _destroyInstance(long moviePtr); - - public synchronized boolean isValid() { - return (moviePtr != 0); - } - public synchronized String getPath() { - return path; - } - public synchronized URL getURL() { - return url; - } - public synchronized String getVideoCodec() { - return vcodec; - } - public synchronized String getAudioCodec() { - return acodec; - } - public synchronized long getTotalFrames() { - return totalFrames; - } - public synchronized long getBitrate() { - return bps; - } - public synchronized int getFramerate() { - return fps; - } - public synchronized int getWidth() { - return width; - } - public synchronized int getHeight() { - return height; - } - public synchronized String toString() { - return "OMXInstance [ stream [ video [ "+vcodec+", "+width+"x"+height+", "+fps+"fps, "+bps+"bsp, "+totalFrames+"f ] ] ]"; - } - - /** - * Java callback method issued by the native OMX backend - */ - private void saveAttributes() { - o_width = width; - o_height = height; - o_fps = fps; - o_bps = bps; - o_totalFrames = totalFrames; - } - - private void attributesUpdated() { - int event_mask = 0; - if( o_width != width || o_height != height ) { - event_mask |= OMXEventListener.EVENT_CHANGE_SIZE; - } - if( o_fps != fps ) { - event_mask |= OMXEventListener.EVENT_CHANGE_FPS; - } - if( o_bps != bps ) { - event_mask |= OMXEventListener.EVENT_CHANGE_BPS; - } - if( o_totalFrames != totalFrames ) { - event_mask |= OMXEventListener.EVENT_CHANGE_LENGTH; - } - if(0==event_mask) { - return; - } - - ArrayList listeners = null; - synchronized(this) { - listeners = eventListeners; - } - for(Iterator i = listeners.iterator(); i.hasNext(); ) { - OMXEventListener l = (OMXEventListener) i.next(); - l.changedAttributes(this, event_mask); - } - } - - private String replaceAll(String orig, String search, String repl) { - String dest=null; - // In case replaceAll / java.util.regex.* is not supported (-> CVM) - int i=0,j; - dest = new String(); - while((j=orig.indexOf(search, i))>=0) { - dest=dest.concat(orig.substring(i, j)); - dest=dest.concat(repl); - i=j+1; - } - return dest.concat(orig.substring(i, orig.length())); - } - - private void removeAllEGLImageTexture2D(GL gl) { - if (moviePtr != 0) { - if(null==eglExt) { - throw new RuntimeException("No valid EGLExt"); - } - - texture = null; - for(int i=0; i<textureNum; i++) { - if(null!=eglImgTexs[i]) { - if(0!=eglImgTexs[i].image) { - eglExt.eglDestroyImageKHR( - eglDisplay, - eglImgTexs[i].image); - } - if(0!=eglImgTexs[i].sync) { - eglExt.eglDestroySyncKHR(eglDisplay, eglImgTexs[i].sync); - } - if(null!=gl) { - eglImgTexs[i].texture.destroy(gl); - } - eglImgTexs[i]=null; - } - } - eglImgTexsMap.clear(); - } - } - - private void errorCheckGL(GL gl, String s) { - int e; - if( (e=gl.glGetError()) != GL.GL_NO_ERROR ) { - System.out.println("GL Error: ("+s+"): "+e); - } - } - - private void errorCheckEGL(String s) { - int e; - if( (e=EGL.eglGetError()) != EGL.EGL_SUCCESS ) { - System.out.println("EGL Error: ("+s+"): 0x"+Integer.toHexString(e)); - } - } - - - // - // OMXEventListener Support - // - - public synchronized void addEventListener(OMXEventListener l) { - if(l == null) { - return; - } - ArrayList newEventListeners = (ArrayList) eventListeners.clone(); - newEventListeners.add(l); - eventListeners = newEventListeners; - } - - public synchronized void removeEventListener(OMXEventListener l) { - if (l == null) { - return; - } - ArrayList newEventListeners = (ArrayList) eventListeners.clone(); - newEventListeners.remove(l); - eventListeners = newEventListeners; - } - - public synchronized OMXEventListener[] getEventListeners() { - return (OMXEventListener[]) eventListeners.toArray(); - } - - private ArrayList eventListeners = new ArrayList(); - -} - diff --git a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java new file mode 100644 index 000000000..adfe2a048 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java @@ -0,0 +1,195 @@ +package jogamp.opengl.android.av; + +import java.io.IOException; +import java.net.URL; + +import javax.media.opengl.GL; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLES2; + +import jogamp.common.os.android.StaticContext; +import jogamp.opengl.av.GLMediaPlayerImpl; + +import android.graphics.SurfaceTexture; +import android.graphics.SurfaceTexture.OnFrameAvailableListener; +import android.media.MediaPlayer; +import android.net.Uri; +import android.view.Surface; + +import com.jogamp.opengl.av.GLMediaEventListener; +import com.jogamp.opengl.av.GLMediaPlayer; +import com.jogamp.opengl.av.GLMediaPlayer.TextureFrame; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.TextureCoords; + +/*** + * Android API Level 14: {@link MediaPlayer#setSurface(Surface)} + * Android API Level 14: {@link Surface#Surface(android.graphics.SurfaceTexture)} + */ +public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { + MediaPlayer mp; + boolean updateSurface = false; + + public static class AndroidTextureFrame extends TextureFrame { + public AndroidTextureFrame(Texture t, SurfaceTexture stex) { + super(t); + this.stex = stex; + } + + public final SurfaceTexture getSurfaceTexture() { return stex; } + + public String toString() { + return "AndroidTextureFrame[" + texture + ", "+ stex + "]"; + } + protected SurfaceTexture stex; + } + + public AndroidGLMediaPlayerAPI14() { + super(); + this.setTextureTarget(GLES2.GL_TEXTURE_EXTERNAL_OES); + this.setTextureCount(1); + mp = new MediaPlayer(); + } + + @Override + public void setPlaySpeed(float rate) { + // n/a + } + + @Override + public void start() { + mp.start(); + } + + @Override + public void pause() { + mp.pause(); + } + + @Override + public void stop() { + mp.stop(); + } + + @Override + public int seek(int msec) { + mp.seekTo(msec); + return mp.getCurrentPosition(); + } + + @Override + public Texture getNextTextureID() { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getCurrentPosition() { + return mp.getCurrentPosition(); + } + + @Override + public boolean isValid() { + return true; + } + + AndroidTextureFrame androidTextureFrame = null; + + @Override + protected void destroyImpl(GL gl) { + mp.release(); + mp = null; + } + + @Override + protected void setStreamImpl() throws IOException { + try { + final Uri uri = Uri.parse(url.toExternalForm()); + mp.setDataSource(StaticContext.getContext(), uri); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e); + } catch (SecurityException e) { + throw new RuntimeException(e); + } catch (IllegalStateException e) { + throw new RuntimeException(e); + } + mp.prepare(); + + width = mp.getVideoWidth(); + height = mp.getVideoHeight(); + fps = 0; + bps = 0; + totalFrames = mp.getDuration(); + acodec = "unknown"; + vcodec = "unknown"; + } + + @Override + protected void destroyTexImage(GLContext ctx, TextureFrame imgTex) { + final AndroidTextureFrame atf = (AndroidTextureFrame) imgTex; + atf.getSurfaceTexture().release(); + super.destroyTexImage(ctx, imgTex); + } + + @Override + protected AndroidTextureFrame createTexImage(GLContext ctx, int idx, int[] tex) { + final GL gl = ctx.getGL(); + + if( 0 > tex[idx] ) { + throw new RuntimeException("TextureName "+toHexString(tex[idx])+" invalid."); + } + gl.glBindTexture(GLES2.GL_TEXTURE_EXTERNAL_OES, tex[idx]); + { + final int err = gl.glGetError(); + if( GL.GL_NO_ERROR != err ) { + throw new RuntimeException("Couldn't bind textureName "+toHexString(tex[idx])+" to 2D target, err "+toHexString(err)); + } + } + // gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR); + // gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); + gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); + gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + // Clamp to edge is only option. + gl.glTexParameteri(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); + gl.glTexParameteri(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); + + SurfaceTexture stex = new SurfaceTexture(tex[idx]); + stex.setOnFrameAvailableListener(onFrameAvailableListener); + + return new AndroidTextureFrame( com.jogamp.opengl.util.texture.TextureIO.newTexture(tex[idx], + GLES2.GL_TEXTURE_EXTERNAL_OES, + width, height, + width, height, + true), stex); + } + + protected OnFrameAvailableListener onFrameAvailableListener = new OnFrameAvailableListener() { + @Override + public void onFrameAvailable(SurfaceTexture surfaceTexture) { + frameNumber++; + updateSurface = true; + } + }; + + @Override + public float getPlaySpeed() { + // TODO Auto-generated method stub + return 0; + } + + private float[] mSTMatrix = new float[16]; + + @Override + public Texture getLastTextureID() { + if(updateSurface) { + androidTextureFrame.getSurfaceTexture().updateTexImage(); + androidTextureFrame.getSurfaceTexture().getTransformMatrix(mSTMatrix); + TextureCoords tc = androidTextureFrame.getTexture().getImageTexCoords(); + PMVMatrix pmv; + } + return androidTextureFrame.getTexture(); + } + +} diff --git a/src/jogl/classes/jogamp/opengl/av/EGLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/av/EGLMediaPlayerImpl.java new file mode 100644 index 000000000..ef3d5072c --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/av/EGLMediaPlayerImpl.java @@ -0,0 +1,109 @@ +package jogamp.opengl.av; + +import javax.media.opengl.GLContext; + +import com.jogamp.opengl.util.texture.Texture; + +import jogamp.opengl.egl.EGL; +import jogamp.opengl.egl.EGLContext; +import jogamp.opengl.egl.EGLDrawable; +import jogamp.opengl.egl.EGLExt; + +public abstract class EGLMediaPlayerImpl extends GLMediaPlayerImpl { + TextureType texType; + boolean useKHRSync; + + public enum TextureType { + GL(0), KHRImage(1); + + public final int id; + + TextureType(int id){ + this.id = id; + } + } + + public static class EGLTextureFrame extends TextureFrame { + + public EGLTextureFrame(Texture t, long khrImage, long khrSync) { + super(t); + this.image = khrImage; + this.sync = khrSync; + } + + public final long getImage() { return image; } + public final long getSync() { return sync; } + + public String toString() { + return "EGLTextureFrame[" + texture + ", img "+ image + ", sync "+ sync+"]"; + } + protected final long image; + protected final long sync; + } + + + protected EGLMediaPlayerImpl() { + this(TextureType.GL, false); + } + + protected EGLMediaPlayerImpl(TextureType texType, boolean useKHRSync) { + super(); + this.texType = texType; + this.useKHRSync = useKHRSync; + } + + @Override + protected TextureFrame createTexImage(GLContext ctx, int idx, int[] tex) { + final Texture texture = super.createTexImageImpl(ctx, idx, tex, true); + final long image; + final long sync; + + final EGLContext eglCtx = (EGLContext) ctx; + final EGLExt eglExt = eglCtx.getEGLExt(); + final EGLDrawable eglDrawable = (EGLDrawable) eglCtx.getGLDrawable(); + int[] tmp = new int[1]; + + if(TextureType.KHRImage == texType) { + // create EGLImage from texture + tmp[0] = EGL.EGL_NONE; + image = eglExt.eglCreateImageKHR( eglDrawable.getDisplay(), eglCtx.getHandle(), + EGLExt.EGL_GL_TEXTURE_2D_KHR, + tex[idx], tmp, 0); + if (0==image) { + throw new RuntimeException("EGLImage creation failed: "+EGL.eglGetError()+", ctx "+eglCtx+", tex "+tex[idx]+", err "+toHexString(EGL.eglGetError())); + } + } else { + image = 0; + } + + if(useKHRSync) { + // Create sync object so that we can be sure that gl has finished + // rendering the EGLImage texture before we tell OpenMAX to fill + // it with a new frame. + tmp[0] = EGL.EGL_NONE; + sync = eglExt.eglCreateSyncKHR(eglDrawable.getDisplay(), EGLExt.EGL_SYNC_FENCE_KHR, tmp, 0); + if (0==sync) { + throw new RuntimeException("EGLSync creation failed: "+EGL.eglGetError()+", ctx "+eglCtx+", err "+toHexString(EGL.eglGetError())); + } + } else { + sync = 0; + } + return new EGLTextureFrame(texture, image, sync); + } + + @Override + protected void destroyTexImage(GLContext ctx, TextureFrame imgTex) { + final EGLContext eglCtx = (EGLContext) ctx; + final EGLExt eglExt = eglCtx.getEGLExt(); + final EGLDrawable eglDrawable = (EGLDrawable) eglCtx.getGLDrawable(); + final EGLTextureFrame eglTex = (EGLTextureFrame) imgTex; + + if(0!=eglTex.getImage()) { + eglExt.eglDestroyImageKHR(eglDrawable.getDisplay(), eglTex.getImage()); + } + if(0!=eglTex.getSync()) { + eglExt.eglDestroySyncKHR(eglDrawable.getDisplay(), eglTex.getSync()); + } + super.destroyTexImage(ctx, imgTex); + } +} diff --git a/src/jogl/classes/jogamp/opengl/av/GLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/av/GLMediaPlayerImpl.java new file mode 100644 index 000000000..826bb6953 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/av/GLMediaPlayerImpl.java @@ -0,0 +1,307 @@ +package jogamp.opengl.av; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import javax.media.opengl.GL; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLES2; + +import com.jogamp.opengl.av.GLMediaPlayer; +import com.jogamp.opengl.av.GLMediaEventListener; +import com.jogamp.opengl.util.texture.Texture; + +/** + * After object creation an implementation may customize the behavior: + * <ul> + * <li>{@link #setTextureCount(int)}</li> + * <li>{@link #setTextureTarget(int)}</li> + * <li>{@link EGLMediaPlayerImpl#setEGLTexImageAttribs(boolean, boolean)}.</li> + * </ul> + * + * <p> + * See {@link GLMediaPlayer}. + * </p> + */ +public abstract class GLMediaPlayerImpl implements GLMediaPlayer { + + protected int textureCount; + protected int textureTarget; + + private int sWidth = 0; + private int sHeight = 0; + protected URL url = null; + + protected Texture texture = null; + protected float playSpeed = 1.0f; + + /** Shall be set by the {@link #setStreamImpl()} method implementation. */ + protected int width = 0; + /** Shall be set by the {@link #setStreamImpl()} method implementation. */ + protected int height = 0; + /** Shall be set by the {@link #setStreamImpl()} method implementation. */ + protected int fps = 0; + /** Shall be set by the {@link #setStreamImpl()} method implementation. */ + protected long bps = 0; + /** Shall be set by the {@link #setStreamImpl()} method implementation. */ + protected long totalFrames = 0; + /** Shall be set by the {@link #setStreamImpl()} method implementation. */ + protected String acodec = null; + /** Shall be set by the {@link #setStreamImpl()} method implementation. */ + protected String vcodec = null; + + protected long frameNumber = 0; + + private TextureFrame[] texFrames = null; + protected HashMap<Integer, TextureFrame> texFrameMap = new HashMap<Integer, TextureFrame>(); + private ArrayList<GLMediaEventListener> eventListeners = new ArrayList<GLMediaEventListener>(); + + protected GLMediaPlayerImpl() { + this.textureCount=3; + this.textureTarget=GL.GL_TEXTURE_2D; + } + + protected final void setTextureCount(int textureCount) { + this.textureCount=textureCount; + } + protected final void setTextureTarget(int textureTarget) { + this.textureTarget=textureTarget; + } + + @Override + public final void setStream(GL gl, URL url) throws IOException { + this.url = url; + if (this.url == null) { + System.out.println("setURL (null)"); + stop(); + return; + } + setStreamImpl(); + init(gl); + } + + /** + * Implementation shall set the following set of data: + * @see #width + * @see #height + * @see #fps + * @see #bps + * @see #totalFrames + * @see #acodec + * @see #vcodec + */ + protected abstract void setStreamImpl() throws IOException; + + protected final void init(GL gl) { + final GLContext ctx = gl.getContext(); + if(!ctx.isCurrent()) { + throw new RuntimeException("Not current: "+ctx); + } + + final GLDrawable drawable = ctx.getGLDrawable(); + sWidth = drawable.getWidth(); + sHeight = drawable.getHeight(); + System.out.println("surface size: "+sWidth+"x"+sHeight); + System.out.println("Platform Extensions : "+ctx.getPlatformExtensionsString()); + + if(null!=texFrames) { + removeAllImageTextures(ctx); + } else { + texFrames = new TextureFrame[textureCount]; + } + + final int[] tex = new int[textureCount]; + { + gl.glGenTextures(textureCount, tex, 0); + final int err = gl.glGetError(); + if( GL.GL_NO_ERROR != err ) { + throw new RuntimeException("TextureNames creation failed (num: "+textureCount+"): err "+toHexString(err)); + } + } + + for(int i=0; i<textureCount; i++) { + final TextureFrame tf = createTexImage(ctx, i, tex); + texFrames[i] = tf; + texFrameMap.put(tex[i], tf); + } + } + + protected TextureFrame createTexImage(GLContext ctx, int idx, int[] tex) { + return new TextureFrame( createTexImageImpl(ctx, idx, tex, true) ); + } + + protected Texture createTexImageImpl(GLContext ctx, int idx, int[] tex, boolean mustFlipVertically) { + final GL gl = ctx.getGL(); + if( 0 > tex[idx] ) { + throw new RuntimeException("TextureName "+toHexString(tex[idx])+" invalid."); + } + gl.glBindTexture(textureTarget, tex[idx]); + { + final int err = gl.glGetError(); + if( GL.GL_NO_ERROR != err ) { + throw new RuntimeException("Couldn't bind textureName "+toHexString(tex[idx])+" to 2D target, err "+toHexString(err)); + } + } + + // create space for buffer with a texture + gl.glTexImage2D( + textureTarget, // target + 0, // level + GL.GL_RGBA, // internal format + width, // width + height, // height + 0, // border + GL.GL_RGBA, // format + GL.GL_UNSIGNED_BYTE, // type + null); // pixels -- will be provided later + { + final int err = gl.glGetError(); + if( GL.GL_NO_ERROR != err ) { + throw new RuntimeException("Couldn't create TexImage2D RGBA "+width+"x"+height+", err "+toHexString(err)); + } + } + gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST); + gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); + // Clamp to edge is only option. + gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); + gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); + + return com.jogamp.opengl.util.texture.TextureIO.newTexture(tex[idx], + textureTarget, + width, height, + width, height, + mustFlipVertically); + } + + protected void destroyTexImage(GLContext ctx, TextureFrame imgTex) { + imgTex.getTexture().destroy(ctx.getGL()); + } + + protected void removeAllImageTextures(GLContext ctx) { + texture = null; + for(int i=0; i<textureCount; i++) { + final TextureFrame imgTex = texFrames[i]; + destroyTexImage(ctx, imgTex); + texFrames[i] = null; + } + texFrameMap.clear(); + } + + protected void attributesUpdated(int event_mask) { + synchronized(eventListenersLock) { + for(Iterator<GLMediaEventListener> i = eventListeners.iterator(); i.hasNext(); ) { + i.next().attributesChanges(this, event_mask); + } + } + } + protected void newFrameAvailable(TextureFrame frame) { + synchronized(eventListenersLock) { + for(Iterator<GLMediaEventListener> i = eventListeners.iterator(); i.hasNext(); ) { + i.next().newFrameAvailable(this, frame); + } + } + } + + @Override + public synchronized float getPlaySpeed() { + return playSpeed; + } + + @Override + public synchronized Texture getLastTextureID() { + return texture; + } + + @Override + public synchronized void destroy(GL gl) { + destroyImpl(gl); + removeAllImageTextures(gl.getContext()); + } + protected abstract void destroyImpl(GL gl); + + @Override + public synchronized URL getURL() { + return url; + } + + @Override + public synchronized String getVideoCodec() { + return vcodec; + } + + @Override + public synchronized String getAudioCodec() { + return acodec; + } + + @Override + public synchronized long getTotalFrames() { + return totalFrames; + } + + @Override + public synchronized long getBitrate() { + return bps; + } + + @Override + public synchronized int getFramerate() { + return fps; + } + + @Override + public synchronized int getWidth() { + return width; + } + + @Override + public synchronized int getHeight() { + return height; + } + + @Override + public synchronized String toString() { + return "GLMediaPlayer [ stream [ video [ "+vcodec+", "+width+"x"+height+", "+fps+"fps, "+bps+"bsp, "+totalFrames+"f ] ] ]"; + } + + @Override + public void addEventListener(GLMediaEventListener l) { + if(l == null) { + return; + } + synchronized(eventListenersLock) { + eventListeners.add(l); + } + } + + @Override + public void removeEventListener(GLMediaEventListener l) { + if (l == null) { + return; + } + synchronized(eventListenersLock) { + eventListeners.remove(l); + } + } + + @Override + public synchronized GLMediaEventListener[] getEventListeners() { + synchronized(eventListenersLock) { + return eventListeners.toArray(new GLMediaEventListener[eventListeners.size()]); + } + } + + private Object eventListenersLock = new Object(); + + protected static final String toHexString(long v) { + return "0x"+Long.toHexString(v); + } + protected static final String toHexString(int v) { + return "0x"+Integer.toHexString(v); + } + +}
\ No newline at end of file diff --git a/src/jogl/classes/jogamp/opengl/omx/OMXGLMediaPlayer.java b/src/jogl/classes/jogamp/opengl/omx/OMXGLMediaPlayer.java new file mode 100644 index 000000000..8f5f9c3ab --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/omx/OMXGLMediaPlayer.java @@ -0,0 +1,238 @@ + +package jogamp.opengl.omx; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import javax.media.opengl.GL; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLException; + +import com.jogamp.opengl.av.GLMediaEventListener; +import com.jogamp.opengl.util.texture.Texture; + +import jogamp.opengl.av.EGLMediaPlayerImpl; +import jogamp.opengl.egl.EGL; + +public class OMXGLMediaPlayer extends EGLMediaPlayerImpl { + protected long moviePtr = 0; + + /** + * Old stream values, before the last attributesUpdated) + */ + protected int o_width = 0; + protected int o_height = 0; + protected int o_fps = 0; + protected long o_bps = 0; + protected long o_totalFrames = 0; + + public OMXGLMediaPlayer() { + super(TextureType.KHRImage, true); + initOMX(); + } + + protected void initOMX() { + moviePtr = _createInstance(); + if(0==moviePtr) { + throw new GLException("Couldn't create OMXInstance"); + } + } + + @Override + protected TextureFrame createTexImage(GLContext ctx, int idx, int[] tex) { + final EGLTextureFrame eglTex = (EGLTextureFrame) super.createTexImage(ctx, idx, tex); + _setStreamEGLImageTexture2D(moviePtr, idx, tex[idx], eglTex.getImage(), eglTex.getSync()); + return eglTex; + } + + @Override + protected void destroyTexImage(GLContext ctx, TextureFrame imgTex) { + super.destroyTexImage(ctx, imgTex); + } + + @Override + protected void destroyImpl(GL gl) { + _detachVideoRenderer(moviePtr); + if (moviePtr != 0) { + _destroyInstance(moviePtr); + moviePtr = 0; + } + } + + @Override + protected void setStreamImpl() throws IOException { + if(0==moviePtr) { + throw new GLException("OMX native instance null"); + } + String path=null; + if (url.getProtocol() == null || "file".equals(url.getProtocol())) { + // CV only accepts absolute paths + try { + File file = new File(url.getPath()); + if (!file.exists()) { + throw new FileNotFoundException(file.toString()); + } + path = file.getCanonicalPath(); + System.out.println("setURL: path "+path); + } catch (Exception e) { + e.printStackTrace(); + throw new IOException(e); + } + } + path = replaceAll(path, "\\", "/").trim(); + if(null==path) { + throw new IOException("Couldn't parse stream URL: "+url); + } + System.out.println("setURL: clean path "+path); + + System.out.println("setURL: p1 "+this); + _setStream(moviePtr, textureCount, path); + System.out.println("setURL: p2 "+this); + } + + + @Override + public synchronized int getCurrentPosition() { + if(0==moviePtr) { + throw new GLException("OMX native instance null"); + } + return _getCurrentPosition(moviePtr); + } + + @Override + public synchronized boolean isValid() { + return (moviePtr != 0); + } + + @Override + public synchronized void setPlaySpeed(float rate) { + if(0==moviePtr) { + throw new GLException("OMX native instance null"); + } + _setPlaySpeed(moviePtr, rate); + playSpeed = rate; + } + + /** @return time position after issuing the command */ + @Override + public synchronized void start() { + if(0==moviePtr) { + throw new GLException("OMX native instance null"); + } + _play(moviePtr); + } + + /** @return time position after issuing the command */ + @Override + public synchronized void pause() { + if(0==moviePtr) { + throw new GLException("OMX native instance null"); + } + _pause(moviePtr); + } + + /** @return time position after issuing the command */ + @Override + public synchronized void stop() { + if(0==moviePtr) { + throw new GLException("OMX native instance null"); + } + _stop(moviePtr); + } + + /** @return time position after issuing the command */ + @Override + public synchronized int seek(int msec) { + if(0==moviePtr) { + throw new GLException("OMX native instance null"); + } + return _seek(moviePtr, msec); + } + + @Override + public synchronized Texture getNextTextureID() { + if(0==moviePtr) { + throw new GLException("OMX native instance null"); + } + texture=null; + TextureFrame eglImgTex = texFrameMap.get(new Integer(_getNextTextureID(moviePtr))); + if(null!=eglImgTex) { + texture = eglImgTex.getTexture(); + } + return texture; + } + + protected void attributesUpdated() { + int event_mask = 0; + if( o_width != width || o_height != height ) { + event_mask |= GLMediaEventListener.EVENT_CHANGE_SIZE; + } + if( o_fps != fps ) { + event_mask |= GLMediaEventListener.EVENT_CHANGE_FPS; + } + if( o_bps != bps ) { + event_mask |= GLMediaEventListener.EVENT_CHANGE_BPS; + } + if( o_totalFrames != totalFrames ) { + event_mask |= GLMediaEventListener.EVENT_CHANGE_LENGTH; + } + if(0==event_mask) { + return; + } + super.attributesUpdated(event_mask); + } + + /** + * Java callback method issued by the native OMX backend + */ + private void saveAttributes() { + o_width = width; + o_height = height; + o_fps = fps; + o_bps = bps; + o_totalFrames = totalFrames; + } + + private String replaceAll(String orig, String search, String repl) { + String dest=null; + // In case replaceAll / java.util.regex.* is not supported (-> CVM) + int i=0,j; + dest = new String(); + while((j=orig.indexOf(search, i))>=0) { + dest=dest.concat(orig.substring(i, j)); + dest=dest.concat(repl); + i=j+1; + } + return dest.concat(orig.substring(i, orig.length())); + } + + private void errorCheckEGL(String s) { + int e; + if( (e=EGL.eglGetError()) != EGL.EGL_SUCCESS ) { + System.out.println("EGL Error: ("+s+"): 0x"+Integer.toHexString(e)); + } + } + + // + // OMXEventListener Support + // + + native long _createInstance(); + native void _destroyInstance(long moviePtr); + + native void _detachVideoRenderer(long moviePtr); // stop before + native void _attachVideoRenderer(long moviePtr); // detach before + native void _setStream(long moviePtr, int textureNum, String path); + native void _activateStream(long moviePtr); + + native void _setStreamEGLImageTexture2D(long moviePtr, int i, int tex, long image, long sync); + native int _seek(long moviePtr, int position); + native void _setPlaySpeed(long moviePtr, float rate); + native void _play(long moviePtr); + native void _pause(long moviePtr); + native void _stop(long moviePtr); + native int _getNextTextureID(long moviePtr); + native int _getCurrentPosition(long moviePtr); +} + diff --git a/src/jogl/native/openmax/com_sun_openmax_OMXInstance.c b/src/jogl/native/openmax/jogamp.opengl.omx.OMXGLMediaPlayer.c index 5317c2abc..00c0ca562 100644 --- a/src/jogl/native/openmax/com_sun_openmax_OMXInstance.c +++ b/src/jogl/native/openmax/jogamp.opengl.omx.OMXGLMediaPlayer.c @@ -13,7 +13,7 @@ // http://developer.apple.com/qa/qa2001/qa1149.html // http://developer.apple.com/qa/qa2001/qa1262.html -#include "com_jogamp_openmax_OMXInstance.h" +#include "jogamp_opengl_omx_OMXGLMediaPlayer.h" #include "omx_tool.h" #include <stdarg.h> @@ -105,7 +105,7 @@ void OMXInstance_UpdateJavaAttributes(OMXToolBasicAV_t *pOMXAV, KDboolean issueJ } } -JNIEXPORT jlong JNICALL Java_com_jogamp_openmax_OMXInstance__1createInstance +JNIEXPORT jlong JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1createInstance (JNIEnv *env, jobject instance) { OMXToolBasicAV_t * pOMXAV; @@ -132,7 +132,7 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_openmax_OMXInstance__1createInstance return (jlong) (intptr_t) (void *)pOMXAV; } -JNIEXPORT void JNICALL Java_com_jogamp_openmax_OMXInstance__1setStream +JNIEXPORT void JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1setStream (JNIEnv *env, jobject instance, jlong ptr, jint vBufferNum, jstring jpath) { jboolean iscopy; @@ -150,7 +150,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_openmax_OMXInstance__1setStream fprintf(stdout, "setStream 3 ..\n"); fflush(stdout); // JAU } -JNIEXPORT void JNICALL Java_com_jogamp_openmax_OMXInstance__1setStreamEGLImageTexture2D +JNIEXPORT void JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1setStreamEGLImageTexture2D (JNIEnv *env, jobject instance, jlong ptr, jint i, jint tex, jlong image, jlong sync) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); @@ -161,7 +161,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_openmax_OMXInstance__1setStreamEGLImageTe } } -JNIEXPORT void JNICALL Java_com_jogamp_openmax_OMXInstance__1activateStream +JNIEXPORT void JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1activateStream (JNIEnv *env, jobject instance, jlong ptr) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); @@ -171,52 +171,49 @@ JNIEXPORT void JNICALL Java_com_jogamp_openmax_OMXInstance__1activateStream } } -JNIEXPORT void JNICALL Java_com_jogamp_openmax_OMXInstance__1attachVideoRenderer +JNIEXPORT void JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1attachVideoRenderer (JNIEnv *env, jobject instance, jlong ptr) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); OMXToolBasicAV_AttachVideoRenderer(pOMXAV); } -JNIEXPORT void JNICALL Java_com_jogamp_openmax_OMXInstance__1detachVideoRenderer +JNIEXPORT void JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1detachVideoRenderer (JNIEnv *env, jobject instance, jlong ptr) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); OMXToolBasicAV_DetachVideoRenderer(pOMXAV); } -JNIEXPORT void JNICALL Java_com_jogamp_openmax_OMXInstance__1setPlaySpeed +JNIEXPORT void JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1setPlaySpeed (JNIEnv *env, jobject instance, jlong ptr, jfloat scale) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); OMXToolBasicAV_SetPlaySpeed(pOMXAV, scale); } -JNIEXPORT jfloat JNICALL Java_com_jogamp_openmax_OMXInstance__1play +JNIEXPORT void JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1play (JNIEnv *env, jobject instance, jlong ptr) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); OMXToolBasicAV_PlayStart(pOMXAV); - return OMXToolBasicAV_GetCurrentPosition(pOMXAV); } -JNIEXPORT jfloat JNICALL Java_com_jogamp_openmax_OMXInstance__1pause +JNIEXPORT void JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1pause (JNIEnv *env, jobject instance, jlong ptr) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); OMXToolBasicAV_PlayPause(pOMXAV); - return OMXToolBasicAV_GetCurrentPosition(pOMXAV); } -JNIEXPORT jfloat JNICALL Java_com_jogamp_openmax_OMXInstance__1stop +JNIEXPORT void JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1stop (JNIEnv *env, jobject instance, jlong ptr) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); OMXToolBasicAV_PlayStop(pOMXAV); - return OMXToolBasicAV_GetCurrentPosition(pOMXAV); } -JNIEXPORT jfloat JNICALL Java_com_jogamp_openmax_OMXInstance__1seek +JNIEXPORT jint JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1seek (JNIEnv *env, jobject instance, jlong ptr, jfloat pos) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); @@ -224,7 +221,7 @@ JNIEXPORT jfloat JNICALL Java_com_jogamp_openmax_OMXInstance__1seek return OMXToolBasicAV_GetCurrentPosition(pOMXAV); } -JNIEXPORT jint JNICALL Java_com_jogamp_openmax_OMXInstance__1getNextTextureID +JNIEXPORT jint JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1getNextTextureID (JNIEnv *env, jobject instance, jlong ptr) { jint textureID = 0xffffffff; @@ -235,7 +232,7 @@ JNIEXPORT jint JNICALL Java_com_jogamp_openmax_OMXInstance__1getNextTextureID return textureID; } -JNIEXPORT jfloat JNICALL Java_com_jogamp_openmax_OMXInstance__1getCurrentPosition +JNIEXPORT jint JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1getCurrentPosition (JNIEnv *env, jobject instance, jlong ptr) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); @@ -243,7 +240,7 @@ JNIEXPORT jfloat JNICALL Java_com_jogamp_openmax_OMXInstance__1getCurrentPositio } -JNIEXPORT void JNICALL Java_com_jogamp_openmax_OMXInstance__1destroyInstance +JNIEXPORT void JNICALL Java_jogamp_opengl_omx_OMXGLMediaPlayer__1destroyInstance (JNIEnv *env, jobject instance, jlong ptr) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); diff --git a/src/jogl/native/openmax/omx_tool.c b/src/jogl/native/openmax/omx_tool.c index 57fa8ad21..1f2ce7da7 100644 --- a/src/jogl/native/openmax/omx_tool.c +++ b/src/jogl/native/openmax/omx_tool.c @@ -627,14 +627,14 @@ static int StartClock(OMXToolBasicAV_t * pOMXAV, KDboolean start, KDfloat32 time return (OMX_ErrorNotReady == eError)?-1:0; } -static KDfloat32 GetClockPosition(OMXToolBasicAV_t * pOMXAV) +static KDint GetClockPosition(OMXToolBasicAV_t * pOMXAV) { OMX_TIME_CONFIG_TIMESTAMPTYPE stamp; INIT_PARAM(stamp); stamp.nPortIndex = 0; OMX_GetConfig(pOMXAV->comp[OMXAV_H_CLOCK], OMX_IndexConfigTimeCurrentMediaTime, &stamp); - return (KDfloat32) (stamp.nTimestamp * (1.0f/(1000.0f*1000.0f))); + return (int) ( stamp.nTimestamp / 1000 ); } static KDfloat32 GetClockScale(OMXToolBasicAV_t * pOMXAV) @@ -1474,7 +1474,7 @@ GLuint OMXToolBasicAV_GetNextTextureID(OMXToolBasicAV_t * pOMXAV) { return texID; } -KDfloat32 OMXToolBasicAV_GetCurrentPosition(OMXToolBasicAV_t * pOMXAV) { +KDint OMXToolBasicAV_GetCurrentPosition(OMXToolBasicAV_t * pOMXAV) { KDfloat32 res = -1.0f; if(NULL==pOMXAV) { java_throwNewRuntimeException(0, "OMX instance null\n"); diff --git a/src/jogl/native/openmax/omx_tool.h b/src/jogl/native/openmax/omx_tool.h index d566507c1..cb0f125ec 100644 --- a/src/jogl/native/openmax/omx_tool.h +++ b/src/jogl/native/openmax/omx_tool.h @@ -141,7 +141,7 @@ void OMXToolBasicAV_PlayStop(OMXToolBasicAV_t * pOMXAV); void OMXToolBasicAV_PlaySeek(OMXToolBasicAV_t * pOMXAV, KDfloat32 time); GLuint OMXToolBasicAV_GetNextTextureID(OMXToolBasicAV_t * pOMXAV); -KDfloat32 OMXToolBasicAV_GetCurrentPosition(OMXToolBasicAV_t * pOMXAV); +KDint OMXToolBasicAV_GetCurrentPosition(OMXToolBasicAV_t * pOMXAV); void OMXToolBasicAV_DestroyInstance(OMXToolBasicAV_t * pOMXAV); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSimple.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSimple.java new file mode 100755 index 000000000..f58938399 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieSimple.java @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ + + +package com.jogamp.opengl.test.junit.jogl.demos.es2.av; + +import java.io.IOException; +import java.net.URL; +import java.nio.FloatBuffer; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; +import javax.media.opengl.GLUniformData; +import javax.media.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.av.GLMediaPlayer; +import com.jogamp.opengl.av.GLMediaEventListener; +import com.jogamp.opengl.av.GLMediaPlayer.TextureFrame; +import com.jogamp.opengl.av.GLMediaPlayerFactory; +import com.jogamp.opengl.util.GLArrayDataServer; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderCode; +import com.jogamp.opengl.util.glsl.ShaderProgram; +import com.jogamp.opengl.util.glsl.ShaderState; + +public class MovieSimple implements MouseListener, GLEventListener, GLMediaEventListener { + private GLWindow window; + private boolean quit = false; + private boolean rotate = false; + private float zoom = -2.5f; + private float ang = 0f; + private long startTime; + private long curTime; + private String stream; + + public void changedAttributes(GLMediaPlayer omx, int event_mask) { + System.out.println("changed stream attr ("+event_mask+"): "+omx); + } + + public void mouseClicked(MouseEvent e) { + switch(e.getClickCount()) { + case 2: + quit=true; + break; + } + } + public void mouseEntered(MouseEvent e) { + } + public void mouseExited(MouseEvent e) { + } + public void mousePressed(MouseEvent e) { + } + public void mouseReleased(MouseEvent e) { + rotate = false; + zoom = -2.5f; + } + public void mouseMoved(MouseEvent e) { + } + public void mouseDragged(MouseEvent e) { + rotate = true; + zoom = -5; + } + public void mouseWheelMoved(MouseEvent e) { + } + + public MovieSimple(String stream) { + this.stream = stream ; + } + + private void run() { + System.err.println("MovieSimple.run()"); + try { + GLCapabilities caps = new GLCapabilities(GLProfile.getGL2ES2()); + // For emulation library, use 16 bpp + caps.setRedBits(5); + caps.setGreenBits(6); + caps.setBlueBits(5); + caps.setDepthBits(16); + + window = GLWindow.create(caps); + + window.addMouseListener(this); + window.addGLEventListener(this); + // window.setEventHandlerMode(GLWindow.EVENT_HANDLER_GL_CURRENT); // default + // window.setEventHandlerMode(GLWindow.EVENT_HANDLER_GL_NONE); // no current .. + + // Size OpenGL to Video Surface + window.setFullscreen(true); + window.setVisible(true); + + startTime = System.currentTimeMillis(); + while (!quit) { + window.display(); + } + + // Shut things down cooperatively + if(null!=movie) { + movie.destroy(window.getGL()); + movie=null; + } + window.destroy(); + System.out.println("MovieSimple shut down cleanly."); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + ShaderState st; + PMVMatrix pmvMatrix; + + private void initShader(GL2ES2 gl) { +// Create & Compile the shader objects + ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, MovieSimple.class, + "shader", "shader/bin", "moviesimple"); + ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, MovieSimple.class, + "shader", "shader/bin", "moviesimple"); + + // Create & Link the shader program + ShaderProgram sp = new ShaderProgram(); + sp.add(rsVp); + sp.add(rsFp); + if(!sp.link(gl, System.err)) { + throw new GLException("Couldn't link program: "+sp); + } + + // Let's manage all our states using ShaderState. + st = new ShaderState(); + st.attachShaderProgram(gl, sp, false); + } + + GLMediaPlayer movie=null; + + public void init(GLAutoDrawable drawable) { + GL2ES2 gl = drawable.getGL().getGL2ES2(); + System.err.println("Entering initialization"); + System.err.println("GL_VERSION=" + gl.glGetString(GL.GL_VERSION)); + System.err.println("GL_EXTENSIONS:"); + System.err.println(" " + gl.glGetString(GL.GL_EXTENSIONS)); + + pmvMatrix = new PMVMatrix(); + + initShader(gl); + + // Push the 1st uniform down the path + st.useProgram(gl, true); + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + + if(!st.uniform(gl, new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()))) { + throw new GLException("Error setting PMVMatrix in shader: "+st); + } + if(!st.uniform(gl, new GLUniformData("mgl_ActiveTexture", 0))) { + throw new GLException("Error setting mgl_ActiveTexture in shader: "+st); + } + gl.glActiveTexture(GL.GL_TEXTURE0); + + float aspect = 16.0f/9.0f; + float xs=1f, ys=1f; // scale object + float ss=1f, ts=1f; // scale tex-coord + + xs = aspect; // b > h + ys = 1f; // b > h + // ss = 1f/aspect; // b > h, crop width + // ts = 1f; // b > h + + // Allocate vertex array + GLArrayDataServer vertices = GLArrayDataServer.createGLSL("mgl_Vertex", 3, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); + { + // Fill them up + FloatBuffer verticeb = (FloatBuffer)vertices.getBuffer(); + verticeb.put(-1f*xs); verticeb.put( -1f*ys); verticeb.put( 0); + verticeb.put(-1f*xs); verticeb.put( 1f*ys); verticeb.put( 0); + verticeb.put( 1f*xs); verticeb.put( -1f*ys); verticeb.put( 0); + verticeb.put( 1f*xs); verticeb.put( 1f*ys); verticeb.put( 0); + } + vertices.seal(gl, true); + + // Allocate texcoord array + GLArrayDataServer texcoord = GLArrayDataServer.createGLSL("mgl_MultiTexCoord", 2, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); + { + // Fill them up + FloatBuffer texcoordb = (FloatBuffer)texcoord.getBuffer(); + texcoordb.put( 0f*ss); texcoordb.put( 0f*ts); + texcoordb.put( 0f*ss); texcoordb.put( 1f*ts); + texcoordb.put( 1f*ss); texcoordb.put( 0f*ts); + texcoordb.put( 1f*ss); texcoordb.put( 1f*ts); + } + texcoord.seal(gl, true); + + GLArrayDataServer colors = GLArrayDataServer.createGLSL("mgl_Color", 4, GL.GL_FLOAT, false, 4, GL.GL_STATIC_DRAW); + { + // Fill them up + FloatBuffer colorb = (FloatBuffer)colors.getBuffer(); + colorb.put( 0); colorb.put( 0); colorb.put( 0); colorb.put( 1); + colorb.put( 1); colorb.put( 1); colorb.put( 1); colorb.put( 1); + colorb.put( 0); colorb.put( 0); colorb.put( 0); colorb.put( 1); + colorb.put( 1); colorb.put( 1); colorb.put( 1); colorb.put( 1); + } + colors.seal(gl, true); + + // OpenGL Render Settings + gl.glClearColor(0.2f, 0.2f, 0.2f, 1); + gl.glEnable(GL2ES2.GL_DEPTH_TEST); + + st.useProgram(gl, false); + + // Let's show the completed shader state .. + System.out.println(st); + + try { + movie = GLMediaPlayerFactory.create(); + movie.addEventListener(this); + // movie.setStream(4, new URL(stream)); + movie.setStream(gl, new URL(stream)); + System.out.println("p0 "+movie); + } catch (IOException ioe) { ioe.printStackTrace(); } + if(null!=movie) { + //movie.setStreamAllEGLImageTexture2D(gl); + //movie.activateStream(); + //System.out.println("p1 "+movie); + movie.start(); + } + } + + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + GL2ES2 gl = drawable.getGL().getGL2ES2(); + + st.useProgram(gl, true); + + // Set location in front of camera + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + pmvMatrix.gluPerspective(45.0f, (float)width / (float)height, 1.0f, 100.0f); + //pmvMatrix.glOrthof(-4.0f, 4.0f, -4.0f, 4.0f, 1.0f, 100.0f); + + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glTranslatef(0, 0, zoom); + + GLUniformData ud = st.getUniform("mgl_PMVMatrix"); + if(null!=ud) { + // same data object + st.uniform(gl, ud); + } + + st.useProgram(gl, false); + } + + public void dispose(GLAutoDrawable drawable) { + GL2ES2 gl = drawable.getGL().getGL2ES2(); + + movie.destroy(gl); + movie=null; + pmvMatrix.destroy(); + pmvMatrix=null; + st.destroy(gl); + st=null; + quit=true; + } + + public void display(GLAutoDrawable drawable) { + GL2ES2 gl = drawable.getGL().getGL2ES2(); + + st.useProgram(gl, true); + + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + + if(rotate) { + curTime = System.currentTimeMillis(); + ang = ((float) (curTime - startTime) * 360.0f) / 8000.0f; + } + + if(rotate || zoom!=0f) { + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glTranslatef(0, 0, zoom); + pmvMatrix.glRotatef(ang, 0, 0, 1); + // pmvMatrix.glRotatef(ang, 0, 1, 0); + + GLUniformData ud = st.getUniform("mgl_PMVMatrix"); + if(null!=ud) { + // same data object + st.uniform(gl, ud); + } + + if(!rotate) { + zoom=0f; + } + } + + + com.jogamp.opengl.util.texture.Texture tex = null; + if(null!=movie) { + tex=movie.getNextTextureID(); + if(null!=tex) { + tex.enable(gl); + tex.bind(gl); + } + } + + // Draw a square + gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4); + + if(null!=tex) { + tex.disable(gl); + } + + st.useProgram(gl, false); + } + + public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { + } + + public static void main(String[] args) { + String fname="file:///Storage Card/resources/a.mp4"; + if(args.length>0) fname=args[0]; + new MovieSimple(fname).run(); + System.exit(0); + } + + @Override + public void attributesChanges(GLMediaPlayer mp, int event_mask) { + // TODO Auto-generated method stub + + } + + @Override + public void newFrameAvailable(GLMediaPlayer mp, TextureFrame frame) { + // TODO Auto-generated method stub + + } +} diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/moviesimple.fp b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/moviesimple.fp new file mode 100644 index 000000000..c71164105 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/moviesimple.fp @@ -0,0 +1,21 @@ + +#ifdef GL_ES + #define MEDIUMP mediump + #define HIGHP highp +#else + #define MEDIUMP + #define HIGHP +#endif + +uniform sampler2D mgl_ActiveTexture; +varying HIGHP vec4 mgl_texCoord; +varying HIGHP vec4 frontColor; + +void main (void) +{ + vec4 texColor = texture2D(mgl_ActiveTexture, mgl_texCoord.st); + + // mix frontColor with texture .. + gl_FragColor = vec4(frontColor.rgb*texColor.rgb, frontColor.a); +} + diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/moviesimple.vp b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/moviesimple.vp new file mode 100644 index 000000000..0b78eb913 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/shader/moviesimple.vp @@ -0,0 +1,22 @@ + +#ifdef GL_ES + #define MEDIUMP mediump + #define HIGHP highp +#else + #define MEDIUMP + #define HIGHP +#endif + +uniform MEDIUMP mat4 mgl_PMVMatrix[2]; +attribute HIGHP vec4 mgl_Vertex; +attribute HIGHP vec4 mgl_Color; +attribute HIGHP vec4 mgl_MultiTexCoord; +varying HIGHP vec4 frontColor; +varying HIGHP vec4 mgl_texCoord; + +void main(void) +{ + frontColor=mgl_Color; + mgl_texCoord = mgl_MultiTexCoord; + gl_Position = mgl_PMVMatrix[0] * mgl_PMVMatrix[1] * mgl_Vertex; +} |