From c594cf1dc9f37dd1a6d861a1aa5426abbd082d60 Mon Sep 17 00:00:00 2001
From: Sven Gothel <sgothel@jausoft.com>
Date: Tue, 3 Apr 2012 18:49:24 +0200
Subject: GLMediaPlayer: API and implementation update. First working version
 on Android API 14

- Introduce states

- Customize / Access texture target,count,features.

- Expose TextureFrame.

- Use 'long' for all time values in msec.

- Mark information optional in API doc (fps, bps, ..)
---
 .../com/jogamp/opengl/av/GLMediaPlayer.java        | 112 +++++++++++--
 .../android/av/AndroidGLMediaPlayerAPI14.java      | 186 +++++++++++----------
 .../jogamp/opengl/av/GLMediaPlayerImpl.java        | 152 ++++++++++++-----
 .../jogamp/opengl/omx/OMXGLMediaPlayer.java        |  50 ++++--
 4 files changed, 342 insertions(+), 158 deletions(-)

(limited to 'src/jogl/classes')

diff --git a/src/jogl/classes/com/jogamp/opengl/av/GLMediaPlayer.java b/src/jogl/classes/com/jogamp/opengl/av/GLMediaPlayer.java
index 71e0e16d9..0d07f69ac 100644
--- a/src/jogl/classes/com/jogamp/opengl/av/GLMediaPlayer.java
+++ b/src/jogl/classes/com/jogamp/opengl/av/GLMediaPlayer.java
@@ -5,6 +5,8 @@ import java.net.URL;
 
 import javax.media.opengl.GL;
 
+import jogamp.opengl.Debug;
+
 import com.jogamp.opengl.util.texture.Texture;
 
 /**
@@ -17,63 +19,149 @@ import com.jogamp.opengl.util.texture.Texture;
  * </ul>
  */
 public interface GLMediaPlayer {
+    public static final boolean DEBUG = Debug.debug("GLMediaPlayer");
+    
+    public enum State {
+        Uninitialized(0), Stopped(1), Playing(2), Paused(3); 
+        
+        public final int id;
 
+        State(int id){
+            this.id = id;
+        }
+    }
+    
     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;
     }
     
-    /** Sets the stream to be used. Initializes all stream related states and GL resources. */
+    public int getTextureCount();
+    
+    public int getTextureTarget();
+    
+    /** Sets the texture min-mag filter, defaults to {@link GL#GL_NEAREST}. */
+    public void setTextureMinMagFilter(int[] minMagFilter);
+    public int[] getTextureMinMagFilter();
+    
+    /** Sets the texture min-mag filter, defaults to {@link GL#GL_CLAMP_TO_EDGE}. */
+    public void setTextureWrapST(int[] wrapST);
+    public int[] getTextureWrapST();
+    
+    /** 
+     * Sets the stream to be used. Initializes all stream related states and GL resources.
+     * <ul>
+     *   <li>ANY -> Uninitialized - invokes destroy(GL)</li>
+     *   <li>Uninitialized -> Stopped</li>
+     * </ul>
+     */
     public void setStream(GL gl, URL url) throws IOException;
 
-    /** Releases the GL and stream resources. */
+    /**
+     * Releases the GL and stream resources.
+     * <p>
+     * <code>ANY</code> -> Uninitialized
+     * </p>
+     */
     public void destroy(GL gl);
 
     public void setPlaySpeed(float rate);
 
     public float getPlaySpeed();
 
-    public void start();
-
-    public void pause();
+    /**
+     * Stopped/Paused -> Playing
+     */
+    public State start();
 
-    public void stop();
+    /**
+     * Playing -> Paused
+     */
+    public State pause();
 
+    /**
+     * Playing/Paused -> Stopped
+     */
+    public State stop();
+    
+    /**
+     * @return the current state, either Uninitialized, Stopped, Playing, Paused
+     */
+    public State getState();
+    
     /**
      * @return time current position in milliseconds 
      **/
-    public int getCurrentPosition();
+    public long getCurrentPosition();
 
     /**
      * @param msec absolute desired time position in milliseconds 
      * @return time current position in milliseconds, after seeking to the desired position  
      **/
-    public int seek(int msec);
-
-    public Texture getLastTextureID();
-
-    public Texture getNextTextureID();
+    public long seek(long msec);
 
+    /**
+     * @return the last updated texture. Not blocking. 
+     */
+    public TextureFrame getLastTexture();
+    
+    /**
+     * @return the next texture, which should be rendered. May block, depending on implementation.
+     * 
+     * @see #addEventListener(GLMediaEventListener)
+     * @see GLMediaEventListener#newFrameAvailable(GLMediaPlayer, TextureFrame)
+     */
+    public TextureFrame getNextTexture();
+    
     public boolean isValid();
 
     public URL getURL();
 
+    /**
+     * <i>Warning:</i> Optional information, may not be supported by implementation.
+     * @return the code of the video stream, if available 
+     */
     public String getVideoCodec();
 
+    /**
+     * <i>Warning:</i> Optional information, may not be supported by implementation.
+     * @return the code of the audio stream, if available 
+     */
     public String getAudioCodec();
 
+    /**
+     * <i>Warning:</i> Optional information, may not be supported by implementation.
+     * @return the total number of video frames
+     */
     public long getTotalFrames();
 
+    /**
+     * @return total duration of stream in msec.
+     */
+    public long getDuration();
+    
+    /**
+     * <i>Warning:</i> Optional information, may not be supported by implementation.
+     * @return the overall bitrate of the stream.  
+     */
     public long getBitrate();
 
+    /**
+     * <i>Warning:</i> Optional information, may not be supported by implementation.
+     * @return the framerate of the video
+     */
     public int getFramerate();
 
     public int getWidth();
diff --git a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
index adfe2a048..a2d9b9bf3 100644
--- a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
+++ b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
@@ -1,11 +1,9 @@
 package jogamp.opengl.android.av;
 
 import java.io.IOException;
-import java.net.URL;
 
 import javax.media.opengl.GL;
 import javax.media.opengl.GLContext;
-import javax.media.opengl.GLDrawable;
 import javax.media.opengl.GLES2;
 
 import jogamp.common.os.android.StaticContext;
@@ -17,12 +15,7 @@ import android.media.MediaPlayer;
 import android.net.Uri;
 import android.view.Surface;
 
-import com.jogamp.opengl.av.GLMediaEventListener;
-import com.jogamp.opengl.av.GLMediaPlayer;
-import com.jogamp.opengl.av.GLMediaPlayer.TextureFrame;
-import com.jogamp.opengl.util.PMVMatrix;
 import com.jogamp.opengl.util.texture.Texture;
-import com.jogamp.opengl.util.texture.TextureCoords;
 
 /***
  * Android API Level 14: {@link MediaPlayer#setSurface(Surface)}
@@ -31,6 +24,8 @@ import com.jogamp.opengl.util.texture.TextureCoords;
 public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl {
     MediaPlayer mp;
     boolean updateSurface = false;
+    Object updateSurfaceLock = new Object();
+    AndroidTextureFrame atex = null;
     
     public static class AndroidTextureFrame extends TextureFrame {
         public AndroidTextureFrame(Texture t, SurfaceTexture stex) {
@@ -59,137 +54,156 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl {
     }
 
     @Override
-    public void start() {
-        mp.start();
+    protected boolean startImpl() {
+        try {
+            mp.start();
+            return true;
+        } catch (IllegalStateException ise) {
+            if(DEBUG) {
+                ise.printStackTrace();
+            }
+        }
+        return false;
     }
 
     @Override
-    public void pause() {
-        mp.pause();
+    protected boolean pauseImpl() {
+        try {
+            mp.pause();
+            return true;
+        } catch (IllegalStateException ise) {
+            if(DEBUG) {
+                ise.printStackTrace();
+            }
+        }
+        return false;
     }
 
     @Override
-    public void stop() {
-        mp.stop();
+    protected boolean stopImpl() {
+        try {
+            mp.stop();
+            return true;
+        } catch (IllegalStateException ise) {
+            if(DEBUG) {
+                ise.printStackTrace();
+            }
+        }
+        return false;
     }
-
+    
     @Override
-    public int seek(int msec) {
-        mp.seekTo(msec);
+    public long seek(long msec) {
+        mp.seekTo((int)msec);
         return mp.getCurrentPosition();
     }
 
     @Override
-    public Texture getNextTextureID() {
-        // TODO Auto-generated method stub
-        return null;
+    public TextureFrame getLastTexture() {
+        return atex;
     }
 
     @Override
-    public int getCurrentPosition() {
-        return mp.getCurrentPosition();
+    public TextureFrame getNextTexture() {
+        if(null != atex) {
+            final boolean _updateSurface;
+            synchronized(updateSurfaceLock) {
+                _updateSurface = updateSurface;
+                updateSurface = false;
+            }
+            if(_updateSurface) {
+                atex.getSurfaceTexture().updateTexImage();
+                // atex.getSurfaceTexture().getTransformMatrix(atex.getSTMatrix());
+            }
+            return atex;
+        } else {
+            return null;
+        }
+    }
+    
+    @Override
+    public long getCurrentPosition() {
+        return null != mp ? mp.getCurrentPosition() : 0;
     }
 
     @Override
     public boolean isValid() {
-        return true;
+        return null != mp;
     }
     
-    AndroidTextureFrame androidTextureFrame = null;
-    
     @Override
     protected void destroyImpl(GL gl) {
-        mp.release();
-        mp = null;        
+        if(null != mp) {
+            mp.release();
+            mp = null;
+        }
     }
     
     @Override
-    protected void setStreamImpl() throws IOException {
-        try {
-            final Uri uri = Uri.parse(url.toExternalForm());        
-            mp.setDataSource(StaticContext.getContext(), uri);
-        } catch (IllegalArgumentException e) {
-            throw new RuntimeException(e);
-        } catch (SecurityException e) {
-            throw new RuntimeException(e);
-        } catch (IllegalStateException e) {
-            throw new RuntimeException(e);
+    protected void setStreamImplPreGL() throws IOException {
+        if(null!=mp && null!=url) {
+            try {
+                final Uri uri = Uri.parse(url.toExternalForm());        
+                mp.setDataSource(StaticContext.getContext(), uri);
+            } catch (IllegalArgumentException e) {
+                throw new RuntimeException(e);
+            } catch (SecurityException e) {
+                throw new RuntimeException(e);
+            } catch (IllegalStateException e) {
+                throw new RuntimeException(e);
+            }
+            mp.prepare();
+            
+            width = mp.getVideoWidth();
+            height = mp.getVideoHeight();
+            fps = 0;
+            bps = 0;
+            totalFrames = 0;
+            duration = mp.getDuration();
+            acodec = "unknown";
+            vcodec = "unknown";
         }
-        mp.prepare();
+    }
+    
+    @Override
+    protected void setStreamImplPostGL() throws IOException {
         
-        width = mp.getVideoWidth();
-        height = mp.getVideoHeight();
-        fps = 0;
-        bps = 0;
-        totalFrames = mp.getDuration();
-        acodec = "unknown";
-        vcodec = "unknown";        
     }
     
     @Override
     protected void destroyTexImage(GLContext ctx, TextureFrame imgTex) {
         final AndroidTextureFrame atf = (AndroidTextureFrame) imgTex;
         atf.getSurfaceTexture().release();
+        atex = null;
         super.destroyTexImage(ctx, imgTex);
     }
     
     @Override
     protected AndroidTextureFrame createTexImage(GLContext ctx, int idx, int[] tex) {
-        final GL gl = ctx.getGL();
-        
-        if( 0 > tex[idx] ) {
-            throw new RuntimeException("TextureName "+toHexString(tex[idx])+" invalid.");
-        }
-        gl.glBindTexture(GLES2.GL_TEXTURE_EXTERNAL_OES, tex[idx]);
-        {
-            final int err = gl.glGetError();
-            if( GL.GL_NO_ERROR != err ) {
-                throw new RuntimeException("Couldn't bind textureName "+toHexString(tex[idx])+" to 2D target, err "+toHexString(err));
-            }
-        }
-        // gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
-        // gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
-        gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
-        gl.glTexParameterf(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
-        // Clamp to edge is only option.
-        gl.glTexParameteri(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
-        gl.glTexParameteri(GLES2.GL_TEXTURE_EXTERNAL_OES, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
+        final Texture texture = super.createTexImageImpl(ctx, idx, tex, true);
                 
-        SurfaceTexture stex = new SurfaceTexture(tex[idx]);
+        final SurfaceTexture stex = new SurfaceTexture(tex[idx]);
         stex.setOnFrameAvailableListener(onFrameAvailableListener);
+        final Surface surf = new Surface(stex);
+        mp.setSurface(surf);
+        surf.release();
         
-        return new AndroidTextureFrame( com.jogamp.opengl.util.texture.TextureIO.newTexture(tex[idx],
-                                     GLES2.GL_TEXTURE_EXTERNAL_OES,
-                                     width, height,
-                                     width, height,
-                                     true), stex);
+        atex = new AndroidTextureFrame( texture, stex );
+        return atex;
     }
 
     protected OnFrameAvailableListener onFrameAvailableListener = new OnFrameAvailableListener() {
         @Override
         public void onFrameAvailable(SurfaceTexture surfaceTexture) {
-            frameNumber++;
-            updateSurface = true;
+            synchronized(updateSurfaceLock) {
+                updateSurface = true;
+            }
+            AndroidGLMediaPlayerAPI14.this.newFrameAvailable(atex);
         }        
     };
         
     @Override
     public float getPlaySpeed() {
-        // TODO Auto-generated method stub
         return 0;
     }
-
-    private float[] mSTMatrix = new float[16];
-    
-    @Override
-    public Texture getLastTextureID() {
-        if(updateSurface) {
-            androidTextureFrame.getSurfaceTexture().updateTexImage();
-            androidTextureFrame.getSurfaceTexture().getTransformMatrix(mSTMatrix);
-            TextureCoords tc = androidTextureFrame.getTexture().getImageTexCoords();
-            PMVMatrix pmv;
-        }
-        return androidTextureFrame.getTexture();
-    }
-
 }
diff --git a/src/jogl/classes/jogamp/opengl/av/GLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/av/GLMediaPlayerImpl.java
index 826bb6953..793ee2ea3 100644
--- a/src/jogl/classes/jogamp/opengl/av/GLMediaPlayerImpl.java
+++ b/src/jogl/classes/jogamp/opengl/av/GLMediaPlayerImpl.java
@@ -29,29 +29,34 @@ import com.jogamp.opengl.util.texture.Texture;
  */
 public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
 
+    protected State state;
     protected int textureCount;
     protected int textureTarget;
     
+    protected int[] texMinMagFilter = { GL.GL_NEAREST, GL.GL_NEAREST };
+    protected int[] texWrapST = { GL.GL_CLAMP_TO_EDGE, GL.GL_CLAMP_TO_EDGE };
+    
     private int sWidth = 0;
     private int sHeight = 0;
     protected URL url = null;
     
-    protected Texture texture = null;
     protected float playSpeed = 1.0f;
     
-    /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+    /** Shall be set by the {@link #setStreamImplPreGL()} or {@link #setStreamImplPostGL()} method implementation. */
     protected int width = 0;
-    /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+    /** Shall be set by the {@link #setStreamImplPreGL()} or {@link #setStreamImplPostGL()}method implementation. */
     protected int height = 0;
-    /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+    /** Shall be set by the {@link #setStreamImplPreGL()} or {@link #setStreamImplPostGL()}method implementation. */
     protected int fps = 0;
-    /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+    /** Shall be set by the {@link #setStreamImplPreGL()} or {@link #setStreamImplPostGL()}method implementation. */
     protected long bps = 0;
-    /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+    /** In frames. Shall be set by the {@link #setStreamImplPreGL()} or {@link #setStreamImplPostGL()}method implementation. */
     protected long totalFrames = 0;
-    /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+    /** In ms. Shall be set by the {@link #setStreamImplPreGL()} or {@link #setStreamImplPostGL()}method implementation. */
+    protected long duration = 0;
+    /** Shall be set by the {@link #setStreamImplPreGL()} or {@link #setStreamImplPostGL()}method implementation. */
     protected String acodec = null;
-    /** Shall be set by the {@link #setStreamImpl()} method implementation. */
+    /** Shall be set by the {@link #setStreamImplPreGL()} or {@link #setStreamImplPostGL()}method implementation. */
     protected String vcodec = null;
 
     protected long frameNumber = 0;
@@ -63,29 +68,75 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
     protected GLMediaPlayerImpl() {
         this.textureCount=3;
         this.textureTarget=GL.GL_TEXTURE_2D;
+        this.state = State.Uninitialized;
     }
 
     protected final void setTextureCount(int textureCount) {
         this.textureCount=textureCount;
     }
+    public final int getTextureCount() { return textureCount; }
+    
     protected final void setTextureTarget(int textureTarget) {
         this.textureTarget=textureTarget;
     }
+    public final int getTextureTarget() { return textureTarget; }
+
+    public final void setTextureMinMagFilter(int[] minMagFilter) { texMinMagFilter[0] = minMagFilter[0]; texMinMagFilter[1] = minMagFilter[1];}
+    public final int[] getTextureMinMagFilter() { return texMinMagFilter; }
+    
+    public final void setTextureWrapST(int[] wrapST) { texWrapST[0] = wrapST[0]; texWrapST[1] = wrapST[1];}
+    public final int[] getTextureWrapST() { return texWrapST; }
+
+    public final State start() {
+        switch(state) {
+            case Stopped:
+            case Paused:
+                if(startImpl()) {
+                    state = State.Playing;
+                }
+        }
+        return state;
+    }
+    protected abstract boolean startImpl();
+    
+    public final State pause() {
+        if(State.Playing == state && pauseImpl()) {
+            state = State.Paused;
+        }
+        return state;
+    }
+    protected abstract boolean pauseImpl();
+    
+    public final State stop() {
+        switch(state) {
+            case Playing:
+            case Paused:
+                if(stopImpl()) {
+                    state = State.Stopped;
+                }
+        }
+        return state;
+    }
+    protected abstract boolean stopImpl();
+    
+    public final State getState() { return state; }
     
     @Override
     public final void setStream(GL gl, URL url) throws IOException {
+        if(State.Uninitialized != state) {
+            destroy(gl);
+        }
         this.url = url;
-        if (this.url == null) {
-            System.out.println("setURL (null)");
-            stop();
-            return;
+        if (this.url != null) {
+            setStreamImplPreGL();
+            init(gl);
+            setStreamImplPostGL();
+            state = State.Stopped;
         }
-        setStreamImpl();
-        init(gl);
     }
     
     /**
-     * Implementation shall set the following set of data: 
+     * Implementation shall set the following set of data here or at {@link #setStreamImplPostGL()} 
      * @see #width
      * @see #height
      * @see #fps
@@ -94,8 +145,20 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
      * @see #acodec
      * @see #vcodec
     */
-    protected abstract void setStreamImpl() throws IOException;
+    protected abstract void setStreamImplPreGL() throws IOException;
 
+    /**
+     * Implementation shall set the following set of data here or at {@link #setStreamImplPreGL()}
+     * @see #width
+     * @see #height
+     * @see #fps
+     * @see #bps
+     * @see #totalFrames
+     * @see #acodec
+     * @see #vcodec
+    */
+    protected abstract void setStreamImplPostGL() throws IOException;
+    
     protected final void init(GL gl) {
         final GLContext ctx = gl.getContext();
         if(!ctx.isCurrent()) {
@@ -147,28 +210,29 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
             }
         }
 
-        // create space for buffer with a texture
-        gl.glTexImage2D(
-                textureTarget,    // target
-                0,                // level
-                GL.GL_RGBA,       // internal format
-                width,            // width
-                height,           // height
-                0,                // border
-                GL.GL_RGBA,       // format
-                GL.GL_UNSIGNED_BYTE, // type
-                null);            // pixels -- will be provided later
-        {
-            final int err = gl.glGetError();
-            if( GL.GL_NO_ERROR != err ) {
-                throw new RuntimeException("Couldn't create TexImage2D RGBA "+width+"x"+height+", err "+toHexString(err));
+        if(GLES2.GL_TEXTURE_EXTERNAL_OES != textureTarget) {
+            // create space for buffer with a texture
+            gl.glTexImage2D(
+                    textureTarget,    // target
+                    0,                // level
+                    GL.GL_RGBA,       // internal format
+                    width,            // width
+                    height,           // height
+                    0,                // border
+                    GL.GL_RGBA,       // format
+                    GL.GL_UNSIGNED_BYTE, // type
+                    null);            // pixels -- will be provided later
+            {
+                final int err = gl.glGetError();
+                if( GL.GL_NO_ERROR != err ) {
+                    throw new RuntimeException("Couldn't create TexImage2D RGBA "+width+"x"+height+", err "+toHexString(err));
+                }
             }
         }
-        gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
-        gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);        
-        // Clamp to edge is only option.
-        gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE);
-        gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE);
+        gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MIN_FILTER, texMinMagFilter[0]);
+        gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MAG_FILTER, texMinMagFilter[0]);        
+        gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_S, texWrapST[0]);
+        gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_T, texWrapST[1]);
         
         return com.jogamp.opengl.util.texture.TextureIO.newTexture(tex[idx],
                      textureTarget,
@@ -182,7 +246,6 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
     }
     
     protected void removeAllImageTextures(GLContext ctx) {
-        texture = null;
         for(int i=0; i<textureCount; i++) {
             final TextureFrame imgTex = texFrames[i]; 
             destroyTexImage(ctx, imgTex);
@@ -199,6 +262,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
         }
     }
     protected void newFrameAvailable(TextureFrame frame) {
+        frameNumber++;        
         synchronized(eventListenersLock) {
             for(Iterator<GLMediaEventListener> i = eventListeners.iterator(); i.hasNext(); ) {
                 i.next().newFrameAvailable(this, frame);
@@ -211,15 +275,11 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
         return playSpeed;
     }
 
-    @Override
-    public synchronized Texture getLastTextureID() {
-        return texture;
-    }
-
     @Override
     public synchronized void destroy(GL gl) {
         destroyImpl(gl);
         removeAllImageTextures(gl.getContext());
+        state = State.Uninitialized;
     }
     protected abstract void destroyImpl(GL gl);
 
@@ -243,6 +303,11 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
         return totalFrames;
     }
 
+    @Override
+    public synchronized long getDuration() {
+        return duration;
+    }
+    
     @Override
     public synchronized long getBitrate() {
         return bps;
@@ -265,7 +330,8 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
 
     @Override
     public synchronized String toString() {
-        return "GLMediaPlayer [ stream [ video [ "+vcodec+", "+width+"x"+height+", "+fps+"fps, "+bps+"bsp, "+totalFrames+"f ] ] ]";
+        final float ct = getCurrentPosition() / 1000.0f, tt = getDuration() / 1000.0f;
+        return "GLMediaPlayer ["+state+", "+frameNumber+"/"+totalFrames+" frames, "+ct+"/"+tt+"s, stream [video ["+vcodec+", "+width+"x"+height+", "+fps+"fps, "+bps+"bsp]]]";
     }
 
     @Override
diff --git a/src/jogl/classes/jogamp/opengl/omx/OMXGLMediaPlayer.java b/src/jogl/classes/jogamp/opengl/omx/OMXGLMediaPlayer.java
index 8f5f9c3ab..23eadcd27 100644
--- a/src/jogl/classes/jogamp/opengl/omx/OMXGLMediaPlayer.java
+++ b/src/jogl/classes/jogamp/opengl/omx/OMXGLMediaPlayer.java
@@ -10,7 +10,7 @@ import javax.media.opengl.GLContext;
 import javax.media.opengl.GLException;
 
 import com.jogamp.opengl.av.GLMediaEventListener;
-import com.jogamp.opengl.util.texture.Texture;
+import com.jogamp.opengl.av.GLMediaPlayer.TextureFrame;
 
 import jogamp.opengl.av.EGLMediaPlayerImpl;
 import jogamp.opengl.egl.EGL;
@@ -26,7 +26,10 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl {
     protected int o_fps = 0;
     protected long o_bps = 0;
     protected long o_totalFrames = 0;
+    protected long o_duration = 0;
         
+    protected TextureFrame lastTex = null;
+
     public OMXGLMediaPlayer() {
         super(TextureType.KHRImage, true);
         initOMX();
@@ -43,6 +46,7 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl {
     protected TextureFrame createTexImage(GLContext ctx, int idx, int[] tex) {
         final EGLTextureFrame eglTex = (EGLTextureFrame) super.createTexImage(ctx, idx, tex);
         _setStreamEGLImageTexture2D(moviePtr, idx, tex[idx], eglTex.getImage(), eglTex.getSync());
+        lastTex = eglTex;
         return eglTex;
     }
     
@@ -61,7 +65,7 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl {
     }
     
     @Override
-    protected void setStreamImpl() throws IOException {
+    protected void setStreamImplPreGL() throws IOException {
         if(0==moviePtr) {
             throw new GLException("OMX native instance null");
         }
@@ -91,9 +95,13 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl {
         System.out.println("setURL: p2 "+this);
     }
     
+    @Override
+    protected void setStreamImplPostGL() throws IOException {
+        
+    }
         
     @Override
-    public synchronized int getCurrentPosition() {
+    public synchronized long getCurrentPosition() {
         if(0==moviePtr) {
             throw new GLException("OMX native instance null");
         }
@@ -114,36 +122,38 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl {
         playSpeed = rate;
     }
 
-    /** @return time position after issuing the command */
     @Override
-    public synchronized void start() {
+    public synchronized boolean startImpl() {
         if(0==moviePtr) {
-            throw new GLException("OMX native instance null");
+            return false;
         }
         _play(moviePtr);
+        return true;
     }
 
     /** @return time position after issuing the command */
     @Override
-    public synchronized void pause() {
+    public synchronized boolean pauseImpl() {
         if(0==moviePtr) {
-            throw new GLException("OMX native instance null");
+            return false;
         }
         _pause(moviePtr);
+        return true;
     }
 
     /** @return time position after issuing the command */
     @Override
-    public synchronized void stop() {
+    public synchronized boolean stopImpl() {
         if(0==moviePtr) {
-            throw new GLException("OMX native instance null");
+            return false;
         }
         _stop(moviePtr);
+        return true;
     }
 
     /** @return time position after issuing the command */
     @Override
-    public synchronized int seek(int msec) {
+    public synchronized long seek(long msec) {
         if(0==moviePtr) {
             throw new GLException("OMX native instance null");
         }
@@ -151,16 +161,21 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl {
     }
 
     @Override
-    public synchronized Texture getNextTextureID() {
+    public TextureFrame getLastTexture() {
+        return lastTex;
+    }
+    
+    @Override
+    public synchronized TextureFrame getNextTexture() {
         if(0==moviePtr) {
             throw new GLException("OMX native instance null");
         }
-        texture=null;
+        lastTex=null;
         TextureFrame eglImgTex = texFrameMap.get(new Integer(_getNextTextureID(moviePtr)));
         if(null!=eglImgTex) {
-            texture = eglImgTex.getTexture();
+            lastTex = eglImgTex;
         }
-        return texture;
+        return lastTex;
     }
 
     protected void attributesUpdated() {
@@ -192,6 +207,7 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl {
         o_fps = fps;
         o_bps = bps;
         o_totalFrames = totalFrames;
+        o_duration = duration;
     }
 
     private String replaceAll(String orig, String search, String repl) {
@@ -227,12 +243,12 @@ public class OMXGLMediaPlayer extends EGLMediaPlayerImpl {
     native void _activateStream(long moviePtr);
     
     native void _setStreamEGLImageTexture2D(long moviePtr, int i, int tex, long image, long sync);
-    native int _seek(long moviePtr, int position);
+    native 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);
-    native int _getCurrentPosition(long moviePtr);
+    native long _getCurrentPosition(long moviePtr);
 }
 
-- 
cgit v1.2.3