From c37629ea8fdcb11f7f8a18e37a4cde57d4ba6a01 Mon Sep 17 00:00:00 2001
From: Sven Gothel
Date: Wed, 14 Aug 2013 07:02:59 +0200
Subject: GLMediaPlayer Multithreaded Decoding: GLMediaPlayer* (Part-3) - WIP
- GLMediaPlayer
- Remove State.Stopped and method stop() - redundant, use pause() / destroy()
- Add notion of stream IDs
- Add API doc: State / Stream-ID incl. html-anchor
- Expose video/audio PTS, ..
- Expose optional AudioSink
- Min multithreaded textureCount is 4 (EGL* and FFMPEG*)
- GLMediaPlayerImpl
- Move AudioSink rel. impl. to this class,
allowing a tight video implementation reusing logic.
- Remove 'synchronized' methods, synchronize on State
where applicable
- implement new methods (see above)
- playSpeed is handled partially in AudioSink.
If it exeeds AudioSink's capabilities, drop audio and rely solely on video sync.
- video sync (WIP)
- video pts delay based on geometric weight
- reset video SCR if 'out of range', resync w/ PTS
-
- FramePusher
- allow interruption when pausing/stopping,
while waiting for next avail free frame to decode.
- FFMPEGMediaPlayer
- Add proper AudioDataFormat negotiation AudioSink <-> libav
- Parse libav's SampleFormat
- Remove AudioSink interaction (moved to GLMediaPlayerImpl)
- Tests (MovieSimple, MovieCube):
- Add aid/vid selection
- Add KeyListener for actions: seek(..), play()/pause(), setPlaySpeed(..)
- Dump perf-string each 2s
- TODO:
- Add audio sync in AudioSink, similar to GLMediaPlayer's weighted video delay,
here: drop audio frames.
---
.../com/jogamp/opengl/util/av/GLMediaPlayer.java | 146 +++++++++++++++------
.../opengl/util/av/GLMediaPlayerFactory.java | 5 +-
.../opengl/util/texture/TextureSequence.java | 5 +-
3 files changed, 115 insertions(+), 41 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 a36bce305..fae88ea18 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
@@ -34,19 +34,37 @@ import javax.media.opengl.GL;
import javax.media.opengl.GLException;
import jogamp.opengl.Debug;
+import jogamp.opengl.util.av.GLMediaPlayerImpl;
import com.jogamp.opengl.util.texture.TextureSequence;
/**
- * Lifecycle of an GLMediaPlayer:
+ * GLMediaPlayer interface specifies a {@link TextureSequence}
+ * with a video stream as it's source.
+ *
+ * Audio maybe supported and played back internally or via an {@link AudioSink} implementation,
+ * if an audio stream is selected in {@link #initGLStream(GL, int, URLConnection, int, int)}.
+ *
+ * GLMediaPlayer Lifecycle
+ *
+ *
+ * action | state before | state after |
+ * {@link #initGLStream(GL, int, URLConnection, int, int)} | Uninitialized | Paused |
+ * {@link #play()} | Paused | Playing |
+ * {@link #pause()} | Playing | Paused |
+ * {@link #seek(int)} | Playing, Paused | Unchanged |
+ * {@link #destroy(GL)} | ANY | Uninitialized |
+ *
+ *
+ * Audio and video Stream IDs
+ *
*
- * action | state before | state after |
- * {@link #initGLStream(GL, int, URLConnection)} | Uninitialized | Stopped |
- * {@link #start()} | Stopped, Paused | Playing |
- * {@link #stop()} | Playing, Paused | Stopped |
- * {@link #pause()} | Playing | Paused |
- * {@link #destroy(GL)} | ANY | Uninitialized |
+ * value | request | get |
+ * {@link #STREAM_ID_NONE} | mute | not available |
+ * {@link #STREAM_ID_AUTO} | auto | unspecified |
+ * ≥0 | specific stream | specific stream |
*
+ *
*
* Current implementations (check each API doc link for details):
*
@@ -76,14 +94,21 @@ import com.jogamp.opengl.util.texture.TextureSequence;
*/
public interface GLMediaPlayer extends TextureSequence {
public static final boolean DEBUG = Debug.debug("GLMediaPlayer");
+
+ /** Constant {@value} for mute or not available. See Audio and video Stream IDs. */
+ public static final int STREAM_ID_NONE = -2;
+ /** Constant {@value} for auto or unspecified. See Audio and video Stream IDs. */
+ public static final int STREAM_ID_AUTO = -1;
public interface GLMediaEventListener extends TexSeqEventListener {
- static final int EVENT_CHANGE_SIZE = 1<<0;
- static final int EVENT_CHANGE_FPS = 1<<1;
- static final int EVENT_CHANGE_BPS = 1<<2;
- static final int EVENT_CHANGE_LENGTH = 1<<3;
- static final int EVENT_CHANGE_CODEC = 1<<3;
+ static final int EVENT_CHANGE_VID = 1<<0;
+ static final int EVENT_CHANGE_AID = 1<<1;
+ static final int EVENT_CHANGE_SIZE = 1<<2;
+ static final int EVENT_CHANGE_FPS = 1<<3;
+ static final int EVENT_CHANGE_BPS = 1<<4;
+ static final int EVENT_CHANGE_LENGTH = 1<<5;
+ static final int EVENT_CHANGE_CODEC = 1<<6;
/**
* @param mp the event source
@@ -93,8 +118,11 @@ public interface GLMediaPlayer extends TextureSequence {
public void attributesChanges(GLMediaPlayer mp, int event_mask, long when);
}
+ /**
+ * See GLMediaPlayer Lifecycle.
+ */
public enum State {
- Uninitialized(0), Stopped(1), Playing(2), Paused(3);
+ Uninitialized(0), Playing(1), Paused(2);
public final int id;
@@ -120,74 +148,106 @@ public interface GLMediaPlayer extends TextureSequence {
* Sets the stream to be used. Initializes all stream related states inclusive OpenGL ones,
* if gl
is not null.
*
- * Uninitialized -> Stopped
+ * GLMediaPlayer Lifecycle: Uninitialized -> Paused
*
* @param gl current GL object. If null, no video output and textures will be available.
* @param textureCount desired number of buffered textures to be decoded off-thread, use 1
for on-thread decoding.
* @param urlConn the stream connection
+ * @param vid video stream id, see audio and video Stream IDs
+ * @param aid video stream id, see audio and video Stream IDs
* @return the new state
*
* @throws IllegalStateException if not invoked in state Uninitialized
* @throws IOException in case of difficulties to open or process the stream
* @throws GLException in case of difficulties to initialize the GL resources
*/
- public State initGLStream(GL gl, int textureCount, URLConnection urlConn) throws IllegalStateException, GLException, IOException;
+ public State initGLStream(GL gl, int textureCount, URLConnection urlConn, int vid, int aid) throws IllegalStateException, GLException, IOException;
+
+ /**
+ * If implementation uses a {@link AudioSink}, it's instance will be returned.
+ *
+ * The {@link AudioSink} instance is available after {@link #initGLStream(GL, int, URLConnection, int, int)},
+ * if used by implementation.
+ *
+ */
+ public AudioSink getAudioSink();
/**
* Releases the GL and stream resources.
*
- * ANY
-> Uninitialized
+ * GLMediaPlayer Lifecycle: ANY
-> Uninitialized
*
*/
public State destroy(GL gl);
- public void setPlaySpeed(float rate);
+ /**
+ * Sets the playback speed.
+ *
+ * Play speed is set to normal, i.e. 1.0f
+ * if abs(1.0f - rate) < 0.01f
to simplify test.
+ *
+ * @return true if successful, otherwise false, i.e. due to unsupported value range of implementation.
+ */
+ public boolean setPlaySpeed(float rate);
public float getPlaySpeed();
/**
- * Stopped/Paused -> Playing
+ * GLMediaPlayer Lifecycle: Paused -> Playing
*/
- public State start();
+ public State play();
/**
- * Playing -> Paused
+ * GLMediaPlayer Lifecycle: Playing -> Paused
*/
public State pause();
/**
- * Playing/Paused -> Stopped
+ * Allowed in state Playing and Paused, otherwise ignored,
+ * see GLMediaPlayer Lifecycle.
+ *
+ * @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);
+
+ /**
+ * See GLMediaPlayer Lifecycle.
+ * @return the current state, either Uninitialized, Playing, Paused
*/
- public State stop();
+ public State getState();
/**
- * @return the current state, either Uninitialized, Stopped, Playing, Paused
+ * Return the video stream id, see audio and video Stream IDs.
*/
- public State getState();
+ public int getVID();
/**
- * @return current streaming position in milliseconds
- **/
- public int getCurrentPosition();
-
+ * Return the audio stream id, see audio and video Stream IDs.
+ */
+ public int getAID();
+
+ /**
+ * @return the current decoded frame count since {@link #initGLStream(GL, int, URLConnection, int, int)}.
+ */
+ public int getDecodedFrameCount();
+
+ /**
+ * @return the current presented frame count since {@link #initGLStream(GL, int, URLConnection, int, int)},
+ * increased by {@link #getNextTexture(GL, boolean)}.
+ */
+ public int getPresentedFrameCount();
+
/**
- * @return current video PTS in milliseconds of {@link #getLastTexture()}
+ * @return current video presentation timestamp (PTS) in milliseconds of {@link #getLastTexture()}
**/
public int getVideoPTS();
/**
- * @return current audio PTS in milliseconds.
+ * @return current audio presentation timestamp (PTS) in milliseconds.
**/
public int getAudioPTS();
- /**
- * Allowed in state Stopped, Playing and Paused, otherwise ignored.
- *
- * @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);
-
/**
* {@inheritDoc}
*/
@@ -225,7 +285,13 @@ public interface GLMediaPlayer extends TextureSequence {
* Warning: Optional information, may not be supported by implementation.
* @return the total number of video frames
*/
- public long getTotalFrames();
+ public int getVideoFrames();
+
+ /**
+ * Warning: Optional information, may not be supported by implementation.
+ * @return the total number of audio frames
+ */
+ public int getAudioFrames();
/**
* @return total duration of stream in msec.
@@ -262,6 +328,8 @@ public interface GLMediaPlayer extends TextureSequence {
public String toString();
+ public String getPerfString();
+
public void addEventListener(GLMediaEventListener l);
public void removeEventListener(GLMediaEventListener l);
diff --git a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayerFactory.java b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayerFactory.java
index 2707dd6d2..c7e1ab5e6 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayerFactory.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayerFactory.java
@@ -47,10 +47,13 @@ public class GLMediaPlayerFactory {
sink = create(cl, FFMPEGMediaPlayerClazzName);
}
if( null == sink ) {
- sink = new NullGLMediaPlayer();
+ sink = createNull();
}
return sink;
}
+ public static GLMediaPlayer createNull() {
+ return new NullGLMediaPlayer();
+ }
public static GLMediaPlayer create(final ClassLoader cl, String implName) {
try {
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 3f739b2cc..50801e791 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureSequence.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureSequence.java
@@ -110,9 +110,12 @@ public interface TextureSequence {
* to associated related data.
*/
public static class TextureFrame {
+ /** Constant marking an invalid PTS, i.e. Integer.MIN_VALUE {@value}. */
+ public static final int INVALID_PTS = Integer.MIN_VALUE;
+
public TextureFrame(Texture t) {
texture = t;
- pts = 0;
+ pts = INVALID_PTS;
}
public final Texture getTexture() { return texture; }
--
cgit v1.2.3