diff options
author | Sven Gothel <[email protected]> | 2012-04-16 21:18:03 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2012-04-16 21:18:03 +0200 |
commit | 35beeabffed61e1597aaffc0c5926ab5ef86d32e (patch) | |
tree | 6a7e91c07e7d61613b03f35a17486faf01b211fc | |
parent | 2f0583aad39f93a934629c21beac66a758373249 (diff) |
TextureSequence Shader Support; GLMediaPlayer uses 'int' where possible; General enhancments.
For details about TextureSequence/GLMediaPlayer shader collaboration w/ your own shader source,
see TextureSequence and TexCubeES2 / MovieSimple demo.
TextureSequence allows implementations to provide their own texture lookup function
which may provide color space conversion (YUV) .. or other runtime hw-accel features.
Have a look at the next commit, which provides an Libav/FFMpeg implementation w/ YUV/RGB shader conversion.
MovieCube adds keyboard control (Android: firm touch on display to launch keyboard, don't break it though :)
28 files changed, 951 insertions, 455 deletions
diff --git a/make/scripts/tests-x32.bat b/make/scripts/tests-x32.bat index 6afbfde28..c29dcef39 100755 --- a/make/scripts/tests-x32.bat +++ b/make/scripts/tests-x32.bat @@ -14,7 +14,7 @@ REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.acore.TestGLPro REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNewtAWTWrapper %* REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.newt.TestGearsNEWT -time 30000 REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es1.newt.TestGearsES1NEWT %* -scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT %* +REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT %* REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT %* REM scripts\java-win32.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT -vsync -time 4000 -x 10 -y 10 -width 100 -height 100 -screen 0 REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestRedSquareES2NEWT %* @@ -50,6 +50,10 @@ REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.newt.TestScreenMode0 REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.newt.TestScreenMode02NEWT REM scripts\java-win32.bat com.jogamp.opengl.test.junit.newt.ManualScreenMode03NEWT +REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieSimple %* +scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieCube %* +REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.TexCubeES2 %* + REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.newt.TestDisplayLifecycle01NEWT REM scripts\java-win32-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT REM scripts\java-win32.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting02NEWT %* diff --git a/make/scripts/tests-x64.bat b/make/scripts/tests-x64.bat index 7d6903d96..f0144f1b8 100755 --- a/make/scripts/tests-x64.bat +++ b/make/scripts/tests-x64.bat @@ -24,7 +24,7 @@ REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.T REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsGLJPanelAWT -time 5000 REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.awt.TestAWT03GLCanvasRecreate01 REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.newt.TestSwingAWTRobotUsageBeforeJOGLInitBug411 -scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.glsl.TestTransformFeedbackVaryingsBug407NEWT +REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.glsl.TestTransformFeedbackVaryingsBug407NEWT REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.glsl.TestGLSLSimple01NEWT -time 2000 REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestParenting01AWT @@ -51,6 +51,10 @@ REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestScreenMode0 REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestScreenMode02NEWT REM scripts\java-win64.bat com.jogamp.opengl.test.junit.newt.ManualScreenMode03NEWT +REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieSimple %* +scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieCube %* +REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.jogl.demos.es2.TexCubeES2 %* + REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.TestDisplayLifecycle01NEWT REM scripts\java-win64-dbg.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting01NEWT REM scripts\java-win64.bat com.jogamp.opengl.test.junit.newt.parenting.TestParenting02NEWT %* diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index c2081691c..ff789e68a 100755 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -62,7 +62,7 @@ function jrun() { #D_ARGS="-Djogl.debug.GLDebugMessageHandler -Djogl.debug.TraceGL -Djogl.debug.DebugGL -Djogl.debug.GLSLCode -Djogl.debug.GLSLState" #D_ARGS="-Djogl.debug.GLDebugMessageHandler -Djogl.debug.DebugGL -Djogl.debug.TraceGL" #D_ARGS="-Djogl.debug.TraceGL -Djogl.debug.DebugGL -Djogl.debug.GLSLCode" - #D_ARGS="-Djogamp.debug.IOUtil -Djogl.debug.GLSLCode" + D_ARGS="-Djogamp.debug.IOUtil -Djogl.debug.GLSLCode -Djogl.debug.GLMediaPlayer" #D_ARGS="-Djogl.debug.GLArrayData" #D_ARGS="-Djogl.debug.EGL -Dnativewindow.debug.GraphicsConfiguration -Djogl.debug.GLDrawable" #D_ARGS="-Dnewt.test.Screen.disableScreenMode -Dnewt.debug.Screen" diff --git a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java index d86c8bfd0..8430d6137 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java @@ -47,6 +47,15 @@ import com.jogamp.opengl.util.texture.TextureSequence; * <tr><td>{@link #pause()}</td> <td>Playing</td> <td>Paused</td></tr> * <tr><td>{@link #destroy(GL)}</td> <td>ANY</td> <td>Uninitialized</td></tr> * </table> + * <p> + * Variable type, value range and dimension has been chosen to suit embedded CPUs + * and characteristics of audio and video streaming. + * Milliseconds of type integer with a maximum value of {@link Integer#MAX_VALUE} + * will allow tracking time up 2,147,483.647 seconds or + * 24 days 20 hours 31 minutes and 23 seconds. + * Milliseconds granularity is also more than enough to deal with A-V synchronization, + * where the threshold usually lies within 100ms. + * </p> */ public interface GLMediaPlayer extends TextureSequence { public static final boolean DEBUG = Debug.debug("GLMediaPlayer"); @@ -57,6 +66,7 @@ public interface GLMediaPlayer extends TextureSequence { static final int EVENT_CHANGE_FPS = 1<<1; static final int EVENT_CHANGE_BPS = 1<<2; static final int EVENT_CHANGE_LENGTH = 1<<3; + static final int EVENT_CHANGE_CODEC = 1<<3; /** * @param mp the event source @@ -136,7 +146,7 @@ public interface GLMediaPlayer extends TextureSequence { /** * @return time current position in milliseconds **/ - public long getCurrentPosition(); + public int getCurrentPosition(); /** * Allowed in state Stopped, Playing and Paused, otherwise ignored. @@ -144,20 +154,26 @@ public interface GLMediaPlayer extends TextureSequence { * @param msec absolute desired time position in milliseconds * @return time current position in milliseconds, after seeking to the desired position **/ - public long seek(long msec); + public int seek(int msec); /** * {@inheritDoc} */ - public TextureSequence.TextureFrame getLastTexture(); + @Override + public TextureSequence.TextureFrame getLastTexture() throws IllegalStateException; /** * {@inheritDoc} * + * <p> + * In case the current state is not {@link State#Playing}, {@link #getLastTexture()} is returned. + * </p> + * * @see #addEventListener(GLMediaEventListener) * @see GLMediaEventListener#newFrameAvailable(GLMediaPlayer, long) */ - public TextureSequence.TextureFrame getNextTexture(GL gl, boolean blocking); + @Override + public TextureSequence.TextureFrame getNextTexture(GL gl, boolean blocking) throws IllegalStateException; public URLConnection getURLConnection(); @@ -182,19 +198,31 @@ public interface GLMediaPlayer extends TextureSequence { /** * @return total duration of stream in msec. */ - public long getDuration(); + public int getDuration(); /** * <i>Warning:</i> Optional information, may not be supported by implementation. * @return the overall bitrate of the stream. */ - public long getBitrate(); + public long getStreamBitrate(); /** * <i>Warning:</i> Optional information, may not be supported by implementation. + * @return video bitrate + */ + public int getVideoBitrate(); + + /** + * <i>Warning:</i> Optional information, may not be supported by implementation. + * @return the audio bitrate + */ + public int getAudioBitrate(); + + /** + * <i>Warning:</i> Optional information, may not be supported by implementation. * @return the framerate of the video */ - public int getFramerate(); + public float getFramerate(); public int getWidth(); @@ -207,5 +235,5 @@ public interface GLMediaPlayer extends TextureSequence { public void removeEventListener(GLMediaEventListener l); public GLMediaEventListener[] getEventListeners(); - + } diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureSequence.java b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureSequence.java index e6d21c613..5ee2104a3 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureSequence.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureSequence.java @@ -29,23 +29,98 @@ package com.jogamp.opengl.util.texture; import javax.media.opengl.GL; +/** + * Protocol for texture sequences, like animations, movies, etc. + * <p> + * Ensure to respect the texture coordinates provided by + * {@link TextureFrame}.{@link TextureFrame#getTexture() getTexture()}.{@link Texture#getImageTexCoords() getImageTexCoords()}. + * </p> + * The user's shader shall be fitted for this implementation. + * Assuming we use a base shader code w/o headers using </code>ShaderCode</code>. + * (Code copied from unit test / demo <code>TexCubeES2</code>) + * <pre> + * + static final String[] es2_prelude = { "#version 100\n", "precision mediump float;\n" }; + static final String gl2_prelude = "#version 110\n"; + static final String shaderBasename = "texsequence_xxx"; // the base shader code w/o headers + static final String myTextureLookupName = "myTexture2D"; // the desired texture lookup function + + private void initShader(GL2ES2 gl, TextureSequence texSeq) { + // Create & Compile the shader objects + ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, TexCubeES2.class, + "shader", "shader/bin", shaderBasename, true); + ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, TexCubeES2.class, + "shader", "shader/bin", shaderBasename, true); + + // Prelude shader code w/ GLSL profile specifics [ 1. pre-proc, 2. other ] + int rsFpPos; + if(gl.isGLES2()) { + // insert ES2 version string in beginning + rsVp.insertShaderSource(0, 0, es2_prelude[0]); + rsFpPos = rsFp.insertShaderSource(0, 0, es2_prelude[0]); + } else { + // insert GL2 version string in beginning + rsVp.insertShaderSource(0, 0, gl2_prelude); + rsFpPos = rsFp.insertShaderSource(0, 0, gl2_prelude); + } + // insert required extensions as determined by TextureSequence implementation. + rsFpPos = rsFp.insertShaderSource(0, rsFpPos, texSeq.getRequiredExtensionsShaderStub()); + if(gl.isGLES2()) { + // insert ES2 default precision declaration + rsFpPos = rsFp.insertShaderSource(0, rsFpPos, es2_prelude[1]); + } + // negotiate the texture lookup function name + final String texLookupFuncName = texSeq.getTextureLookupFunctionName(myTextureLookupName); + + // in case a fixed lookup function is being chosen, replace the name in our code + rsFp.replaceInShaderSource(myTextureLookupName, texLookupFuncName); + + // Cache the TextureSequence shader details in StringBuffer: + final StringBuilder sFpIns = new StringBuilder(); + + // .. declaration of the texture sampler using the implementation specific type + sFpIns.append("uniform ").append(texSeq.getTextureSampler2DType()).append(" mgl_ActiveTexture;\n"); + + // .. the actual texture lookup function, maybe null in case a built-in function is being used + sFpIns.append(texSeq.getTextureLookupFragmentShaderImpl()); + + // Now insert the TextureShader details in our shader after the given tag: + rsFp.insertShaderSource(0, "TEXTURE-SEQUENCE-CODE-BEGIN", 0, sFpIns); + + // 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); + } + ... + * </pre> + * The above procedure might look complicated, however, it allows most flexibility and + * workarounds to also deal with GLSL bugs. + * + */ public interface TextureSequence { - + public static final String GL_OES_EGL_image_external_Required_Prelude = "#extension GL_OES_EGL_image_external : enable\n"; + public static final String GL_OES_EGL_image_external = "GL_OES_EGL_image_external"; + public static final String samplerExternalOES = "samplerExternalOES"; + public static final String sampler2D = "sampler2D"; + + /** + * Texture holder interface, maybe specialized by implementation + * to associated related data. + */ public static class TextureFrame { public TextureFrame(Texture t) { texture = t; - // stMatrix = new float[4*4]; - // ProjectFloat.makeIdentityf(stMatrix, 0); } public final Texture getTexture() { return texture; } - // public final float[] getSTMatrix() { return stMatrix; } public String toString() { return "TextureFrame[" + texture + "]"; } protected final Texture texture; - // protected final float[] stMatrix; } public interface TexSeqEventListener<T extends TextureSequence> { @@ -57,8 +132,7 @@ public interface TextureSequence { public void newFrameAvailable(T ts, long when); } - public int getTextureTarget(); - + /** Return the texture unit to be used with this frame. */ public int getTextureUnit(); public int[] getTextureMinMagFilter(); @@ -66,15 +140,17 @@ public interface TextureSequence { public int[] getTextureWrapST(); /** - * Returns the last updated texture. + * Returns the last updated texture. * <p> * In case the instance is just initialized, it shall return a <code>TextureFrame</code> * object with valid attributes. The texture content may be undefined * until the first call of {@link #getNextTexture(GL, boolean)}.<br> * </p> - * Not blocking. + * Not blocking. + * + * @throws IllegalStateException if instance is not initialized */ - public TextureFrame getLastTexture(); + public TextureFrame getLastTexture() throws IllegalStateException ; /** * Returns the next texture to be rendered. @@ -85,6 +161,61 @@ public interface TextureSequence { * <p> * Shall return <code>null</code> in case <i>no</i> frame is available. * </p> + * + * @throws IllegalStateException if instance is not initialized + */ + public TextureFrame getNextTexture(GL gl, boolean blocking) throws IllegalStateException ; + + /** + * In case a shader extension is required, based on the implementation + * and the runtime GL profile, this method returns the preprocessor macros, e.g.: + * <pre> + * #extension GL_OES_EGL_image_external : enable + * </pre> + * + * @throws IllegalStateException if instance is not initialized + */ + public String getRequiredExtensionsShaderStub() throws IllegalStateException ; + + /** + * Returns either <code>sampler2D</code> or <code>samplerExternalOES</code> + * depending on {@link #getLastTexture()}.{@link TextureFrame#getTexture() getTexture()}.{@link Texture#getTarget() getTarget()}. + * + * @throws IllegalStateException if instance is not initialized + **/ + public String getTextureSampler2DType() throws IllegalStateException ; + + /** + * @param desiredFuncName desired lookup function name. If <code>null</code> or ignored by the implementation, + * a build-in name is returned. + * @return the final lookup function name + * + * @see {@link #getTextureLookupFragmentShaderImpl()} + * + * @throws IllegalStateException if instance is not initialized + */ + public String getTextureLookupFunctionName(String desiredFuncName) throws IllegalStateException ; + + /** + * Returns the complete texture2D lookup function code of type + * <pre> + * vec4 <i>funcName</i>(in <i>getTextureSampler2DType()</i> image, in vec2 texCoord) { + * vec4 texColor = do_something_with(image, texCoord); + * return texColor; + * } + * </pre> + * <p> + * <i>funcName</i> can be negotiated and queried via {@link #getTextureLookupFunctionName(String)}. + * </p> + * Note: This function may return an empty string in case a build-in lookup + * function is being chosen. If the implementation desires so, + * {@link #getTextureLookupFunctionName(String)} will ignore the desired function name + * and returns the build-in lookup function name. + * </p> + * @see #getTextureLookupFunctionName(String) + * @see #getTextureSampler2DType() + * + * @throws IllegalStateException if instance is not initialized */ - public TextureFrame getNextTexture(GL gl, boolean blocking); + public String getTextureLookupFragmentShaderImpl() throws IllegalStateException ; }
\ No newline at end of file diff --git a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java index 1239db742..f6189f03c 100644 --- a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java +++ b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java @@ -48,6 +48,14 @@ import android.view.Surface; * Android API Level 14: {@link Surface#Surface(android.graphics.SurfaceTexture)} */ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { + static final boolean available; + + static { + available = true; // default .. TODO: May restrict availability ? + } + + public static final boolean isAvailable() { return available; } + MediaPlayer mp; volatile boolean updateSurface = false; Object updateSurfaceLock = new Object(); @@ -61,22 +69,20 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { public AndroidGLMediaPlayerAPI14() { super(); + if(!available) { + throw new RuntimeException("AndroidGLMediaPlayerAPI14 not available"); + } this.setTextureTarget(GLES2.GL_TEXTURE_EXTERNAL_OES); this.setTextureCount(1); mp = new MediaPlayer(); } @Override - public void setPlaySpeed(float rate) { - // n/a + protected boolean setPlaySpeedImpl(float rate) { + return false; } @Override - public float getPlaySpeed() { - return 0; - } - - @Override protected boolean startImpl() { if(null != mp) { try { @@ -124,21 +130,21 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { } @Override - protected long seekImpl(long msec) { + protected int seekImpl(int msec) { if(null != mp) { - mp.seekTo((int)msec); + mp.seekTo(msec); return mp.getCurrentPosition(); } return 0; } @Override - public TextureSequence.TextureFrame getLastTexture() { + protected TextureSequence.TextureFrame getLastTextureImpl() { return lastTexFrame; } @Override - public TextureSequence.TextureFrame getNextTexture(GL gl, boolean blocking) { + protected TextureSequence.TextureFrame getNextTextureImpl(GL gl, boolean blocking) { if(null != stex && null != mp) { // Only block once, no while-loop. // This relaxes locking code of non crucial resources/events. @@ -176,7 +182,7 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { } @Override - public long getCurrentPosition() { + protected int getCurrentPositionImpl() { return null != mp ? mp.getCurrentPosition() : 0; } @@ -214,20 +220,16 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl { } catch (IOException ioe) { throw new IOException("MediaPlayer failed to process stream <"+urlConn.getURL().toExternalForm()+">: "+ioe.getMessage(), ioe); } - width = mp.getVideoWidth(); - height = mp.getVideoHeight(); - fps = 0; - bps = 0; - totalFrames = 0; - duration = mp.getDuration(); - acodec = "unknown"; - vcodec = "unknown"; + updateAttributes(mp.getVideoWidth(), mp.getVideoHeight(), + 0, 0, 0, + 0f, 0, mp.getDuration(), + null, null); } } @Override protected TextureSequence.TextureFrame createTexImage(GL gl, int idx, int[] tex) { - lastTexFrame = new TextureSequence.TextureFrame( createTexImageImpl(gl, idx, tex, true) ); + lastTexFrame = new TextureSequence.TextureFrame( createTexImageImpl(gl, idx, tex, width, height, true) ); return lastTexFrame; } diff --git a/src/jogl/classes/jogamp/opengl/util/av/EGLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/util/av/EGLMediaPlayerImpl.java index 52378d0fd..31f13297b 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/EGLMediaPlayerImpl.java +++ b/src/jogl/classes/jogamp/opengl/util/av/EGLMediaPlayerImpl.java @@ -27,6 +27,7 @@ */ package jogamp.opengl.util.av; +import java.nio.Buffer; import java.nio.IntBuffer; import javax.media.opengl.GL; @@ -41,8 +42,8 @@ import jogamp.opengl.egl.EGLDrawable; import jogamp.opengl.egl.EGLExt; public abstract class EGLMediaPlayerImpl extends GLMediaPlayerImpl { - TextureType texType; - boolean useKHRSync; + final protected TextureType texType; + final protected boolean useKHRSync; public enum TextureType { GL(0), KHRImage(1); @@ -56,18 +57,21 @@ public abstract class EGLMediaPlayerImpl extends GLMediaPlayerImpl { public static class EGLTextureFrame extends TextureSequence.TextureFrame { - public EGLTextureFrame(Texture t, long khrImage, long khrSync) { + public EGLTextureFrame(Buffer clientBuffer, Texture t, long khrImage, long khrSync) { super(t); + this.clientBuffer = clientBuffer; this.image = khrImage; this.sync = khrSync; } + public final Buffer getClientBuffer() { return clientBuffer; } public final long getImage() { return image; } public final long getSync() { return sync; } public String toString() { - return "EGLTextureFrame[" + texture + ", img "+ image + ", sync "+ sync+"]"; + return "EGLTextureFrame[" + texture + ", img "+ image + ", sync "+ sync+", clientBuffer "+clientBuffer+"]"; } + protected final Buffer clientBuffer; protected final long image; protected final long sync; } @@ -85,30 +89,43 @@ public abstract class EGLMediaPlayerImpl extends GLMediaPlayerImpl { @Override protected TextureSequence.TextureFrame createTexImage(GL gl, int idx, int[] tex) { - final Texture texture = super.createTexImageImpl(gl, idx, tex, true); + final Texture texture = super.createTexImageImpl(gl, idx, tex, width, height, false); + final Buffer clientBuffer; final long image; final long sync; + final boolean eglUsage = TextureType.KHRImage == texType || useKHRSync ; + final EGLContext eglCtx; + final EGLExt eglExt; + final EGLDrawable eglDrawable; - final EGLContext eglCtx = (EGLContext) gl.getContext(); - final EGLExt eglExt = eglCtx.getEGLExt(); - final EGLDrawable eglDrawable = (EGLDrawable) eglCtx.getGLDrawable(); - int[] tmp = new int[1]; - IntBuffer nioTmp = Buffers.newDirectIntBuffer(1); + if(eglUsage) { + eglCtx = (EGLContext) gl.getContext(); + eglExt = eglCtx.getEGLExt(); + eglDrawable = (EGLDrawable) eglCtx.getGLDrawable(); + } else { + eglCtx = null; + eglExt = null; + eglDrawable = null; + } if(TextureType.KHRImage == texType) { + IntBuffer nioTmp = Buffers.newDirectIntBuffer(1); // create EGLImage from texture + clientBuffer = null; // FIXME nioTmp.put(0, EGL.EGL_NONE); image = eglExt.eglCreateImageKHR( eglDrawable.getDisplay(), eglCtx.getHandle(), EGLExt.EGL_GL_TEXTURE_2D_KHR, - null /* buffer */, nioTmp); + clientBuffer, nioTmp); if (0==image) { throw new RuntimeException("EGLImage creation failed: "+EGL.eglGetError()+", ctx "+eglCtx+", tex "+tex[idx]+", err "+toHexString(EGL.eglGetError())); } } else { + clientBuffer = null; image = 0; } if(useKHRSync) { + int[] tmp = new int[1]; // 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. @@ -120,14 +137,25 @@ public abstract class EGLMediaPlayerImpl extends GLMediaPlayerImpl { } else { sync = 0; } - return new EGLTextureFrame(texture, image, sync); + return new EGLTextureFrame(clientBuffer, texture, image, sync); } @Override protected void destroyTexImage(GL gl, TextureSequence.TextureFrame imgTex) { - final EGLContext eglCtx = (EGLContext) gl.getContext(); - final EGLExt eglExt = eglCtx.getEGLExt(); - final EGLDrawable eglDrawable = (EGLDrawable) eglCtx.getGLDrawable(); + final boolean eglUsage = TextureType.KHRImage == texType || useKHRSync ; + final EGLContext eglCtx; + final EGLExt eglExt; + final EGLDrawable eglDrawable; + + if(eglUsage) { + eglCtx = (EGLContext) gl.getContext(); + eglExt = eglCtx.getEGLExt(); + eglDrawable = (EGLDrawable) eglCtx.getGLDrawable(); + } else { + eglCtx = null; + eglExt = null; + eglDrawable = null; + } final EGLTextureFrame eglTex = (EGLTextureFrame) imgTex; if(0!=eglTex.getImage()) { diff --git a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java index bc3fa0919..d3d45e692 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java +++ b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java @@ -34,6 +34,7 @@ import java.util.HashMap; import java.util.Iterator; import javax.media.opengl.GL; +import javax.media.opengl.GL2; import javax.media.opengl.GLES2; import javax.media.opengl.GLException; @@ -55,11 +56,16 @@ import com.jogamp.opengl.util.texture.TextureSequence; */ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { + protected static final String unknown = "unknown"; + protected State state; protected int textureCount; protected int textureTarget; + protected int textureFormat; + protected int textureType; protected int texUnit; + protected int[] texMinMagFilter = { GL.GL_NEAREST, GL.GL_NEAREST }; protected int[] texWrapST = { GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE }; @@ -71,20 +77,24 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { protected int width = 0; /** Shall be set by the {@link #initGLStreamImpl(GL, int[])} method implementation. */ protected int height = 0; - /** Shall be set by the {@link #initGLStreamImpl(GL, int[])} method implementation. */ - protected int fps = 0; - /** Shall be set by the {@link #initGLStreamImpl(GL, int[])} method implementation. */ - protected long bps = 0; + /** Video fps. Shall be set by the {@link #initGLStreamImpl(GL, int[])} method implementation. */ + protected float fps = 0; + /** Stream bps. Shall be set by the {@link #initGLStreamImpl(GL, int[])} method implementation. */ + protected int bps_stream = 0; + /** Video bps. Shall be set by the {@link #initGLStreamImpl(GL, int[])} method implementation. */ + protected int bps_video = 0; + /** Audio bps. Shall be set by the {@link #initGLStreamImpl(GL, int[])} method implementation. */ + protected int bps_audio = 0; /** In frames. Shall be set by the {@link #initGLStreamImpl(GL, int[])} method implementation. */ - protected long totalFrames = 0; + protected int totalFrames = 0; /** In ms. Shall be set by the {@link #initGLStreamImpl(GL, int[])} method implementation. */ - protected long duration = 0; + protected int duration = 0; /** Shall be set by the {@link #initGLStreamImpl(GL, int[])} method implementation. */ - protected String acodec = null; + protected String acodec = unknown; /** Shall be set by the {@link #initGLStreamImpl(GL, int[])} method implementation. */ - protected String vcodec = null; - - protected long frameNumber = 0; + protected String vcodec = unknown; + + protected int frameNumber = 0; protected TextureSequence.TextureFrame[] texFrames = null; protected HashMap<Integer, TextureSequence.TextureFrame> texFrameMap = new HashMap<Integer, TextureSequence.TextureFrame>(); @@ -93,22 +103,27 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { protected GLMediaPlayerImpl() { this.textureCount=3; this.textureTarget=GL.GL_TEXTURE_2D; + this.textureFormat = GL.GL_RGBA; + this.textureType = GL.GL_UNSIGNED_BYTE; this.texUnit = 0; this.state = State.Uninitialized; } + @Override public void setTextureUnit(int u) { texUnit = u; } + + @Override public int getTextureUnit() { return texUnit; } protected final void setTextureCount(int textureCount) { this.textureCount=textureCount; } + @Override public final int getTextureCount() { return textureCount; } - protected final void setTextureTarget(int textureTarget) { - this.textureTarget=textureTarget; - } - public final int getTextureTarget() { return textureTarget; } + protected final void setTextureTarget(int target) { textureTarget=target; } + protected final void setTextureFormat(int f) { textureFormat=f; } + protected final void setTextureType(int t) { textureType=t; } public final void setTextureMinMagFilter(int[] minMagFilter) { texMinMagFilter[0] = minMagFilter[0]; texMinMagFilter[1] = minMagFilter[1];} public final int[] getTextureMinMagFilter() { return texMinMagFilter; } @@ -116,6 +131,98 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { public final void setTextureWrapST(int[] wrapST) { texWrapST[0] = wrapST[0]; texWrapST[1] = wrapST[1];} public final int[] getTextureWrapST() { return texWrapST; } + @Override + public final TextureSequence.TextureFrame getLastTexture() throws IllegalStateException { + if(State.Uninitialized == state) { + throw new IllegalStateException("Instance not initialized: "+this); + } + return getLastTextureImpl(); + } + protected abstract TextureSequence.TextureFrame getLastTextureImpl(); + + @Override + public final synchronized TextureSequence.TextureFrame getNextTexture(GL gl, boolean blocking) throws IllegalStateException { + if(State.Uninitialized == state) { + throw new IllegalStateException("Instance not initialized: "+this); + } + if(State.Playing == state) { + final TextureSequence.TextureFrame f = getNextTextureImpl(gl, blocking); + return f; + } + return getLastTextureImpl(); + } + protected abstract TextureSequence.TextureFrame getNextTextureImpl(GL gl, boolean blocking); + + @Override + public String getRequiredExtensionsShaderStub() throws IllegalStateException { + if(State.Uninitialized == state) { + throw new IllegalStateException("Instance not initialized: "+this); + } + if(GLES2.GL_TEXTURE_EXTERNAL_OES == textureTarget) { + return TextureSequence.GL_OES_EGL_image_external_Required_Prelude; + } + return ""; + } + + @Override + public String getTextureSampler2DType() throws IllegalStateException { + if(State.Uninitialized == state) { + throw new IllegalStateException("Instance not initialized: "+this); + } + switch(textureTarget) { + case GL.GL_TEXTURE_2D: + case GL2.GL_TEXTURE_RECTANGLE: + return TextureSequence.sampler2D; + case GLES2.GL_TEXTURE_EXTERNAL_OES: + return TextureSequence.samplerExternalOES; + default: + throw new GLException("Unsuported texture target: "+toHexString(textureTarget)); + } + } + + /** + * {@inheritDoc} + * + * This implementation simply returns the build-in function name of <code>texture2D</code>, + * if not overridden by specialization. + */ + @Override + public String getTextureLookupFunctionName(String desiredFuncName) throws IllegalStateException { + if(State.Uninitialized == state) { + throw new IllegalStateException("Instance not initialized: "+this); + } + return "texture2D"; + } + + /** + * {@inheritDoc} + * + * This implementation simply returns an empty string since it's using + * the build-in function <code>texture2D</code>, + * if not overridden by specialization. + */ + @Override + public String getTextureLookupFragmentShaderImpl() throws IllegalStateException { + if(State.Uninitialized == state) { + throw new IllegalStateException("Instance not initialized: "+this); + } + return ""; + } + + @Override + public final synchronized float getPlaySpeed() { + return playSpeed; + } + + @Override + public final synchronized void setPlaySpeed(float rate) { + if(State.Uninitialized != state && setPlaySpeedImpl(rate)) { + playSpeed = rate; + } + if(DEBUG) { System.err.println("SetPlaySpeed: "+toString()); } + } + protected abstract boolean setPlaySpeedImpl(float rate); + public final State start() { switch(state) { case Stopped: @@ -124,6 +231,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { state = State.Playing; } } + if(DEBUG) { System.err.println("Start: "+toString()); } return state; } protected abstract boolean startImpl(); @@ -132,6 +240,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { if(State.Playing == state && pauseImpl()) { state = State.Paused; } + if(DEBUG) { System.err.println("Pause: "+toString()); } return state; } protected abstract boolean pauseImpl(); @@ -144,12 +253,22 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { state = State.Stopped; } } + if(DEBUG) { System.err.println("Stop: "+toString()); } return state; } protected abstract boolean stopImpl(); - public final long seek(long msec) { - final long cp; + @Override + public final int getCurrentPosition() { + if(State.Uninitialized != state) { + return getCurrentPositionImpl(); + } + return 0; + } + protected abstract int getCurrentPositionImpl(); + + public final int seek(int msec) { + final int cp; switch(state) { case Stopped: case Playing: @@ -159,14 +278,15 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { default: cp = 0; } + if(DEBUG) { System.err.println("Seek("+msec+"): "+toString()); } return cp; } - protected abstract long seekImpl(long msec); + protected abstract int seekImpl(int msec); public final State getState() { return state; } @Override - public State initGLStream(GL gl, URLConnection urlConn) throws IllegalStateException, GLException, IOException { + public final State initGLStream(GL gl, URLConnection urlConn) throws IllegalStateException, GLException, IOException { if(State.Uninitialized != state) { throw new IllegalStateException("Instance not in state "+State.Uninitialized+", but "+state+", "+this); } @@ -212,7 +332,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { * @see #width * @see #height * @see #fps - * @see #bps + * @see #bps_stream * @see #totalFrames * @see #acodec * @see #vcodec @@ -220,13 +340,14 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { protected abstract void initGLStreamImpl(GL gl, int[] texNames) throws IOException; protected TextureSequence.TextureFrame createTexImage(GL gl, int idx, int[] tex) { - return new TextureSequence.TextureFrame( createTexImageImpl(gl, idx, tex, false) ); + return new TextureSequence.TextureFrame( createTexImageImpl(gl, idx, tex, width, height, false) ); } - protected Texture createTexImageImpl(GL gl, int idx, int[] tex, boolean mustFlipVertically) { + protected Texture createTexImageImpl(GL gl, int idx, int[] tex, int tWidth, int tHeight, boolean mustFlipVertically) { if( 0 > tex[idx] ) { throw new RuntimeException("TextureName "+toHexString(tex[idx])+" invalid."); } + gl.glActiveTexture(GL.GL_TEXTURE0+getTextureUnit()); gl.glBindTexture(textureTarget, tex[idx]); { final int err = gl.glGetError(); @@ -241,18 +362,22 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { textureTarget, // target 0, // level GL.GL_RGBA, // internal format - width, // width - height, // height + tWidth, // width + tHeight, // height 0, // border - GL.GL_RGBA, // format - GL.GL_UNSIGNED_BYTE, // type + textureFormat, + textureType, 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)); + throw new RuntimeException("Couldn't create TexImage2D RGBA "+tWidth+"x"+tHeight+", err "+toHexString(err)); } } + if(DEBUG) { + System.err.println("Created TexImage2D RGBA "+tWidth+"x"+tHeight+", target "+toHexString(textureTarget)+ + ", ifmt "+toHexString(GL.GL_RGBA)+", fmt "+toHexString(textureFormat)+", type "+toHexString(textureType)); + } } gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MIN_FILTER, texMinMagFilter[0]); gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MAG_FILTER, texMinMagFilter[1]); @@ -261,8 +386,8 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { return com.jogamp.opengl.util.texture.TextureIO.newTexture(tex[idx], textureTarget, - width, height, - width, height, + tWidth, tHeight, + width, height, mustFlipVertically); } @@ -283,14 +408,52 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { texFrameMap.clear(); } - protected void attributesUpdated(int event_mask) { + protected final void updateAttributes(int width, int height, int bps_stream, int bps_video, int bps_audio, + float fps, int totalFrames, int duration, + String vcodec, String acodec) { + int event_mask = 0; + if( this.width != width || this.height != height ) { + event_mask |= GLMediaEventListener.EVENT_CHANGE_SIZE; + this.width = width; + this.height = height; + } + if( this.fps != fps ) { + event_mask |= GLMediaEventListener.EVENT_CHANGE_FPS; + this.fps = fps; + } + if( this.bps_stream != bps_stream || this.bps_video != bps_video || this.bps_audio != bps_audio ) { + event_mask |= GLMediaEventListener.EVENT_CHANGE_BPS; + this.bps_stream = bps_stream; + this.bps_video = bps_video; + this.bps_audio = bps_audio; + } + if( this.totalFrames != totalFrames || this.duration != duration ) { + event_mask |= GLMediaEventListener.EVENT_CHANGE_LENGTH; + this.totalFrames = totalFrames; + this.duration = duration; + } + if( (null!=acodec && acodec.length()>0 && !this.acodec.equals(acodec)) ) { + event_mask |= GLMediaEventListener.EVENT_CHANGE_CODEC; + this.acodec = acodec; + } + if( (null!=vcodec && vcodec.length()>0 && !this.vcodec.equals(vcodec)) ) { + event_mask |= GLMediaEventListener.EVENT_CHANGE_CODEC; + this.vcodec = vcodec; + } + if(0==event_mask) { + return; + } + attributesUpdated(event_mask); + } + + protected final void attributesUpdated(int event_mask) { synchronized(eventListenersLock) { for(Iterator<GLMediaEventListener> i = eventListeners.iterator(); i.hasNext(); ) { i.next().attributesChanges(this, event_mask, System.currentTimeMillis()); } } } - protected void newFrameAvailable() { + protected final void newFrameAvailable() { frameNumber++; synchronized(eventListenersLock) { for(Iterator<GLMediaEventListener> i = eventListeners.iterator(); i.hasNext(); ) { @@ -300,12 +463,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { } @Override - public synchronized float getPlaySpeed() { - return playSpeed; - } - - @Override - public synchronized State destroy(GL gl) { + public final synchronized State destroy(GL gl) { destroyImpl(gl); removeAllImageTextures(gl); state = State.Uninitialized; @@ -314,59 +472,72 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { protected abstract void destroyImpl(GL gl); @Override - public synchronized URLConnection getURLConnection() { + public final synchronized URLConnection getURLConnection() { return urlConn; } @Override - public synchronized String getVideoCodec() { + public final synchronized String getVideoCodec() { return vcodec; } @Override - public synchronized String getAudioCodec() { + public final synchronized String getAudioCodec() { return acodec; } @Override - public synchronized long getTotalFrames() { + public final synchronized long getTotalFrames() { return totalFrames; } @Override - public synchronized long getDuration() { + public final synchronized int getDuration() { return duration; } @Override - public synchronized long getBitrate() { - return bps; + public final synchronized long getStreamBitrate() { + return bps_stream; } @Override - public synchronized int getFramerate() { + public final synchronized int getVideoBitrate() { + return bps_video; + } + + @Override + public final synchronized int getAudioBitrate() { + return bps_audio; + } + + @Override + public final synchronized float getFramerate() { return fps; } @Override - public synchronized int getWidth() { + public final synchronized int getWidth() { return width; } @Override - public synchronized int getHeight() { + public final synchronized int getHeight() { return height; } @Override - public synchronized String toString() { + public final synchronized String toString() { final float ct = getCurrentPosition() / 1000.0f, tt = getDuration() / 1000.0f; final String loc = ( null != urlConn ) ? urlConn.getURL().toExternalForm() : "<undefined stream>" ; - return "GLMediaPlayer ["+state+", "+frameNumber+"/"+totalFrames+" frames, "+ct+"/"+tt+"s, stream [video ["+vcodec+", "+width+"x"+height+", "+fps+"fps, "+bps+"bsp], "+loc+"]]"; + return "GLMediaPlayer["+state+", "+frameNumber+"/"+totalFrames+" frames, "+ct+"/"+tt+"s, speed "+playSpeed+", "+bps_stream+" bps, "+ + "Texture[count "+textureCount+", target "+toHexString(textureTarget)+", format "+toHexString(textureFormat)+", type "+toHexString(textureType)+"], "+ + "Stream[Video[<"+vcodec+">, "+width+"x"+height+", "+fps+" fps, "+bps_video+" bsp], "+ + "Audio[<"+acodec+">, "+bps_audio+" bsp]], "+loc+"]"; } @Override - public void addEventListener(GLMediaEventListener l) { + public final void addEventListener(GLMediaEventListener l) { if(l == null) { return; } @@ -376,7 +547,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { } @Override - public void removeEventListener(GLMediaEventListener l) { + public final void removeEventListener(GLMediaEventListener l) { if (l == null) { return; } @@ -386,7 +557,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer { } @Override - public synchronized GLMediaEventListener[] getEventListeners() { + public final synchronized GLMediaEventListener[] getEventListeners() { synchronized(eventListenersLock) { return eventListeners.toArray(new GLMediaEventListener[eventListeners.size()]); } diff --git a/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java index c97f04225..fe2aeaf19 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java +++ b/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java @@ -49,8 +49,8 @@ import com.jogamp.opengl.util.texture.TextureSequence; public class NullGLMediaPlayer extends GLMediaPlayerImpl { private TextureData texData = null; private TextureSequence.TextureFrame frame = null; - private long pos_ms = 0; - private long pos_start = 0; + private int pos_ms = 0; + private int pos_start = 0; public NullGLMediaPlayer() { super(); @@ -58,18 +58,13 @@ public class NullGLMediaPlayer extends GLMediaPlayerImpl { } @Override - public void setPlaySpeed(float rate) { - // n/a + protected boolean setPlaySpeedImpl(float rate) { + return false; } @Override - public float getPlaySpeed() { - return 0; - } - - @Override protected boolean startImpl() { - pos_start = System.currentTimeMillis(); + pos_start = (int)System.currentTimeMillis(); return true; } @@ -84,25 +79,25 @@ public class NullGLMediaPlayer extends GLMediaPlayerImpl { } @Override - protected long seekImpl(long msec) { + protected int seekImpl(int msec) { pos_ms = msec; validatePos(); return pos_ms; } @Override - public TextureSequence.TextureFrame getLastTexture() { + protected TextureSequence.TextureFrame getLastTextureImpl() { return frame; } @Override - public TextureSequence.TextureFrame getNextTexture(GL gl, boolean blocking) { + protected TextureSequence.TextureFrame getNextTextureImpl(GL gl, boolean blocking) { return frame; } @Override - public long getCurrentPosition() { - pos_ms = System.currentTimeMillis() - pos_start; + protected int getCurrentPositionImpl() { + pos_ms = (int)System.currentTimeMillis() - pos_start; validatePos(); return pos_ms; } @@ -137,17 +132,15 @@ public class NullGLMediaPlayer extends GLMediaPlayerImpl { GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, false, false, false, buffer, null); } - fps = 30; - bps = 0; - totalFrames = 0; - duration = 10*60*1000; - acodec = "none"; - vcodec = "tga-dummy"; + fps = 24f; + duration = 10*60*1000; // msec + totalFrames = (int) ( (duration/1000)*fps ); + vcodec = "png-static"; } @Override protected TextureSequence.TextureFrame createTexImage(GL gl, int idx, int[] tex) { - Texture texture = super.createTexImageImpl(gl, idx, tex, false); + Texture texture = super.createTexImageImpl(gl, idx, tex, width, height, false); if(null != texData) { texture.updateImage(gl, texData); texData.destroy(); diff --git a/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java index ebbdf252f..7c812ce1c 100644 --- a/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java +++ b/src/jogl/classes/jogamp/opengl/util/av/impl/OMXGLMediaPlayer.java @@ -6,6 +6,7 @@ import java.net.URL; import javax.media.opengl.GL; import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; import com.jogamp.opengl.util.texture.TextureSequence; @@ -13,22 +14,25 @@ import jogamp.opengl.egl.EGL; import jogamp.opengl.util.av.EGLMediaPlayerImpl; public class OMXGLMediaPlayer extends EGLMediaPlayerImpl { + static final boolean available; + + static { + // OMX binding is included in jogl_desktop and jogl_mobile + GLProfile.initSingleton(); + available = initIDs0(); + } + + public static final boolean isAvailable() { return available; } + 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; - protected long o_duration = 0; - protected TextureSequence.TextureFrame lastTex = null; public OMXGLMediaPlayer() { super(TextureType.KHRImage, true); + if(!available) { + throw new RuntimeException("OMXGLMediaPlayer not available"); + } initOMX(); } @@ -80,20 +84,17 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl { } @Override - public synchronized long getCurrentPosition() { - if(0==moviePtr) { - throw new GLException("OMX native instance null"); - } - return _getCurrentPosition(moviePtr); + protected int getCurrentPositionImpl() { + return 0!=moviePtr ? _getCurrentPosition(moviePtr) : 0; } @Override - public synchronized void setPlaySpeed(float rate) { + protected boolean setPlaySpeedImpl(float rate) { if(0==moviePtr) { throw new GLException("OMX native instance null"); } _setPlaySpeed(moviePtr, rate); - playSpeed = rate; + return true; } @Override @@ -127,7 +128,7 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl { /** @return time position after issuing the command */ @Override - protected long seekImpl(long msec) { + protected int seekImpl(int msec) { if(0==moviePtr) { throw new GLException("OMX native instance null"); } @@ -135,12 +136,12 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl { } @Override - public TextureSequence.TextureFrame getLastTexture() { + protected TextureSequence.TextureFrame getLastTextureImpl() { return lastTex; } @Override - public synchronized TextureSequence.TextureFrame getNextTexture(GL gl, boolean blocking) { + protected TextureSequence.TextureFrame getNextTextureImpl(GL gl, boolean blocking) { if(0==moviePtr) { throw new GLException("OMX native instance null"); } @@ -154,38 +155,6 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl { return lastTex; } - 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; - o_duration = duration; - } - private String replaceAll(String orig, String search, String repl) { String dest=null; // In case replaceAll / java.util.regex.* is not supported (-> CVM) @@ -206,21 +175,22 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl { } } - native long _createInstance(); - native void _destroyInstance(long moviePtr); + private static native boolean initIDs0(); + private native long _createInstance(); + private 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); + private native void _detachVideoRenderer(long moviePtr); // stop before + private native void _attachVideoRenderer(long moviePtr); // detach before + private native void _setStream(long moviePtr, int textureNum, String path); + private native void _activateStream(long moviePtr); - native void _setStreamEGLImageTexture2D(long moviePtr, int i, int tex, long image, long sync); - native long _seek(long moviePtr, long 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, boolean blocking); - native long _getCurrentPosition(long moviePtr); + private native void _setStreamEGLImageTexture2D(long moviePtr, int i, int tex, long image, long sync); + private native int _seek(long moviePtr, int position); + private native void _setPlaySpeed(long moviePtr, float rate); + private native void _play(long moviePtr); + private native void _pause(long moviePtr); + private native void _stop(long moviePtr); + private native int _getNextTextureID(long moviePtr, boolean blocking); + private native int _getCurrentPosition(long moviePtr); } diff --git a/src/jogl/native/JoglCommon.c b/src/jogl/native/JoglCommon.c index 719e0df56..d9f5edd49 100644 --- a/src/jogl/native/JoglCommon.c +++ b/src/jogl/native/JoglCommon.c @@ -11,48 +11,63 @@ static jclass runtimeExceptionClz=NULL; static JavaVM *_jvmHandle = NULL; static int _jvmVersion = 0; +void JoglCommon_init(JNIEnv *env) { + if(NULL==runtimeExceptionClz) { + jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); + if(NULL==c) { + JoglCommon_FatalError(env, "JOGL: can't find %s", ClazzNameRuntimeException); + } + runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==runtimeExceptionClz) { + JoglCommon_FatalError(env, "JOGL: can't use %s", ClazzNameRuntimeException); + } + } + if(0 != (*env)->GetJavaVM(env, &_jvmHandle)) { + JoglCommon_FatalError(env, "JOGL: can't fetch JavaVM handle"); + } else { + _jvmVersion = (*env)->GetVersion(env); + } +} void JoglCommon_FatalError(JNIEnv *env, const char* msg, ...) { char buffer[512]; va_list ap; + int shallBeDetached = 0; + + if(NULL == env) { + env = JoglCommon_GetJNIEnv (&shallBeDetached); + } va_start(ap, msg); vsnprintf(buffer, sizeof(buffer), msg, ap); va_end(ap); fprintf(stderr, "%s\n", buffer); - (*env)->FatalError(env, buffer); + if(NULL != env) { + (*env)->FatalError(env, buffer); + JoglCommon_ReleaseJNIEnv (shallBeDetached); + } } void JoglCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) { char buffer[512]; va_list ap; + int shallBeDetached = 0; + + if(NULL == env) { + env = JoglCommon_GetJNIEnv (&shallBeDetached); + } va_start(ap, msg); vsnprintf(buffer, sizeof(buffer), msg, ap); va_end(ap); - (*env)->ThrowNew(env, runtimeExceptionClz, buffer); -} - -void JoglCommon_init(JNIEnv *env) { - if(NULL==runtimeExceptionClz) { - jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); - if(NULL==c) { - JoglCommon_FatalError(env, "JOGL: can't find %s", ClazzNameRuntimeException); - } - runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==runtimeExceptionClz) { - JoglCommon_FatalError(env, "JOGL: can't use %s", ClazzNameRuntimeException); - } - } - if(0 != (*env)->GetJavaVM(env, &_jvmHandle)) { - JoglCommon_FatalError(env, "JOGL: can't fetch JavaVM handle"); - } else { - _jvmVersion = (*env)->GetVersion(env); + if(NULL != env) { + (*env)->ThrowNew(env, runtimeExceptionClz, buffer); + JoglCommon_ReleaseJNIEnv (shallBeDetached); } } @@ -110,7 +125,6 @@ JNIEnv* JoglCommon_GetJNIEnv (int * shallBeDetached) void JoglCommon_ReleaseJNIEnv (int shallBeDetached) { if(NULL == _jvmHandle) { fprintf(stderr, "JOGL: No JavaVM handle registered, call JoglCommon_init(..) 1st"); - return NULL; } if(shallBeDetached) { diff --git a/src/jogl/native/JoglCommon.h b/src/jogl/native/JoglCommon.h index b988336fa..023b4be03 100644 --- a/src/jogl/native/JoglCommon.h +++ b/src/jogl/native/JoglCommon.h @@ -15,7 +15,10 @@ int JoglCommon_GetJVMVersion(); jchar* JoglCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str); +/** env may be NULL, in which case JoglCommon_GetJNIEnv() is being used. */ void JoglCommon_FatalError(JNIEnv *env, const char* msg, ...); + +/** env may be NULL, in which case JoglCommon_GetJNIEnv() is being used. */ void JoglCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); /** diff --git a/src/jogl/native/openmax/jogamp_opengl_util_av_impl_OMXGLMediaPlayer.c b/src/jogl/native/openmax/jogamp_opengl_util_av_impl_OMXGLMediaPlayer.c index 60e436678..964ac64a7 100644 --- a/src/jogl/native/openmax/jogamp_opengl_util_av_impl_OMXGLMediaPlayer.c +++ b/src/jogl/native/openmax/jogamp_opengl_util_av_impl_OMXGLMediaPlayer.c @@ -14,94 +14,68 @@ // http://developer.apple.com/qa/qa2001/qa1262.html #include "jogamp_opengl_util_av_impl_OMXGLMediaPlayer.h" +#include "JoglCommon.h" #include "omx_tool.h" #include <stdarg.h> -static const char * const ClazzNameRuntimeException = - "java/lang/RuntimeException"; -static jclass runtimeExceptionClz=NULL; +static const char * const ClazzNameOMXGLMediaPlayer = "jogamp/opengl/util/av/impl/OMXGLMediaPlayer"; + +static jclass omxGLMediaPlayerClazz = NULL; +static jmethodID jni_mid_updateAttributes = NULL; + #ifdef _WIN32_WCE #define STDOUT_FILE "\\Storage Card\\demos\\stdout.txt" #define STDERR_FILE "\\Storage Card\\demos\\stderr.txt" #endif -static void _initStatics(JNIEnv *env) +JNIEXPORT jboolean JNICALL Java_jogamp_opengl_util_av_impl_OMXGLMediaPlayer_initIDs0 + (JNIEnv *env, jclass clazz) { - jclass c; #ifdef _WIN32_WCE _wfreopen(TEXT(STDOUT_FILE),L"w",stdout); _wfreopen(TEXT(STDERR_FILE),L"w",stderr); #endif - fprintf(stdout, "_initstatics ..\n"); fflush(stdout); // JAU - if (runtimeExceptionClz != NULL) { + JoglCommon_init(env); + + jclass c; + if (omxGLMediaPlayerClazz != NULL) { return; } - c = (*env)->FindClass(env, ClazzNameRuntimeException); + c = (*env)->FindClass(env, ClazzNameOMXGLMediaPlayer); if(NULL==c) { - fprintf(stdout, "FatalError: can't find %s\n", ClazzNameRuntimeException); - (*env)->FatalError(env, ClazzNameRuntimeException); + JoglCommon_FatalError(env, "JOGL OMX: can't find %s", ClazzNameOMXGLMediaPlayer); } - runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); - if(NULL==runtimeExceptionClz) { - fprintf(stdout, "FatalError: can't use %s\n", ClazzNameRuntimeException); - (*env)->FatalError(env, ClazzNameRuntimeException); + omxGLMediaPlayerClazz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==omxGLMediaPlayerClazz) { + JoglCommon_FatalError(env, "JOGL OMX: can't use %s", ClazzNameOMXGLMediaPlayer); } -} -void java_throwNewRuntimeException(intptr_t jni_env, const char* format, ...) -{ - va_list ap; - char buffer[255]; - va_start(ap, format); - #ifdef _WIN32 - _vsnprintf(buffer, sizeof(buffer)-1, format, ap); - #else - vsnprintf(buffer, sizeof(buffer)-1, format, ap); - #endif - va_end(ap); - buffer[sizeof(buffer)-1]=0; - fprintf(stderr, "RuntimeException: %s\n", buffer); fflush(stderr); - if(jni_env!=0) { - (*((JNIEnv *)jni_env))->ThrowNew((JNIEnv *)jni_env, runtimeExceptionClz, buffer); - } -} + jni_mid_updateAttributes = (*env)->GetMethodID(env, omxGLMediaPlayerClazz, "updateAttributes", "(IIIIIFIILjava/lang/String;Ljava/lang/String;)V"); -void OMXInstance_SaveJavaAttributes(OMXToolBasicAV_t *pOMXAV, KDboolean issueJavaCallback) -{ - if(NULL==pOMXAV || 0==pOMXAV->jni_env || 0==pOMXAV->jni_instance) { - fprintf(stderr, "OMXInstance_SaveJavaAttributes failed"); - return; - } else if(issueJavaCallback==KD_TRUE) { - JNIEnv * env = (JNIEnv *)pOMXAV->jni_env; - jobject instance = (jobject)pOMXAV->jni_instance; - (*env)->CallVoidMethod(env, instance, (jmethodID)pOMXAV->jni_mid_saveAttributes); + if(jni_mid_updateAttributes == NULL) { + return JNI_FALSE; } + return JNI_TRUE; } -void OMXInstance_UpdateJavaAttributes(OMXToolBasicAV_t *pOMXAV, KDboolean issueJavaCallback) +void OMXInstance_UpdateJavaAttributes(OMXToolBasicAV_t *pAV) { - if(NULL==pOMXAV || 0==pOMXAV->jni_env || 0==pOMXAV->jni_instance) { + if(NULL==pAV || 0==pAV->jni_instance) { fprintf(stderr, "OMXInstance_UpdateJavaAttributes failed"); return; - } else { - JNIEnv * env = (JNIEnv *)pOMXAV->jni_env; - jobject instance = (jobject)pOMXAV->jni_instance; - (*env)->SetIntField(env, instance, (jfieldID)pOMXAV->jni_fid_width, (jint)pOMXAV->width); - (*env)->SetIntField(env, instance, (jfieldID)pOMXAV->jni_fid_height, (jint)pOMXAV->height); - (*env)->SetIntField(env, instance, (jfieldID)pOMXAV->jni_fid_fps, (jint)pOMXAV->framerate); - (*env)->SetLongField(env, instance, (jfieldID)pOMXAV->jni_fid_bps, (jlong)pOMXAV->bitrate); - (*env)->SetLongField(env, instance, (jfieldID)pOMXAV->jni_fid_totalFrames, (jlong)(pOMXAV->length*pOMXAV->framerate)); - if(issueJavaCallback==KD_TRUE) { - (*env)->CallVoidMethod(env, instance, (jmethodID)pOMXAV->jni_mid_attributesUpdated); - } else { - if(strlen(pOMXAV->videoCodec)>0) { - (*env)->SetObjectField(env, instance, (jfieldID)pOMXAV->jni_fid_vcodec, (*env)->NewStringUTF(env, pOMXAV->videoCodec)); - } - if(strlen(pOMXAV->audioCodec)>0) { - (*env)->SetObjectField(env, instance, (jfieldID)pOMXAV->jni_fid_acodec, (*env)->NewStringUTF(env, pOMXAV->audioCodec)); - } - } + } + int shallBeDetached = 0; + JNIEnv * env = JoglCommon_GetJNIEnv (&shallBeDetached); + if(NULL!=env) { + (*env)->CallVoidMethod(env, (jobject)pAV->jni_instance, jni_mid_updateAttributes, + pAV->width, pAV->height, + pAV->bitrate, 0, 0, + pAV->framerate, (uint32_t)(pAV->length*pAV->framerate), pAV->length, + (*env)->NewStringUTF(env, pAV->videoCodec), + (*env)->NewStringUTF(env, pAV->audioCodec) ); + JoglCommon_ReleaseJNIEnv (shallBeDetached); } } @@ -110,26 +84,9 @@ JNIEXPORT jlong JNICALL Java_jogamp_opengl_util_av_impl_OMXGLMediaPlayer__1creat { OMXToolBasicAV_t * pOMXAV; - _initStatics(env); - - pOMXAV->jni_env=(intptr_t)env; - pOMXAV->jni_instance=(intptr_t)instance; - pOMXAV = OMXToolBasicAV_CreateInstance((EGLDisplay)(intptr_t)env); - if(NULL!=pOMXAV) { - jclass cls = (*env)->GetObjectClass(env, instance); - pOMXAV->jni_mid_saveAttributes = (intptr_t) (*env)->GetMethodID(env, cls, "saveAttributes", "()V"); - pOMXAV->jni_mid_attributesUpdated = (intptr_t) (*env)->GetMethodID(env, cls, "attributesUpdated", "()V"); - pOMXAV->jni_fid_width = (intptr_t) (*env)->GetFieldID(env, cls, "width", "I"); - pOMXAV->jni_fid_height = (intptr_t) (*env)->GetFieldID(env, cls, "height", "I"); - pOMXAV->jni_fid_fps = (intptr_t) (*env)->GetFieldID(env, cls, "fps", "I"); - pOMXAV->jni_fid_bps = (intptr_t) (*env)->GetFieldID(env, cls, "bps", "J"); - pOMXAV->jni_fid_totalFrames = (intptr_t) (*env)->GetFieldID(env, cls, "totalFrames", "J"); - pOMXAV->jni_fid_acodec = (intptr_t) (*env)->GetFieldID(env, cls, "acodec", "Ljava/lang/String;"); - pOMXAV->jni_fid_vcodec = (intptr_t) (*env)->GetFieldID(env, cls, "vcodec", "Ljava/lang/String;"); - } - - return (jlong) (intptr_t) (void *)pOMXAV; + pOMXAV->jni_instance=(intptr_t)instance; + return (jlong) (intptr_t) pOMXAV; } JNIEXPORT void JNICALL Java_jogamp_opengl_util_av_impl_OMXGLMediaPlayer__1setStream @@ -142,7 +99,6 @@ JNIEXPORT void JNICALL Java_jogamp_opengl_util_av_impl_OMXGLMediaPlayer__1setStr if (pOMXAV != NULL) { const char *filePath = (*env)->GetStringUTFChars(env, jpath, &iscopy); fprintf(stdout, "setStream 2 %s..\n", filePath); fflush(stdout); // JAU - pOMXAV->jni_env=(intptr_t)env; pOMXAV->jni_instance=(intptr_t)instance; OMXToolBasicAV_SetStream(pOMXAV, vBufferNum, filePath); (*env)->ReleaseStringChars(env, jpath, (const jchar *)filePath); @@ -213,8 +169,8 @@ JNIEXPORT void JNICALL Java_jogamp_opengl_util_av_impl_OMXGLMediaPlayer__1stop OMXToolBasicAV_PlayStop(pOMXAV); } -JNIEXPORT jlong JNICALL Java_jogamp_opengl_util_av_impl_OMXGLMediaPlayer__1seek - (JNIEnv *env, jobject instance, jlong ptr, jlong pos) +JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_OMXGLMediaPlayer__1seek + (JNIEnv *env, jobject instance, jlong ptr, jint pos) { OMXToolBasicAV_t *pOMXAV = (OMXToolBasicAV_t *)((void *)((intptr_t)ptr)); OMXToolBasicAV_PlaySeek(pOMXAV, pos); @@ -232,7 +188,7 @@ JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_OMXGLMediaPlayer__1getNex return textureID; } -JNIEXPORT jlong JNICALL Java_jogamp_opengl_util_av_impl_OMXGLMediaPlayer__1getCurrentPosition +JNIEXPORT jint JNICALL Java_jogamp_opengl_util_av_impl_OMXGLMediaPlayer__1getCurrentPosition (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 5e168ad02..16c43f6a8 100644 --- a/src/jogl/native/openmax/omx_tool.c +++ b/src/jogl/native/openmax/omx_tool.c @@ -28,35 +28,15 @@ #define NOTSET_U32 ((OMX_U32)0xDEDEDEDE) #define INIT_PARAM(_X_) (memset(&(_X_), NOTSET_U8, sizeof(_X_)), ((_X_).nSize = sizeof (_X_)), (_X_).nVersion = vOMX) -void OMXInstance_SaveJavaAttributes(OMXToolBasicAV_t *pOMXAV, KDboolean issueJavaCallback); -void OMXInstance_UpdateJavaAttributes(OMXToolBasicAV_t *pOMXAV, KDboolean issueJavaCallback); +void OMXInstance_UpdateJavaAttributes(OMXToolBasicAV_t *pOMXAV); -#if !defined(SELF_TEST) -void java_throwNewRuntimeException(intptr_t jni_env, const char* format, ...); -#else -#include <stdarg.h> -void java_throwNewRuntimeException(intptr_t jni_env, const char* format, ...) { - va_list ap; - char buffer[255]; - va_start(ap, format); - #ifdef _WIN32 - _vsnprintf(buffer, sizeof(buffer)-1, format, ap); - #else - vsnprintf(buffer, sizeof(buffer)-1, format, ap); - #endif - va_end(ap); - buffer[sizeof(buffer)-1]=0; - DBG_PRINT( "RuntimeException: %s\n", buffer); - exit(1); -} -#endif static void DestroyInstanceUnlock(OMXToolBasicAV_t * pOMXAV); #define OMXSAFEVOID(x) \ do { \ OMX_ERRORTYPE err = (x); \ if (err != OMX_ErrorNone) { \ - java_throwNewRuntimeException((NULL!=pOMXAV)?pOMXAV->jni_env:0, "FAILED at %s:%d, Error: 0x%x\n", __FILE__, __LINE__, err); \ + JoglCommon_throwNewRuntimeException(0, "FAILED at %s:%d, Error: 0x%x\n", __FILE__, __LINE__, err); \ if(NULL!=pOMXAV) { \ DestroyInstanceUnlock(pOMXAV); \ } \ @@ -68,7 +48,7 @@ do { \ do { \ OMX_ERRORTYPE err = (x); \ if (err != OMX_ErrorNone) { \ - java_throwNewRuntimeException((NULL!=pOMXAV)?pOMXAV->jni_env:0, "FAILED at %s:%d, Error: 0x%x\n", __FILE__, __LINE__, err); \ + JoglCommon_throwNewRuntimeException(0, "FAILED at %s:%d, Error: 0x%x\n", __FILE__, __LINE__, err); \ if(NULL!=pOMXAV) { \ DestroyInstanceUnlock(pOMXAV); \ } \ @@ -80,7 +60,7 @@ do { \ do { \ OMX_ERRORTYPE err = (x); \ if (err != OMX_ErrorNone) { \ - java_throwNewRuntimeException((NULL!=pOMXAV)?pOMXAV->jni_env:0, "FAILED at %s:%d, Error: 0x%x\n", __FILE__, __LINE__, err); \ + JoglCommon_throwNewRuntimeException(0, "FAILED at %s:%d, Error: 0x%x\n", __FILE__, __LINE__, err); \ if(NULL!=pOMXAV) { \ DestroyInstanceUnlock(pOMXAV); \ } \ @@ -466,7 +446,7 @@ static void DestroyInstanceUnlock(OMXToolBasicAV_t * pOMXAV) DBG_PRINT( "Destroy p2\n"); if(0!=(res1=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateIdle, KD_TRUE))) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Destroy - Wait for Idle Failed (%d)", res1); + JoglCommon_throwNewRuntimeException(0, "Destroy - Wait for Idle Failed (%d)", res1); } DBG_PRINT( "Destroy p3\n"); @@ -479,7 +459,7 @@ static void DestroyInstanceUnlock(OMXToolBasicAV_t * pOMXAV) if(0!=(res2=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateLoaded, KD_TRUE))) { if(!res1) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Destroy - Wait for Loaded Failed (%d)", res2); + JoglCommon_throwNewRuntimeException(0, "Destroy - Wait for Loaded Failed (%d)", res2); } } @@ -726,19 +706,20 @@ static OMX_ERRORTYPE UpdateStreamInfo(OMXToolBasicAV_t * pOMXAV, KDboolean issue } DBG_PRINT( "Update StreamInfo p1\n" ); - OMXInstance_SaveJavaAttributes(pOMXAV, issueCallback); pOMXAV->width = oPortDef.format.video.nFrameWidth; pOMXAV->height = oPortDef.format.video.nFrameHeight; /* pOMXAV->stride = oPortDef.format.video.nStride; pOMXAV->sliceHeight = oPortDef.format.video.nSliceHeight; */ - pOMXAV->framerate = oPortDef.format.video.xFramerate; + pOMXAV->framerate = (float) oPortDef.format.video.xFramerate; pOMXAV->bitrate = oPortDef.format.video.nBitrate; - DBG_PRINT( "Update StreamInfo p2 %dx%d, fps %d, bps %d\n", pOMXAV->width, pOMXAV->height, pOMXAV->framerate, pOMXAV->bitrate ); + DBG_PRINT( "Update StreamInfo p2 %dx%d, fps %f, bps %d\n", pOMXAV->width, pOMXAV->height, pOMXAV->framerate, pOMXAV->bitrate ); pOMXAV->length = GetMediaLength(pOMXAV); pOMXAV->speed = GetClockScale(pOMXAV); - OMXInstance_UpdateJavaAttributes(pOMXAV, issueCallback); + if(issueCallback) { + OMXInstance_UpdateJavaAttributes(pOMXAV); + } return err; } @@ -755,7 +736,7 @@ static int AttachAudioRenderer(OMXToolBasicAV_t * pOMXAV) // FIXME: proper audio buffering .. OMXSAFE(OMX_GetHandle(&pOMXAV->comp[OMXAV_H_ABUFFERING], "OMX.Nvidia.audio.visualization", pOMXAV, &pOMXAV->callbacks)); if(0!=(res=SyncOnState(pOMXAV->comp[OMXAV_H_ABUFFERING], OMX_StateLoaded))) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Loading AudioBuffering Failed (%d)", res); + JoglCommon_throwNewRuntimeException(0, "Loading AudioBuffering Failed (%d)", res); return res; } /** @@ -777,7 +758,7 @@ static int AttachAudioRenderer(OMXToolBasicAV_t * pOMXAV) // mandatory before SetupTunnel if(0!=(res=SyncOnState(pOMXAV->comp[OMXAV_H_ARENDERER], OMX_StateLoaded))) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Loading AudioRenderer Failed (%d)", res); + JoglCommon_throwNewRuntimeException(0, "Loading AudioRenderer Failed (%d)", res); return res; } @@ -828,7 +809,7 @@ static int AttachVideoRenderer(OMXToolBasicAV_t * pOMXAV) { int i, res=0; if(KD_NULL!=pOMXAV->comp[OMXAV_H_VSCHEDULER]) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Detach Video first"); + JoglCommon_throwNewRuntimeException(0, "Detach Video first"); return -1; } OMXSAFE(OMX_GetHandle(&pOMXAV->comp[OMXAV_H_VSCHEDULER], "OMX.Nvidia.video.scheduler", pOMXAV, &pOMXAV->callbacks)); @@ -836,7 +817,7 @@ static int AttachVideoRenderer(OMXToolBasicAV_t * pOMXAV) // mandatory before SetupTunnel if(0!=(res=SyncOnState(pOMXAV->comp[OMXAV_H_VSCHEDULER], OMX_StateLoaded))) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Loading VideoScheduler Failed (%d)", res); + JoglCommon_throwNewRuntimeException(0, "Loading VideoScheduler Failed (%d)", res); return res; } // mandatory before EGLUseImage @@ -861,7 +842,7 @@ static int AttachVideoRenderer(OMXToolBasicAV_t * pOMXAV) DBG_PRINT( "UseEGLImg %p #%d t:%d i:%p s:%p p1\n", pOMXAV, i, pBuf->tex, pBuf->image, pBuf->sync); if(NULL==pBuf->image) { - java_throwNewRuntimeException(pOMXAV->jni_env, "AttachVideoRenderer: User didn't set buffer %d/%d\n", i, pOMXAV->vBufferNum); + JoglCommon_throwNewRuntimeException(0, "AttachVideoRenderer: User didn't set buffer %d/%d\n", i, pOMXAV->vBufferNum); return -1; } else { // tell decoder output port that it will be using EGLImage @@ -886,7 +867,7 @@ static int DetachVideoRenderer(OMXToolBasicAV_t * pOMXAV) if(NULL==pOMXAV) return -1; if(KD_NULL==pOMXAV->comp[OMXAV_H_VSCHEDULER]) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Attach Video first"); + JoglCommon_throwNewRuntimeException(0, "Attach Video first"); return -1; } DBG_PRINT( "DetachVideoRenderer p0\n"); @@ -968,11 +949,11 @@ void OMXToolBasicAV_SetStream(OMXToolBasicAV_t * pOMXAV, int vBufferNum, const K // FIXME: verify player state .. ie stop ! if(pOMXAV->status!=OMXAV_INIT) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Player instance in use\n"); + JoglCommon_throwNewRuntimeException(0, "Player instance in use\n"); return; } if(vBufferNum>EGLIMAGE_MAX_BUFFERS) { - java_throwNewRuntimeException(pOMXAV->jni_env, "buffer number %d > MAX(%d)\n", vBufferNum, EGLIMAGE_MAX_BUFFERS); + JoglCommon_throwNewRuntimeException(0, "buffer number %d > MAX(%d)\n", vBufferNum, EGLIMAGE_MAX_BUFFERS); return; } @@ -987,7 +968,7 @@ void OMXToolBasicAV_SetStream(OMXToolBasicAV_t * pOMXAV, int vBufferNum, const K eError = AddFile(pOMXAV, stream); if(eError!=OMX_ErrorNone) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Couldn't open or handle stream: %s\n", stream); + JoglCommon_throwNewRuntimeException(0, "Couldn't open or handle stream: %s\n", stream); kdThreadMutexUnlock(pOMXAV->mutex); return; } @@ -1040,7 +1021,7 @@ void OMXToolBasicAV_SetStream(OMXToolBasicAV_t * pOMXAV, int vBufferNum, const K if (pOMXAV->audioPort == -1 && pOMXAV->videoPort == -1) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Neither audioport or videoport could be played back!\n"); + JoglCommon_throwNewRuntimeException(0, "Neither audioport or videoport could be played back!\n"); kdThreadMutexUnlock(pOMXAV->mutex); return; } @@ -1071,12 +1052,12 @@ void OMXToolBasicAV_SetStream(OMXToolBasicAV_t * pOMXAV, int vBufferNum, const K void OMXToolBasicAV_SetStreamEGLImageTexture2D(OMXToolBasicAV_t * pOMXAV, KDint i, GLuint tex, EGLImageKHR image, EGLSyncKHR sync) { if(NULL==pOMXAV) { - java_throwNewRuntimeException(0, "OMX instance null\n"); + JoglCommon_throwNewRuntimeException(0, "OMX instance null\n"); return; } DBG_PRINT( "SetStreamEGLImg %p #%d/%d t:%d i:%p s:%p..\n", pOMXAV, i, pOMXAV->vBufferNum, tex, image, sync); if(i<0||i>=pOMXAV->vBufferNum) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Buffer index out of range: %d\n", i); + JoglCommon_throwNewRuntimeException(0, "Buffer index out of range: %d\n", i); return; } @@ -1094,7 +1075,7 @@ void OMXToolBasicAV_SetStreamEGLImageTexture2D(OMXToolBasicAV_t * pOMXAV, KDint void OMXToolBasicAV_ActivateStream(OMXToolBasicAV_t * pOMXAV) { int res; if(NULL==pOMXAV) { - java_throwNewRuntimeException(0, "OMX instance null\n"); + JoglCommon_throwNewRuntimeException(0, "OMX instance null\n"); return; } DBG_PRINT( "ActivateStream 1\n"); @@ -1115,7 +1096,7 @@ void OMXToolBasicAV_ActivateStream(OMXToolBasicAV_t * pOMXAV) { // mandatory: before SetupTunnel (->Activate), wait until all devices are ready .. // arender/vrender must wait as well .. if(0!=(res=OMXToolBasicAV_WaitForState(pOMXAV, OMX_StateLoaded))) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Loaded Failed (%d)", res); + JoglCommon_throwNewRuntimeException(0, "Loaded Failed (%d)", res); kdThreadMutexUnlock(pOMXAV->mutex); return; } @@ -1161,7 +1142,7 @@ void OMXToolBasicAV_ActivateStream(OMXToolBasicAV_t * pOMXAV) { // if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateIdle, KD_TRUE))) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Wait for Idle Failed (%d)", res); + JoglCommon_throwNewRuntimeException(0, "Wait for Idle Failed (%d)", res); kdThreadMutexUnlock(pOMXAV->mutex); return; } @@ -1172,11 +1153,11 @@ void OMXToolBasicAV_ActivateStream(OMXToolBasicAV_t * pOMXAV) { void OMXToolBasicAV_DetachVideoRenderer(OMXToolBasicAV_t * pOMXAV) { if(NULL==pOMXAV) { - java_throwNewRuntimeException(0, "OMX instance null\n"); + JoglCommon_throwNewRuntimeException(0, "OMX instance null\n"); return; } if(pOMXAV->status<=OMXAV_INIT) { - java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + JoglCommon_throwNewRuntimeException(0, "OMX invalid status: %d <= INIT\n", pOMXAV->status); return; } kdThreadMutexLock(pOMXAV->mutex); @@ -1188,11 +1169,11 @@ void OMXToolBasicAV_DetachVideoRenderer(OMXToolBasicAV_t * pOMXAV) { void OMXToolBasicAV_AttachVideoRenderer(OMXToolBasicAV_t * pOMXAV) { if(NULL==pOMXAV) { - java_throwNewRuntimeException(0, "OMX instance null\n"); + JoglCommon_throwNewRuntimeException(0, "OMX instance null\n"); return; } if(pOMXAV->status<=OMXAV_INIT) { - java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + JoglCommon_throwNewRuntimeException(0, "OMX invalid status: %d <= INIT\n", pOMXAV->status); return; } kdThreadMutexLock(pOMXAV->mutex); @@ -1205,11 +1186,11 @@ void OMXToolBasicAV_AttachVideoRenderer(OMXToolBasicAV_t * pOMXAV) { void OMXToolBasicAV_SetPlaySpeed(OMXToolBasicAV_t * pOMXAV, KDfloat32 scale) { if(NULL==pOMXAV) { - java_throwNewRuntimeException(0, "OMX instance null\n"); + JoglCommon_throwNewRuntimeException(0, "OMX instance null\n"); return; } if(pOMXAV->status<=OMXAV_INIT) { - java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + JoglCommon_throwNewRuntimeException(0, "OMX invalid status: %d <= INIT\n", pOMXAV->status); return; } kdThreadMutexLock(pOMXAV->mutex); @@ -1226,11 +1207,11 @@ void OMXToolBasicAV_PlayStart(OMXToolBasicAV_t * pOMXAV) { int res; if(NULL==pOMXAV) { - java_throwNewRuntimeException(0, "OMX instance null\n"); + JoglCommon_throwNewRuntimeException(0, "OMX instance null\n"); return; } if(pOMXAV->status<=OMXAV_INIT) { - java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + JoglCommon_throwNewRuntimeException(0, "OMX invalid status: %d <= INIT\n", pOMXAV->status); return; } if(pOMXAV->status==OMXAV_PLAYING) { @@ -1244,14 +1225,14 @@ void OMXToolBasicAV_PlayStart(OMXToolBasicAV_t * pOMXAV) DBG_PRINT( "Play 3.1\n"); if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateExecuting, KD_TRUE))) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Play Execute Failed (%d)", res); + JoglCommon_throwNewRuntimeException(0, "Play Execute Failed (%d)", res); kdThreadMutexUnlock(pOMXAV->mutex); return; } if(pOMXAV->status==OMXAV_STOPPED || pOMXAV->status==OMXAV_FIN) { DBG_PRINT( "Play 3.2\n"); if(StartClock(pOMXAV, KD_TRUE, 0.0)) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Play StartClock Failed"); + JoglCommon_throwNewRuntimeException(0, "Play StartClock Failed"); kdThreadMutexUnlock(pOMXAV->mutex); return; } @@ -1275,13 +1256,13 @@ static int PlayStop(OMXToolBasicAV_t * pOMXAV) if(OMXToolBasicAV_CheckState(pOMXAV, OMX_StateLoaded)) { if(StartClock(pOMXAV, KD_FALSE, 0.0)) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Stop StopClock Failed"); + JoglCommon_throwNewRuntimeException(0, "Stop StopClock Failed"); kdThreadMutexUnlock(pOMXAV->mutex); return -1; } if(OMXToolBasicAV_CheckState(pOMXAV, OMX_StateIdle)) { if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateIdle, KD_TRUE))) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Stop Idle Failed (%d)", res); + JoglCommon_throwNewRuntimeException(0, "Stop Idle Failed (%d)", res); kdThreadMutexUnlock(pOMXAV->mutex); return res; } @@ -1294,11 +1275,11 @@ static int PlayStop(OMXToolBasicAV_t * pOMXAV) void OMXToolBasicAV_PlayStop(OMXToolBasicAV_t * pOMXAV) { if(NULL==pOMXAV) { - java_throwNewRuntimeException(0, "OMX instance null\n"); + JoglCommon_throwNewRuntimeException(0, "OMX instance null\n"); return; } if(pOMXAV->status<=OMXAV_INIT) { - java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + JoglCommon_throwNewRuntimeException(0, "OMX invalid status: %d <= INIT\n", pOMXAV->status); return; } kdThreadMutexLock(pOMXAV->mutex); @@ -1312,11 +1293,11 @@ void OMXToolBasicAV_PlayPause(OMXToolBasicAV_t * pOMXAV) { int res; if(NULL==pOMXAV) { - java_throwNewRuntimeException(0, "OMX instance null\n"); + JoglCommon_throwNewRuntimeException(0, "OMX instance null\n"); return; } if(pOMXAV->status<=OMXAV_INIT) { - java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + JoglCommon_throwNewRuntimeException(0, "OMX invalid status: %d <= INIT\n", pOMXAV->status); return; } if(pOMXAV->status==OMXAV_PAUSED || pOMXAV->status!=OMXAV_PLAYING) { @@ -1339,11 +1320,11 @@ void OMXToolBasicAV_PlaySeek(OMXToolBasicAV_t * pOMXAV, KDint64 time) int res; if(NULL==pOMXAV) { - java_throwNewRuntimeException(0, "OMX instance null\n"); + JoglCommon_throwNewRuntimeException(0, "OMX instance null\n"); return; } if(pOMXAV->status<=OMXAV_INIT) { - java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + JoglCommon_throwNewRuntimeException(0, "OMX invalid status: %d <= INIT\n", pOMXAV->status); return; } kdThreadMutexLock(pOMXAV->mutex); @@ -1359,7 +1340,7 @@ void OMXToolBasicAV_PlaySeek(OMXToolBasicAV_t * pOMXAV, KDint64 time) // state transition to OMX_StatePause. if(pOMXAV->status!=OMXAV_PAUSED) { if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StatePause, KD_TRUE))) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Seek Pause Failed (%d)", res); + JoglCommon_throwNewRuntimeException(0, "Seek Pause Failed (%d)", res); kdThreadMutexUnlock(pOMXAV->mutex); return; } @@ -1369,7 +1350,7 @@ void OMXToolBasicAV_PlaySeek(OMXToolBasicAV_t * pOMXAV, KDint64 time) // on OMX_TIME_CONFIG_CLOCKSTATETYPE requesting a transition to // OMX_TIME_ClockStateStopped. if(StartClock(pOMXAV, KD_FALSE, 0.0)) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Seek StopClock Failed"); + JoglCommon_throwNewRuntimeException(0, "Seek StopClock Failed"); kdThreadMutexUnlock(pOMXAV->mutex); return; } @@ -1377,14 +1358,14 @@ void OMXToolBasicAV_PlaySeek(OMXToolBasicAV_t * pOMXAV, KDint64 time) // 3. Seek to the desired location through the use of OMX_SetConfig on // OMX_IndexConfigTimePosition requesting the desired timestamp. if(SetMediaPosition(pOMXAV, time)) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Seek position Failed"); + JoglCommon_throwNewRuntimeException(0, "Seek position Failed"); kdThreadMutexUnlock(pOMXAV->mutex); return; } // 4. Flush all components. if(SendCommand(pOMXAV, OMX_CommandFlush, OMX_ALL, 0)) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Seek Flush Failed"); + JoglCommon_throwNewRuntimeException(0, "Seek Flush Failed"); kdThreadMutexUnlock(pOMXAV->mutex); return; } @@ -1394,7 +1375,7 @@ void OMXToolBasicAV_PlaySeek(OMXToolBasicAV_t * pOMXAV, KDint64 time) // OMX_TIME_ClockStateRunning or // OMX_TIME_ClockStateWaitingForStartTime. if(StartClock(pOMXAV, KD_TRUE, time)) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Seek StartClock Failed"); + JoglCommon_throwNewRuntimeException(0, "Seek StartClock Failed"); kdThreadMutexUnlock(pOMXAV->mutex); return; } @@ -1403,7 +1384,7 @@ void OMXToolBasicAV_PlaySeek(OMXToolBasicAV_t * pOMXAV, KDint64 time) // state transition to OMX_StateExecuting. if(pOMXAV->status==OMXAV_PLAYING) { if(0!=(res=OMXToolBasicAV_RequestState(pOMXAV, OMX_StateExecuting, KD_TRUE))) { - java_throwNewRuntimeException(pOMXAV->jni_env, "Seek Execute Failed (%d)", res); + JoglCommon_throwNewRuntimeException(0, "Seek Execute Failed (%d)", res); kdThreadMutexUnlock(pOMXAV->mutex); return; } @@ -1478,11 +1459,11 @@ GLuint OMXToolBasicAV_GetNextTextureID(OMXToolBasicAV_t * pOMXAV, int blocking) KDint64 OMXToolBasicAV_GetCurrentPosition(OMXToolBasicAV_t * pOMXAV) { KDint64 res = 0L; if(NULL==pOMXAV) { - java_throwNewRuntimeException(0, "OMX instance null\n"); + JoglCommon_throwNewRuntimeException(0, "OMX instance null\n"); return res; } if(pOMXAV->status<=OMXAV_INIT) { - java_throwNewRuntimeException(pOMXAV->jni_env, "OMX invalid status: %d <= INIT\n", pOMXAV->status); + JoglCommon_throwNewRuntimeException(0, "OMX invalid status: %d <= INIT\n", pOMXAV->status); return res; } kdThreadMutexLock(pOMXAV->mutex); diff --git a/src/jogl/native/openmax/omx_tool.h b/src/jogl/native/openmax/omx_tool.h index 1ade60e4f..414befca0 100644 --- a/src/jogl/native/openmax/omx_tool.h +++ b/src/jogl/native/openmax/omx_tool.h @@ -73,16 +73,16 @@ typedef struct { OMX_HANDLETYPE endComponent; OMX_CALLBACKTYPE callbacks; - KDchar audioCodec[256]; - KDchar audioCodecComponent[256]; - KDchar videoCodec[256]; - KDchar videoCodecComponent[256]; + KDchar audioCodec[64]; + KDchar audioCodecComponent[64]; + KDchar videoCodec[64]; + KDchar videoCodecComponent[64]; int audioPort; int videoPort; KDuint32 width; KDuint32 height; KDuint32 bitrate; // per seconds - KDuint32 framerate; // per seconds + KDfloat32 framerate; // per seconds KDfloat32 length; // seconds KDfloat32 speed; // current clock scale KDfloat32 play_speed; // current play clock scale @@ -99,17 +99,7 @@ typedef struct { int status; - intptr_t jni_env; intptr_t jni_instance; - intptr_t jni_mid_saveAttributes; - intptr_t jni_mid_attributesUpdated; - intptr_t jni_fid_width; - intptr_t jni_fid_height; - intptr_t jni_fid_fps; - intptr_t jni_fid_bps; - intptr_t jni_fid_totalFrames; - intptr_t jni_fid_acodec; - intptr_t jni_fid_vcodec; } OMXToolBasicAV_t ; // diff --git a/src/newt/native/NewtCommon.h b/src/newt/native/NewtCommon.h index 33aba64ae..f5ca73b74 100644 --- a/src/newt/native/NewtCommon.h +++ b/src/newt/native/NewtCommon.h @@ -39,6 +39,42 @@ jchar* NewtCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str); void NewtCommon_FatalError(JNIEnv *env, const char* msg, ...); void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); +/** + * + * 1) Store jvmHandle and jvmVersion + + JavaVM *jvmHandle = NULL; + int jvmVersion = 0; + + if(0 != (*env)->GetJavaVM(env, &jvmHandle)) { + jvmHandle = NULL; + } else { + jvmVersion = (*env)->GetVersion(env); + } + + * + * 2) Use current thread JNIEnv or attach current thread to JVM, generating new JNIEnv + * + + int shallBeDetached = 0; + JNIEnv* env = NewtCommon_GetJNIEnv(jvmHandle, jvmVersion, &shallBeDetached); + if(NULL==env) { + DBG_PRINT("drawRect: null JNIEnv\n"); + return; + } + + * + * 3) Use JNIEnv .. + * + .. your JNIEnv code here .. + + * + * 4) Detach thread from JVM, if required + * + if (shallBeDetached) { + (*jvmHandle)->DetachCurrentThread(jvmHandle); + } + */ JNIEnv* NewtCommon_GetJNIEnv (JavaVM * jvmHandle, int jvmVersion, int * shallBeDetached); #endif diff --git a/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java b/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java index 4b84525f6..59e78936d 100644 --- a/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java +++ b/src/test/com/jogamp/opengl/test/android/MovieCubeActivity0.java @@ -46,19 +46,25 @@ import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieCube; import com.jogamp.opengl.util.Animator; +import android.content.Context; import android.os.Bundle; import android.util.Log; +import android.view.inputmethod.InputMethodManager; public class MovieCubeActivity0 extends NewtBaseActivity { static String TAG = "MovieCubeActivity0"; - MouseAdapter toFrontMouseListener = new MouseAdapter() { - public void mouseClicked(MouseEvent e) { - Object src = e.getSource(); - if(src instanceof AndroidWindow) { - ((AndroidWindow)src).requestFocus(false); + MouseAdapter showKeyboardMouseListener = new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if(e.getPressure()>2f) { + final AndroidWindow win = (AndroidWindow)e.getSource(); + InputMethodManager mgr = (InputMethodManager) win.getAndroidView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + mgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); // shows keyboard .. + win.getAndroidView().requestFocus(); } - } }; + } + }; @Override public void onCreate(Bundle savedInstanceState) { @@ -89,6 +95,7 @@ public class MovieCubeActivity0 extends NewtBaseActivity { final GLWindow glWindowMain = GLWindow.create(scrn, capsMain); glWindowMain.setFullscreen(true); setContentView(getWindow(), glWindowMain); + glWindowMain.addMouseListener(showKeyboardMouseListener); glWindowMain.addGLEventListener(demoMain); animator.add(glWindowMain); glWindowMain.setVisible(true); diff --git a/src/test/com/jogamp/opengl/test/android/MovieCubeActivityLauncher0.java b/src/test/com/jogamp/opengl/test/android/MovieCubeActivityLauncher0.java index 0332906b7..4f24fc9b8 100644 --- a/src/test/com/jogamp/opengl/test/android/MovieCubeActivityLauncher0.java +++ b/src/test/com/jogamp/opengl/test/android/MovieCubeActivityLauncher0.java @@ -57,14 +57,14 @@ public class MovieCubeActivityLauncher0 extends LauncherUtil.BaseActivityLaunche props.setProperty("jogl.debug.GLDrawable", "true"); props.setProperty("jogl.debug.GLContext", "true"); props.setProperty("jogl.debug.GLSLCode", "true"); - props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); // props.setProperty("jogl.debug.GLSLState", "true"); // props.setProperty("jogl.debug.DebugGL", "true"); // props.setProperty("jogl.debug.TraceGL", "true"); // props.setProperty("newt.debug", "all"); - props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window", "true"); // props.setProperty("newt.debug.Window.MouseEvent", "true"); - // props.setProperty("newt.debug.Window.KeyEvent", "true"); + // props.setProperty("newt.debug.Window.KeyEvent", "true"); props.setProperty("jogamp.debug.IOUtil", "true"); } diff --git a/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher00a.java b/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher00a.java index 3ad462691..fbb0223f8 100644 --- a/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher00a.java +++ b/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher00a.java @@ -60,12 +60,12 @@ public class MovieSimpleActivityLauncher00a extends LauncherUtil.BaseActivityLau props.setProperty("jogl.debug.GLDrawable", "true"); props.setProperty("jogl.debug.GLContext", "true"); props.setProperty("jogl.debug.GLSLCode", "true"); - props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); // props.setProperty("jogl.debug.GLSLState", "true"); // props.setProperty("jogl.debug.DebugGL", "true"); // props.setProperty("jogl.debug.TraceGL", "true"); // props.setProperty("newt.debug", "all"); - props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window", "true"); // props.setProperty("newt.debug.Window.MouseEvent", "true"); // props.setProperty("newt.debug.Window.KeyEvent", "true"); props.setProperty("jogamp.debug.IOUtil", "true"); diff --git a/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher00b.java b/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher00b.java index e3c87bd7a..8c08e987f 100644 --- a/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher00b.java +++ b/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher00b.java @@ -60,12 +60,12 @@ public class MovieSimpleActivityLauncher00b extends LauncherUtil.BaseActivityLau props.setProperty("jogl.debug.GLDrawable", "true"); props.setProperty("jogl.debug.GLContext", "true"); props.setProperty("jogl.debug.GLSLCode", "true"); - props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); // props.setProperty("jogl.debug.GLSLState", "true"); // props.setProperty("jogl.debug.DebugGL", "true"); // props.setProperty("jogl.debug.TraceGL", "true"); // props.setProperty("newt.debug", "all"); - props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window", "true"); // props.setProperty("newt.debug.Window.MouseEvent", "true"); // props.setProperty("newt.debug.Window.KeyEvent", "true"); props.setProperty("jogamp.debug.IOUtil", "true"); diff --git a/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher01a.java b/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher01a.java index 5fcb9d584..b2a3facbd 100644 --- a/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher01a.java +++ b/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher01a.java @@ -60,12 +60,12 @@ public class MovieSimpleActivityLauncher01a extends LauncherUtil.BaseActivityLau props.setProperty("jogl.debug.GLDrawable", "true"); props.setProperty("jogl.debug.GLContext", "true"); props.setProperty("jogl.debug.GLSLCode", "true"); - props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); // props.setProperty("jogl.debug.GLSLState", "true"); // props.setProperty("jogl.debug.DebugGL", "true"); // props.setProperty("jogl.debug.TraceGL", "true"); // props.setProperty("newt.debug", "all"); - props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window", "true"); // props.setProperty("newt.debug.Window.MouseEvent", "true"); // props.setProperty("newt.debug.Window.KeyEvent", "true"); props.setProperty("jogamp.debug.IOUtil", "true"); diff --git a/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher01b.java b/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher01b.java index 2801acf48..905e2628d 100644 --- a/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher01b.java +++ b/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher01b.java @@ -60,12 +60,12 @@ public class MovieSimpleActivityLauncher01b extends LauncherUtil.BaseActivityLau props.setProperty("jogl.debug.GLDrawable", "true"); props.setProperty("jogl.debug.GLContext", "true"); props.setProperty("jogl.debug.GLSLCode", "true"); - props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); // props.setProperty("jogl.debug.GLSLState", "true"); // props.setProperty("jogl.debug.DebugGL", "true"); // props.setProperty("jogl.debug.TraceGL", "true"); // props.setProperty("newt.debug", "all"); - props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window", "true"); // props.setProperty("newt.debug.Window.MouseEvent", "true"); // props.setProperty("newt.debug.Window.KeyEvent", "true"); props.setProperty("jogamp.debug.IOUtil", "true"); diff --git a/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher02.java b/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher02.java index f862b5ee9..369457946 100644 --- a/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher02.java +++ b/src/test/com/jogamp/opengl/test/android/MovieSimpleActivityLauncher02.java @@ -60,12 +60,12 @@ public class MovieSimpleActivityLauncher02 extends LauncherUtil.BaseActivityLaun props.setProperty("jogl.debug.GLDrawable", "true"); props.setProperty("jogl.debug.GLContext", "true"); props.setProperty("jogl.debug.GLSLCode", "true"); - props.setProperty("jogl.debug.CapabilitiesChooser", "true"); + // props.setProperty("jogl.debug.CapabilitiesChooser", "true"); // props.setProperty("jogl.debug.GLSLState", "true"); // props.setProperty("jogl.debug.DebugGL", "true"); // props.setProperty("jogl.debug.TraceGL", "true"); // props.setProperty("newt.debug", "all"); - props.setProperty("newt.debug.Window", "true"); + // props.setProperty("newt.debug.Window", "true"); // props.setProperty("newt.debug.Window.MouseEvent", "true"); // props.setProperty("newt.debug.Window.KeyEvent", "true"); props.setProperty("jogamp.debug.IOUtil", "true"); diff --git a/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2ActivityLauncher.java b/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2ActivityLauncher.java index b6265b72b..96299e873 100644 --- a/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2ActivityLauncher.java +++ b/src/test/com/jogamp/opengl/test/android/NEWTRedSquareES2ActivityLauncher.java @@ -12,7 +12,7 @@ public class NEWTRedSquareES2ActivityLauncher extends Activity { super.onCreate(savedInstanceState); final Uri uri = Uri.parse("launch://jogamp.org/com.jogamp.opengl.test.android.NEWTRedSquareES2Activity?pkg=com.jogamp.opengl.test"); - final Intent intent = new Intent("org.jogamp.launcher.action.LAUNCH_ACTIVITY_NORMAL", uri); + final Intent intent = new Intent("org.jogamp.launcher.action.LAUNCH_ACTIVITY_NORMAL", uri); Log.d(getClass().getSimpleName(), "Launching Activity: "+intent); startActivity (intent); diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/TestTextureSequence.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/TestTextureSequence.java index 5e607feb3..6dfb11855 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/TestTextureSequence.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/TestTextureSequence.java @@ -19,8 +19,10 @@ public class TestTextureSequence implements TextureSequence { int textureUnit = 0; protected int[] texMinMagFilter = { GL.GL_NEAREST, GL.GL_NEAREST }; protected int[] texWrapST = { GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE }; - - public TestTextureSequence() { + final boolean useBuildInTexLookup; + + public TestTextureSequence(boolean useBuildInTexLookup) { + this.useBuildInTexLookup = useBuildInTexLookup; } public void initGLResources(GL gl) throws GLException { @@ -57,11 +59,6 @@ public class TestTextureSequence implements TextureSequence { } @Override - public int getTextureTarget() { - return frame.getTexture().getTarget(); - } - - @Override public int getTextureUnit() { return textureUnit; } @@ -77,13 +74,47 @@ public class TestTextureSequence implements TextureSequence { } @Override - public TextureSequence.TextureFrame getLastTexture() { + public TextureSequence.TextureFrame getLastTexture() throws IllegalStateException { return frame; // may return null } @Override - public TextureSequence.TextureFrame getNextTexture(GL gl, boolean blocking) { + public TextureSequence.TextureFrame getNextTexture(GL gl, boolean blocking) throws IllegalStateException { return frame; } + @Override + public String getRequiredExtensionsShaderStub() throws IllegalStateException { + return "// TextTextureSequence: No extensions required\n"; + } + + @Override + public String getTextureSampler2DType() throws IllegalStateException { + return "sampler2D" ; + } + + private String textureLookupFunctionName = "myTexture2D"; + + @Override + public String getTextureLookupFunctionName(String desiredFuncName) throws IllegalStateException { + if(useBuildInTexLookup) { + return "texture2D"; + } + if(null != desiredFuncName && desiredFuncName.length()>0) { + textureLookupFunctionName = desiredFuncName; + } + return textureLookupFunctionName; + } + + @Override + public String getTextureLookupFragmentShaderImpl() throws IllegalStateException { + if(useBuildInTexLookup) { + return ""; + } + return + "\n"+ + "vec4 "+textureLookupFunctionName+"(in "+getTextureSampler2DType()+" image, in vec2 texCoord) {\n"+ + " return texture2D(image, texCoord);\n"+ + "}\n\n"; + } } diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TexCubeES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TexCubeES2.java index f330dde0d..e85468bcb 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TexCubeES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/TexCubeES2.java @@ -1,3 +1,30 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ package com.jogamp.opengl.test.junit.jogl.demos.es2; import java.nio.ByteBuffer; @@ -23,6 +50,7 @@ import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.opengl.GLWindow; import com.jogamp.opengl.JoglVersion; import com.jogamp.opengl.test.junit.jogl.demos.TestTextureSequence; +import com.jogamp.opengl.test.junit.util.MiscUtils; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.util.GLArrayDataServer; import com.jogamp.opengl.util.PMVMatrix; @@ -30,18 +58,19 @@ import com.jogamp.opengl.util.glsl.ShaderCode; import com.jogamp.opengl.util.glsl.ShaderProgram; import com.jogamp.opengl.util.glsl.ShaderState; import com.jogamp.opengl.util.texture.Texture; +import com.jogamp.opengl.util.texture.TextureCoords; import com.jogamp.opengl.util.texture.TextureSequence; public class TexCubeES2 implements GLEventListener { public TexCubeES2 (TextureSequence texSource, boolean innerCube, float zoom0, float rotx, float roty) { - this.texSource = texSource; + this.texSeq = texSource; this.innerCube = innerCube; this.zoom0 = zoom0; this.view_rotx = rotx; this.view_roty = roty; } - private TextureSequence texSource; + private TextureSequence texSeq; private ShaderState st; private PMVMatrix pmvMatrix; private GLUniformData pmvMatrixUniform; @@ -117,17 +146,40 @@ public class TexCubeES2 implements GLEventListener { } }; + static final String[] es2_prelude = { "#version 100\n", "precision mediump float;\n" }; + static final String gl2_prelude = "#version 110\n"; + static final String shaderBasename = "texsequence_xxx"; + static final String myTextureLookupName = "myTexture2D"; - private void initShader(GL2ES2 gl, boolean useExternalTexture) { + private void initShader(GL2ES2 gl) { // Create & Compile the shader objects - final String vShaderBasename = gl.isGLES2() ? "texsimple_es2" : "texsimple_gl2" ; - final String fShaderBasename = gl.isGLES2() ? ( useExternalTexture ? "texsimple_es2_exttex" : "texsimple_es2" ) : "texsimple_gl2"; + ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, TexCubeES2.class, + "shader", "shader/bin", shaderBasename, true); + ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, TexCubeES2.class, + "shader", "shader/bin", shaderBasename, true); + + // Prelude shader code w/ GLSL profile specifics [ 1. pre-proc, 2. other ] + int rsFpPos; + if(gl.isGLES2()) { + rsVp.insertShaderSource(0, 0, es2_prelude[0]); + rsFpPos = rsFp.insertShaderSource(0, 0, es2_prelude[0]); + } else { + rsVp.insertShaderSource(0, 0, gl2_prelude); + rsFpPos = rsFp.insertShaderSource(0, 0, gl2_prelude); + } + rsFpPos = rsFp.insertShaderSource(0, rsFpPos, texSeq.getRequiredExtensionsShaderStub()); + if(gl.isGLES2()) { + rsFpPos = rsFp.insertShaderSource(0, rsFpPos, es2_prelude[1]); + } + final String texLookupFuncName = texSeq.getTextureLookupFunctionName(myTextureLookupName); + rsFp.replaceInShaderSource(myTextureLookupName, texLookupFuncName); + + // Inject TextureSequence shader details + final StringBuilder sFpIns = new StringBuilder(); + sFpIns.append("uniform ").append(texSeq.getTextureSampler2DType()).append(" mgl_ActiveTexture;\n"); + sFpIns.append(texSeq.getTextureLookupFragmentShaderImpl()); + rsFp.insertShaderSource(0, "TEXTURE-SEQUENCE-CODE-BEGIN", 0, sFpIns); - ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, TexCubeES2.class, - "shader", "shader/bin", vShaderBasename); - ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, TexCubeES2.class, - "shader", "shader/bin", fShaderBasename); - // Create & Link the shader program ShaderProgram sp = new ShaderProgram(); sp.add(rsVp); @@ -146,13 +198,14 @@ public class TexCubeES2 implements GLEventListener { public void init(GLAutoDrawable drawable) { GL2ES2 gl = drawable.getGL().getGL2ES2(); System.err.println(JoglVersion.getGLInfo(gl, null)); + final Texture tex= texSeq.getLastTexture().getTexture(); - final boolean useExternalTexture = GLES2.GL_TEXTURE_EXTERNAL_OES == texSource.getTextureTarget(); + final boolean useExternalTexture = GLES2.GL_TEXTURE_EXTERNAL_OES == tex.getTarget(); if(useExternalTexture && !gl.isExtensionAvailable("GL_OES_EGL_image_external")) { throw new GLException("GL_OES_EGL_image_external requested but not available"); } - initShader(gl, useExternalTexture); + initShader(gl); // Push the 1st uniform down the path st.useProgram(gl, true); @@ -163,26 +216,31 @@ public class TexCubeES2 implements GLEventListener { if(!st.uniform(gl, pmvMatrixUniform)) { throw new GLException("Error setting PMVMatrix in shader: "+st); } - if(!st.uniform(gl, new GLUniformData("mgl_ActiveTexture", texSource.getTextureUnit()))) { + if(!st.uniform(gl, new GLUniformData("mgl_ActiveTexture", texSeq.getTextureUnit()))) { throw new GLException("Error setting mgl_ActiveTexture in shader: "+st); } { - final Texture tex= texSource.getLastTexture().getTexture(); final float aspect = tex.getAspectRatio(); + final TextureCoords tc = tex.getImageTexCoords(); System.err.println("XXX0: aspect: "+aspect); System.err.println("XXX0: y-flip: "+tex.getMustFlipVertically()); - System.err.println("XXX0: "+tex.getImageTexCoords()); + System.err.println("XXX0: "+tc); + final float tc_x1 = Math.max(tc.left(), tc.right()); + final float tc_y1 = Math.max(tc.bottom(), tc.top()); final float ss=1f, ts=aspect; // scale tex-coord final float dy = ( 1f - aspect ) / 2f ; for(int i=0; i<s_cubeTexCoords.length; i+=2) { - s_cubeTexCoords[i+0] *= ss; - final float t = s_cubeTexCoords[i+1]; - if(t==0 && !tex.getMustFlipVertically() || t!=0 && tex.getMustFlipVertically()) { - s_cubeTexCoords[i+1] = 0f + dy; + final float tx = s_cubeTexCoords[i+0]; + final float ty = s_cubeTexCoords[i+1]; + if(tx!=0) { + s_cubeTexCoords[i+0] = tc_x1 * ss; + } + if(ty==0 && !tex.getMustFlipVertically() || ty!=0 && tex.getMustFlipVertically()) { + s_cubeTexCoords[i+1] = 0f + dy; } else { - s_cubeTexCoords[i+1] = 1f * ts + dy; + s_cubeTexCoords[i+1] = tc_y1 * ts + dy; } } } @@ -274,7 +332,7 @@ public class TexCubeES2 implements GLEventListener { public void dispose(GLAutoDrawable drawable) { GL2ES2 gl = drawable.getGL().getGL2ES2(); - texSource = null; + texSeq = null; pmvMatrixUniform = null; pmvMatrix.destroy(); pmvMatrix=null; @@ -298,11 +356,11 @@ public class TexCubeES2 implements GLEventListener { st.uniform(gl, pmvMatrixUniform); interleavedVBO.enableBuffer(gl, true); Texture tex = null; - if(null!=texSource) { - final TextureSequence.TextureFrame texFrame = texSource.getNextTexture(gl, true); + if(null!=texSeq) { + final TextureSequence.TextureFrame texFrame = texSeq.getNextTexture(gl, true); if(null != texFrame) { tex = texFrame.getTexture(); - gl.glActiveTexture(GL.GL_TEXTURE0+texSource.getTextureUnit()); + gl.glActiveTexture(GL.GL_TEXTURE0+texSeq.getTextureUnit()); tex.enable(gl); tex.bind(gl); } @@ -401,14 +459,27 @@ public class TexCubeES2 implements GLEventListener { public static void main(String[] args) { int width = 510; int height = 300; + boolean useBuildInTexLookup = false; System.err.println("TexCubeES2.run()"); + for(int i=0; i<args.length; i++) { + if(args[i].equals("-width")) { + i++; + width = MiscUtils.atoi(args[i], width); + } else if(args[i].equals("-height")) { + i++; + height = MiscUtils.atoi(args[i], height); + } else if(args[i].equals("-shaderBuildIn")) { + useBuildInTexLookup = true; + } + } + final GLWindow window = GLWindow.create(new GLCapabilities(GLProfile.getGL2ES2())); // Size OpenGL to Video Surface window.setSize(width, height); window.setFullscreen(false); window.setSize(width, height); - final TestTextureSequence texSource = new TestTextureSequence(); + final TestTextureSequence texSource = new TestTextureSequence(useBuildInTexLookup); window.addGLEventListener(new GLEventListener() { @Override public void init(GLAutoDrawable drawable) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java index 343c4b2a6..9ecb15018 100755 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java @@ -45,6 +45,10 @@ import javax.media.opengl.GLEventListener; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.KeyAdapter; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.event.WindowEvent; import com.jogamp.newt.opengl.GLWindow; @@ -61,15 +65,55 @@ public class MovieCube implements GLEventListener, GLMediaEventListener { boolean quit = false; TexCubeES2 cube=null; GLMediaPlayer mPlayer=null; - URLConnection stream = null; + URLConnection stream = null; public MovieCube(URLConnection stream, float zoom0, float rotx, float roty) throws IOException { this.stream = stream; mPlayer = GLMediaPlayerFactory.create(); mPlayer.addEventListener(this); - cube = new TexCubeES2(mPlayer, false, zoom0, rotx, roty); + cube = new TexCubeES2(mPlayer, false, zoom0, rotx, roty); } + private final KeyListener keyAction = new KeyAdapter() { + public void keyTyped(KeyEvent e) { + System.err.println("MC "+e); + int pts0 = mPlayer.getCurrentPosition(); + int pts1 = 0; + switch(e.getKeyCode()) { + case KeyEvent.VK_3: + case KeyEvent.VK_RIGHT: pts1 = pts0 + 1000; break; + case KeyEvent.VK_4: + case KeyEvent.VK_UP: pts1 = pts0 + 10000; break; + case KeyEvent.VK_2: + case KeyEvent.VK_LEFT: pts1 = pts0 - 1000; break; + case KeyEvent.VK_1: + case KeyEvent.VK_DOWN: pts1 = pts0 - 10000; break; + case KeyEvent.VK_ESCAPE: + case KeyEvent.VK_DELETE: + case KeyEvent.VK_BACK_SPACE: { + mPlayer.seek(0); + mPlayer.setPlaySpeed(1.0f); + mPlayer.start(); + break; + } + case KeyEvent.VK_SPACE: { + if(GLMediaPlayer.State.Paused == mPlayer.getState()) { + mPlayer.start(); + } else { + mPlayer.pause(); + } + break; + } + case KeyEvent.VK_S: mPlayer.setPlaySpeed(mPlayer.getPlaySpeed()/2.0f); break; + case KeyEvent.VK_F: mPlayer.setPlaySpeed(mPlayer.getPlaySpeed()*2.0f); break; + } + + if( 0 != pts1 ) { + mPlayer.seek(pts1); + } + } + }; + @Override public void attributesChanges(GLMediaPlayer mp, int event_mask, long when) { System.out.println("attributesChanges: "+mp+", 0x"+Integer.toHexString(event_mask)+", when "+when); @@ -99,6 +143,14 @@ public class MovieCube implements GLEventListener, GLMediaEventListener { cube.init(drawable); mPlayer.start(); + + boolean added; + if (drawable instanceof Window) { + Window window = (Window) drawable; + window.addKeyListener(keyAction); + added = true; + } else { added = false; } + System.err.println("MC.init: kl-added "+added+", "+drawable.getClass().getName()); } public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { 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 index fa2870437..8210065ab 100755 --- 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 @@ -129,7 +129,7 @@ public class MovieSimple implements GLEventListener, GLMediaEventListener { if(y>winHeight/2) { final float dp = (float)(x-prevMouseX)/(float)winWidth; - mPlayer.seek(mPlayer.getCurrentPosition() + (long) (mPlayer.getDuration() * dp)); + mPlayer.seek(mPlayer.getCurrentPosition() + (int) (mPlayer.getDuration() * dp)); } else { mPlayer.start(); rotate = 1; @@ -198,16 +198,39 @@ public class MovieSimple implements GLEventListener, GLMediaEventListener { ShaderState st; PMVMatrix pmvMatrix; GLUniformData pmvMatrixUniform; + static final String[] es2_prelude = { "#version 100\n", "precision mediump float;\n" }; + static final String gl2_prelude = "#version 110\n"; + static final String shaderBasename = "texsequence_xxx"; + static final String myTextureLookupName = "myTexture2D"; - private void initShader(GL2ES2 gl, boolean useExternalTexture) { + private void initShader(GL2ES2 gl) { // Create & Compile the shader objects - final String vShaderBasename = gl.isGLES2() ? "texsimple_es2" : "texsimple_gl2" ; - final String fShaderBasename = gl.isGLES2() ? ( useExternalTexture ? "texsimple_es2_exttex" : "texsimple_es2" ) : "texsimple_gl2"; + ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, MovieSimple.class, + "../shader", "../shader/bin", shaderBasename, true); + ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, MovieSimple.class, + "../shader", "../shader/bin", shaderBasename, true); + + // Prelude shader code w/ GLSL profile specifics [ 1. pre-proc, 2. other ] + int rsFpPos; + if(gl.isGLES2()) { + rsVp.insertShaderSource(0, 0, es2_prelude[0]); + rsFpPos = rsFp.insertShaderSource(0, 0, es2_prelude[0]); + } else { + rsVp.insertShaderSource(0, 0, gl2_prelude); + rsFpPos = rsFp.insertShaderSource(0, 0, gl2_prelude); + } + rsFpPos = rsFp.insertShaderSource(0, rsFpPos, mPlayer.getRequiredExtensionsShaderStub()); + if(gl.isGLES2()) { + rsFpPos = rsFp.insertShaderSource(0, rsFpPos, es2_prelude[1]); + } + final String texLookupFuncName = mPlayer.getTextureLookupFunctionName(myTextureLookupName); + rsFp.replaceInShaderSource(myTextureLookupName, texLookupFuncName); - ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, MovieSimple.class, - "../shader", "../shader/bin", vShaderBasename); - ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, MovieSimple.class, - "../shader", "../shader/bin", fShaderBasename); + // Inject TextureSequence shader details + final StringBuilder sFpIns = new StringBuilder(); + sFpIns.append("uniform ").append(mPlayer.getTextureSampler2DType()).append(" mgl_ActiveTexture;\n"); + sFpIns.append(mPlayer.getTextureLookupFragmentShaderImpl()); + rsFp.insertShaderSource(0, "TEXTURE-SEQUENCE-CODE-BEGIN", 0, sFpIns); // Create & Link the shader program ShaderProgram sp = new ShaderProgram(); @@ -232,14 +255,16 @@ public class MovieSimple implements GLEventListener, GLMediaEventListener { System.err.println("Alpha: "+alpha+", opaque "+drawable.getChosenGLCapabilities().isBackgroundOpaque()+ ", "+drawable.getClass().getName()+", "+drawable); + final Texture tex; boolean useExternalTexture = false; try { System.out.println("p0 "+mPlayer+", shared "+mPlayerShared); if(!mPlayerShared) { mPlayer.initGLStream(gl, stream); } + tex = mPlayer.getLastTexture().getTexture(); System.out.println("p1 "+mPlayer+", shared "+mPlayerShared); - useExternalTexture = GLES2.GL_TEXTURE_EXTERNAL_OES == mPlayer.getTextureTarget(); + useExternalTexture = GLES2.GL_TEXTURE_EXTERNAL_OES == tex.getTarget(); if(useExternalTexture && !gl.isExtensionAvailable("GL_OES_EGL_image_external")) { throw new GLException("GL_OES_EGL_image_external requested but not available"); } @@ -254,7 +279,7 @@ public class MovieSimple implements GLEventListener, GLMediaEventListener { throw new GLException(glex); } - initShader(gl, useExternalTexture); + initShader(gl); // Push the 1st uniform down the path st.useProgram(gl, true); @@ -313,7 +338,6 @@ public class MovieSimple implements GLEventListener, GLMediaEventListener { interleavedVBO.addGLSLSubArray("mgl_MultiTexCoord", 2, GL.GL_ARRAY_BUFFER); final FloatBuffer ib = (FloatBuffer)interleavedVBO.getBuffer(); - final Texture tex= mPlayer.getLastTexture().getTexture(); final TextureCoords tc = tex.getImageTexCoords(); final float aspect = tex.getAspectRatio(); System.err.println("XXX0: tex aspect: "+aspect); |