From 35beeabffed61e1597aaffc0c5926ab5ef86d32e Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Mon, 16 Apr 2012 21:18:03 +0200 Subject: 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 :) --- .../com/jogamp/opengl/util/av/GLMediaPlayer.java | 44 ++++-- .../opengl/util/texture/TextureSequence.java | 153 +++++++++++++++++++-- 2 files changed, 178 insertions(+), 19 deletions(-) (limited to 'src/jogl/classes/com') 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; * {@link #pause()} Playing Paused * {@link #destroy(GL)} ANY Uninitialized * + *

+ * 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. + *

*/ 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} * + *

+ * In case the current state is not {@link State#Playing}, {@link #getLastTexture()} is returned. + *

+ * * @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(); /** * Warning: Optional information, may not be supported by implementation. * @return the overall bitrate of the stream. */ - public long getBitrate(); + public long getStreamBitrate(); + /** + * Warning: Optional information, may not be supported by implementation. + * @return video bitrate + */ + public int getVideoBitrate(); + + /** + * Warning: Optional information, may not be supported by implementation. + * @return the audio bitrate + */ + public int getAudioBitrate(); + /** * Warning: 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. + *

+ * Ensure to respect the texture coordinates provided by + * {@link TextureFrame}.{@link TextureFrame#getTexture() getTexture()}.{@link Texture#getImageTexCoords() getImageTexCoords()}. + *

+ * The user's shader shall be fitted for this implementation. + * Assuming we use a base shader code w/o headers using ShaderCode. + * (Code copied from unit test / demo TexCubeES2) + *
+ * 
+    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);
+        }
+        ...
+ * 
+ * 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 { @@ -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. *

* In case the instance is just initialized, it shall return a TextureFrame * object with valid attributes. The texture content may be undefined * until the first call of {@link #getNextTexture(GL, boolean)}.
*

- * 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 { *

* Shall return null in case no frame is available. *

+ * + * @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.: + *
+     * #extension GL_OES_EGL_image_external : enable
+     * 
+ * + * @throws IllegalStateException if instance is not initialized + */ + public String getRequiredExtensionsShaderStub() throws IllegalStateException ; + + /** + * Returns either sampler2D or samplerExternalOES + * 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 null 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 + *
+     *   vec4 funcName(in getTextureSampler2DType() image, in vec2 texCoord) {
+     *      vec4 texColor = do_something_with(image, texCoord);
+     *      return texColor;
+     *   }
+     * 
+ *

+ * funcName can be negotiated and queried via {@link #getTextureLookupFunctionName(String)}. + *

+ * 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. + *

+ * @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 -- cgit v1.2.3