diff options
author | Sven Gothel <[email protected]> | 2013-08-14 07:02:59 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-08-14 07:02:59 +0200 |
commit | c37629ea8fdcb11f7f8a18e37a4cde57d4ba6a01 (patch) | |
tree | 96e6ef2b8db44f3dd331ac78a0a52d5d5ea15e50 /src/jogl/classes/com/jogamp/opengl | |
parent | bc3776633ccad81199a96ff8116195133d862395 (diff) |
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.
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl')
3 files changed, 115 insertions, 41 deletions
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. + * <p> + * 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)}. + * </p> + * <a name="lifecycle"><h5>GLMediaPlayer Lifecycle</h5></a> + * <p> + * <table border="1"> + * <tr><th>action</th> <th>state before</th> <th>state after</th></tr> + * <tr><td>{@link #initGLStream(GL, int, URLConnection, int, int)}</td> <td>Uninitialized</td> <td>Paused</td></tr> + * <tr><td>{@link #play()}</td> <td>Paused</td> <td>Playing</td></tr> + * <tr><td>{@link #pause()}</td> <td>Playing</td> <td>Paused</td></tr> + * <tr><td>{@link #seek(int)}</td> <td>Playing, Paused</td> <td>Unchanged</td></tr> + * <tr><td>{@link #destroy(GL)}</td> <td>ANY</td> <td>Uninitialized</td></tr> + * </table> + * </p> + * <a name="streamIDs"><h5>Audio and video Stream IDs</h5></a> + * <p> * <table border="1"> - * <tr><th>action</th> <th>state before</th> <th>state after</th></tr> - * <tr><td>{@link #initGLStream(GL, int, URLConnection)}</td> <td>Uninitialized</td> <td>Stopped</td></tr> - * <tr><td>{@link #start()}</td> <td>Stopped, Paused</td> <td>Playing</td></tr> - * <tr><td>{@link #stop()}</td> <td>Playing, Paused</td> <td>Stopped</td></tr> - * <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> + * <tr><th>value</th> <th>request</th> <th>get</th></tr> + * <tr><td>{@link #STREAM_ID_NONE}</td> <td>mute</td> <td>not available</td></tr> + * <tr><td>{@link #STREAM_ID_AUTO}</td> <td>auto</td> <td>unspecified</td></tr> + * <tr><td>≥0</td> <td>specific stream</td> <td>specific stream</td></tr> * </table> + * </p> * <p> * Current implementations (check each API doc link for details): * <ul> @@ -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 <i>mute</i> or <i>not available</i>. See <a href="#streamIDs">Audio and video Stream IDs</a>. */ + public static final int STREAM_ID_NONE = -2; + /** Constant {@value} for <i>auto</i> or <i>unspecified</i>. See <a href="#streamIDs">Audio and video Stream IDs</a>. */ + public static final int STREAM_ID_AUTO = -1; public interface GLMediaEventListener extends TexSeqEventListener<GLMediaPlayer> { - 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 <a href="#lifecycle">GLMediaPlayer Lifecycle</a>. + */ public enum State { - Uninitialized(0), Stopped(1), Playing(2), Paused(3); + Uninitialized(0), Playing(1), Paused(2); public final int id; @@ -120,75 +148,107 @@ public interface GLMediaPlayer extends TextureSequence { * Sets the stream to be used. Initializes all stream related states inclusive OpenGL ones, * if <code>gl</code> is not null. * <p> - * Uninitialized -> Stopped + * <a href="#lifecycle">GLMediaPlayer Lifecycle</a>: Uninitialized -> Paused * </p> * @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 <code>1</code> for on-thread decoding. * @param urlConn the stream connection + * @param vid video stream id, see <a href="#streamIDs">audio and video Stream IDs</a> + * @param aid video stream id, see <a href="#streamIDs">audio and video Stream IDs</a> * @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. + * <p> + * The {@link AudioSink} instance is available after {@link #initGLStream(GL, int, URLConnection, int, int)}, + * if used by implementation. + * </p> + */ + public AudioSink getAudioSink(); /** * Releases the GL and stream resources. * <p> - * <code>ANY</code> -> Uninitialized + * <a href="#lifecycle">GLMediaPlayer Lifecycle</a>: <code>ANY</code> -> Uninitialized * </p> */ public State destroy(GL gl); - public void setPlaySpeed(float rate); + /** + * Sets the playback speed. + * <p> + * Play speed is set to <i>normal</i>, i.e. <code>1.0f</code> + * if <code> abs(1.0f - rate) < 0.01f</code> to simplify test. + * </p> + * @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 + * <a href="#lifecycle">GLMediaPlayer Lifecycle</a>: Paused -> Playing */ - public State start(); + public State play(); /** - * Playing -> Paused + * <a href="#lifecycle">GLMediaPlayer Lifecycle</a>: Playing -> Paused */ public State pause(); /** - * Playing/Paused -> Stopped + * Allowed in state Playing and Paused, otherwise ignored, + * see <a href="#lifecycle">GLMediaPlayer Lifecycle</a>. + * + * @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 <a href="#lifecycle">GLMediaPlayer Lifecycle</a>. + * @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 <a href="#streamIDs">audio and video Stream IDs</a>. */ - public State getState(); + public int getVID(); /** - * @return current streaming position in milliseconds - **/ - public int getCurrentPosition(); - + * Return the audio stream id, see <a href="#streamIDs">audio and video Stream IDs</a>. + */ + 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} */ @Override @@ -225,7 +285,13 @@ public interface GLMediaPlayer extends TextureSequence { * <i>Warning:</i> Optional information, may not be supported by implementation. * @return the total number of video frames */ - public long getTotalFrames(); + public int getVideoFrames(); + + /** + * <i>Warning:</i> 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; } |