aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-11-01 12:38:54 +0100
committerSven Gothel <[email protected]>2013-11-01 12:38:54 +0100
commitf4574bf6846f2084f6a403552f7be6e845107c73 (patch)
tree1699c8bee62797231657265a741acad58d1a43e9 /src
parent33db4580da46ba21771499fdf50489e60294e439 (diff)
Bug 885 - GLMediaPlayer: Allow single threaded mode - Especially where multiple media textures (Android) or shared GL context are not usable.
- GLMediaPlayer: - TEXTURE_COUNT_MIN is the new minimum: '1' - i.e. no multithreading, single threaded player - TEXTURE_COUNT_DEFAULT is '4' - multithreaded - GLMediaPlayerImpl: - Add Single threaded mode, but perform initStreamImpl(..) off-thread. -
Diffstat (limited to 'src')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java9
-rw-r--r--src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java32
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java152
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java4
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/av/MovieCube.java100
5 files changed, 189 insertions, 108 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 3f6b78d7e..f0864f949 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/av/GLMediaPlayer.java
@@ -186,8 +186,11 @@ public interface GLMediaPlayer extends TextureSequence {
public static final boolean DEBUG = Debug.debug("GLMediaPlayer");
public static final boolean DEBUG_NATIVE = Debug.debug("GLMediaPlayer.Native");
- /** Minimum texture count, value {@value}. */
- public static final int TEXTURE_COUNT_MIN = 4;
+ /** Default texture count, value {@value}. */
+ public static final int TEXTURE_COUNT_DEFAULT = 4;
+
+ /** Minimum texture count, value {@value}. Using the minimum texture count disables multi-threaded decoding. */
+ public static final int TEXTURE_COUNT_MIN = 1;
/** 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;
@@ -350,7 +353,7 @@ public interface GLMediaPlayer extends TextureSequence {
* @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>
* @param textureCount desired number of buffered textures to be decoded off-thread, will be validated by implementation.
- * The minimum value is {@link #TEXTURE_COUNT_MIN}.
+ * The minimum value is {@link #TEXTURE_COUNT_DEFAULT}.
* Ignored if video is muted.
* @throws IllegalStateException if not invoked in {@link State#Uninitialized}
* @throws IllegalArgumentException if arguments are invalid
diff --git a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
index 415ee65a2..25a0bc15d 100644
--- a/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
+++ b/src/jogl/classes/jogamp/opengl/android/av/AndroidGLMediaPlayerAPI14.java
@@ -56,6 +56,11 @@ import android.view.Surface;
* Android implementation utilizes API level 14 (4.0.? ICS) features
* as listed below.
* <p>
+ * Implementation is single threaded only, since we are not able to utilize multiple textures.
+ * We would need to add an implementation for API level 16 using MediaCodec/MediaExtractor
+ * to expose multithreading on multiple surface/textures.
+ * </p>
+ * <p>
* We utilize the {@link MediaPlayer} with direct to texture streaming.
* The MediaPlayer uses <code>libstagefright</code> to access the OpenMAX AL implementation
* for hardware decoding.
@@ -248,8 +253,7 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl {
}
@Override
- protected final void initStreamImpl(int vid, int aid) throws IOException {
-
+ protected final void initStreamImpl(final int vid, final int aid) throws IOException {
if( null == streamLoc ) {
return;
}
@@ -297,6 +301,21 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl {
mp.getVideoWidth(), mp.getVideoHeight(), 0,
0, 0, 0f,
0, 0, mp.getDuration(), icodec, icodec);
+ /**
+ mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+ @Override
+ public void onPrepared(final MediaPlayer mp) {
+ final int r_aid = GLMediaPlayer.STREAM_ID_NONE == aid ? GLMediaPlayer.STREAM_ID_NONE : 1; // fake
+ final String icodec = "android";
+ updateAttributes(0, r_aid, // fake
+ mp.getVideoWidth(), mp.getVideoHeight(), 0,
+ 0, 0, 0f,
+ 0, 0, mp.getDuration(), icodec, icodec);
+ }
+ });
+ mp.prepareAsync();
+ *
+ */
} else if( null != cam ) {
final String icodec = "android";
final int[] fpsRange = { 0, 0 };
@@ -336,23 +355,20 @@ public class AndroidGLMediaPlayerAPI14 extends GLMediaPlayerImpl {
/**
* {@inheritDoc}
* <p>
- * Returns 2 - implementation duplicates single texture
+ * Returns {@link #TEXTURE_COUNT_MIN}, using a single texture
* </p>
*/
@Override
protected int validateTextureCount(int desiredTextureCount) {
- return 2;
+ return TEXTURE_COUNT_MIN;
}
@Override
protected final int getNextTextureImpl(GL gl, TextureFrame nextFrame) {
int pts = TimeFrameI.INVALID_PTS;
if(null != mp || null != cam) {
- final SurfaceTextureFrame sTexFrame = (SurfaceTextureFrame) nextFrame;
+ final SurfaceTextureFrame sTexFrame = null != nextFrame ? (SurfaceTextureFrame) nextFrame : singleSTexFrame;
final SurfaceTexture surfTex = sTexFrame.surfaceTex;
- if( sTexFrame != singleSTexFrame ) {
- throw new InternalError("XXX: sTexFrame: "+sTexFrame+", singleSTexFrame "+singleSTexFrame);
- }
if( !sTexFrameAttached ) {
sTexFrameAttached = true;
final Surface surface;
diff --git a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java
index 1d73d1a44..91647394d 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/GLMediaPlayerImpl.java
@@ -304,7 +304,9 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
if( null != audioSink ) {
audioSink.play(); // cont. w/ new data
}
- streamWorker.doResume();
+ if( null != streamWorker ) {
+ streamWorker.doResume();
+ }
changeState(0, State.Playing);
}
default:
@@ -325,7 +327,9 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
if( State.Playing == state ) {
event_mask = addStateEventMask(event_mask, GLMediaPlayer.State.Paused);
state = State.Paused;
- streamWorker.doPause();
+ if( null != streamWorker ) {
+ streamWorker.doPause();
+ }
if( flush ) {
resetAVPTSAndFlush();
} else if( null != audioSink ) {
@@ -348,8 +352,10 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
private final State destroyImpl(GL gl, int event_mask) {
synchronized( stateLock ) {
- streamWorker.doStop();
- streamWorker = null;
+ if( null != streamWorker ) {
+ streamWorker.doStop();
+ streamWorker = null;
+ }
destroyImpl(gl);
removeAllTextureFrames(gl);
textureCount=0;
@@ -369,14 +375,18 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
case Paused:
final State _state = state;
state = State.Paused;
- streamWorker.doPause();
+ if( null != streamWorker ) {
+ streamWorker.doPause();
+ }
pts1 = seekImpl(msec);
resetAVPTSAndFlush();
if( null != audioSink && State.Playing == _state ) {
audioSink.play(); // cont. w/ new data
}
System.err.println("SEEK XXX: "+getPerfString());
- streamWorker.doResume();
+ if( null != streamWorker ) {
+ streamWorker.doResume();
+ }
state = _state;
break;
default:
@@ -476,7 +486,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
@Override
- public final void initStream(URI streamLoc, int vid, int aid, int reqTextureCount) throws IllegalStateException, IllegalArgumentException {
+ public final void initStream(URI streamLoc, final int vid, final int aid, int reqTextureCount) throws IllegalStateException, IllegalArgumentException {
synchronized( stateLock ) {
if(State.Uninitialized != state) {
throw new IllegalStateException("Instance not in state unintialized: "+this);
@@ -486,8 +496,8 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
if( STREAM_ID_NONE != vid ) {
textureCount = validateTextureCount(reqTextureCount);
- if( textureCount < 2 ) {
- throw new InternalError("Validated texture count < 2: "+textureCount);
+ if( textureCount < TEXTURE_COUNT_MIN ) {
+ throw new InternalError("Validated texture count < "+TEXTURE_COUNT_MIN+": "+textureCount);
}
} else {
textureCount = 0;
@@ -515,8 +525,21 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
this.vid = vid;
this.aid = aid;
- if (this.streamLoc != null) {
- streamWorker = new StreamWorker();
+ if ( this.streamLoc != null ) {
+ if( TEXTURE_COUNT_MIN < textureCount ) {
+ streamWorker = new StreamWorker();
+ } else {
+ new Thread() {
+ public void run() {
+ try {
+ initStreamImpl(vid, aid);
+ } catch (Throwable t) {
+ streamErr = new StreamException(t.getClass().getSimpleName()+" while initializing: "+GLMediaPlayerImpl.this.toString(), t);
+ changeState(GLMediaEventListener.EVENT_CHANGE_ERR, GLMediaPlayer.State.Uninitialized);
+ } // also initializes width, height, .. etc
+ }
+ }.start();
+ }
}
}
}
@@ -537,13 +560,12 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
@Override
public final StreamException getStreamException() {
+ final StreamException e;
synchronized( stateLock ) {
- if( null != streamWorker ) {
- return streamWorker.getStreamErr();
- } else {
- return null;
- }
+ e = streamErr;
+ streamErr = null;
}
+ return e;
}
@Override
@@ -552,11 +574,13 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
if(State.Initialized != state ) {
throw new IllegalStateException("Stream not in state initialized: "+this);
}
- final StreamException streamInitErr = streamWorker.getStreamErr();
- if( null != streamInitErr ) {
- streamWorker = null; // already terminated!
- destroy(null);
- throw streamInitErr;
+ if( null != streamWorker ) {
+ final StreamException streamInitErr = getStreamException();
+ if( null != streamInitErr ) {
+ streamWorker = null; // already terminated!
+ destroy(null);
+ throw streamInitErr;
+ }
}
try {
if( STREAM_ID_NONE != vid ) {
@@ -566,10 +590,18 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
System.err.println("initGLImpl.X "+this);
}
videoFramesOrig = createTexFrames(gl, textureCount);
- videoFramesFree = new LFRingbuffer<TextureFrame>(videoFramesOrig);
- videoFramesDecoded = new LFRingbuffer<TextureFrame>(TextureFrame[].class, textureCount);
- lastFrame = videoFramesFree.getBlocking( );
- streamWorker.initGL(gl);
+ if( TEXTURE_COUNT_MIN == textureCount ) {
+ videoFramesFree = null;
+ videoFramesDecoded = null;
+ lastFrame = videoFramesOrig[0];
+ } else {
+ videoFramesFree = new LFRingbuffer<TextureFrame>(videoFramesOrig);
+ videoFramesDecoded = new LFRingbuffer<TextureFrame>(TextureFrame[].class, textureCount);
+ lastFrame = videoFramesFree.getBlocking( );
+ }
+ if( null != streamWorker ) {
+ streamWorker.initGL(gl);
+ }
} else {
removeAllTextureFrames(null);
initGLImpl(null);
@@ -601,10 +633,11 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
/**
* Returns the validated number of textures to be handled.
* <p>
- * Default is {@link #TEXTURE_COUNT_MIN} minimum textures.
+ * Default is {@link #TEXTURE_COUNT_DEFAULT} minimum textures, if <code>desiredTextureCount</code>
+ * is < {@link #TEXTURE_COUNT_MIN}, {@link #TEXTURE_COUNT_MIN} is returned.
* </p>
* <p>
- * Implementation must at least return a texture count of <i>two</i>, the last texture and the decoding texture.
+ * Implementation must at least return a texture count of {@link #TEXTURE_COUNT_MIN}, <i>two</i>, the last texture and the decoding texture.
* </p>
*/
protected int validateTextureCount(int desiredTextureCount) {
@@ -737,7 +770,11 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
cachedFrame = null;
presentedFrameCount--;
} else if( STREAM_ID_NONE != vid ) {
- nextFrame = videoFramesDecoded.get();
+ if( null != videoFramesDecoded ) { // single threaded ? TEXTURE_COUNT_MIN == textureCount
+ nextFrame = videoFramesDecoded.get();
+ } else {
+ nextFrame = getNextSingleThreaded(gl, lastFrame);
+ }
}
currentTimeMillis = Platform.currentTimeMillis();
if( null != nextFrame ) {
@@ -785,7 +822,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
if( dt > maxVideoDelay ) {
cachedFrame = nextFrame;
nextFrame = null;
- } else if ( !droppedFrame && dt < -maxVideoDelay && videoFramesDecoded.size() > 0 ) {
+ } else if ( !droppedFrame && dt < -maxVideoDelay && null != videoFramesDecoded && videoFramesDecoded.size() > 0 ) {
// only drop if prev. frame has not been dropped and
// frame is too late and one decoded frame is already available.
dropFrame = true;
@@ -802,7 +839,8 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
} else if( DEBUG ) {
System.err.println("Invalid PTS: "+nextFrame);
}
- if( null != nextFrame ) {
+ if( null != nextFrame && null != videoFramesFree ) {
+ // Had frame and not single threaded ? (TEXTURE_COUNT_MIN < textureCount)
final TextureFrame _lastFrame = lastFrame;
lastFrame = nextFrame;
videoFramesFree.putBlocking(_lastFrame);
@@ -857,6 +895,27 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
*/
protected abstract int getNextTextureImpl(GL gl, TextureFrame nextFrame);
+ protected final TextureFrame getNextSingleThreaded(final GL gl, final TextureFrame nextFrame) throws InterruptedException {
+ if( STREAM_ID_NONE != vid ) {
+ preNextTextureImpl(gl);
+ final int vPTS = getNextTextureImpl(gl, nextFrame);
+ postNextTextureImpl(gl);
+ if( TimeFrameI.INVALID_PTS != vPTS ) {
+ newFrameAvailable(nextFrame, Platform.currentTimeMillis());
+ return nextFrame;
+ }
+ } else {
+ // audio only
+ final int vPTS = getNextTextureImpl(null, null);
+ if( TimeFrameI.INVALID_PTS != vPTS && TimeFrameI.END_OF_STREAM_PTS == vPTS ) {
+ // state transition incl. notification
+ pauseImpl(true, GLMediaEventListener.EVENT_CHANGE_EOS);
+ }
+ }
+ return null;
+ }
+
+
/**
* {@inheritDoc}
* <p>
@@ -887,8 +946,6 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
videoFramesFree.resetFull(videoFramesOrig);
lastFrame = videoFramesFree.get();
if( null == lastFrame ) { throw new InternalError("XXX"); }
- }
- if( null != videoFramesDecoded ) {
videoFramesDecoded.clear();
}
cachedFrame = null;
@@ -933,7 +990,6 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
private volatile boolean shallPause = true;
private volatile boolean shallStop = false;
- private volatile StreamException streamErr = null;
private volatile GLContext sharedGLCtx = null;
private boolean sharedGLCtxCurrent = false;
private GLDrawable dummyDrawable = null;
@@ -977,7 +1033,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
}
- public synchronized void initGL(GL gl) {
+ public final synchronized void initGL(GL gl) {
final GLContext glCtx = gl.getContext();
final boolean glCtxCurrent = glCtx.isCurrent();
final GLProfile glp = gl.getGLProfile();
@@ -993,7 +1049,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
sharedGLCtx.release();
}
}
- public synchronized void doPause() {
+ public final synchronized void doPause() {
if( isActive ) {
shallPause = true;
if( Thread.currentThread() != this ) {
@@ -1010,7 +1066,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
}
}
- public synchronized void doResume() {
+ public final synchronized void doResume() {
if( isRunning && !isActive ) {
shallPause = false;
if( Thread.currentThread() != this ) {
@@ -1025,7 +1081,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
}
}
- public synchronized void doStop() {
+ public final synchronized void doStop() {
if( isRunning ) {
shallStop = true;
if( Thread.currentThread() != this ) {
@@ -1043,12 +1099,11 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
}
}
- public boolean isRunning() { return isRunning; }
- public boolean isActive() { return isActive; }
- public StreamException getStreamErr() { return streamErr; }
+ public final boolean isRunning() { return isRunning; }
+ public final boolean isActive() { return isActive; }
@Override
- public void run() {
+ public final void run() {
setName(getName()+"-StreamWorker_"+StreamWorkerInstanceId);
StreamWorkerInstanceId++;
@@ -1109,9 +1164,9 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
if( !shallStop ) {
TextureFrame nextFrame = null;
try {
- final GL gl;
isBlocked = true;
- if( null != videoFramesFree ) {
+ final GL gl;
+ if( STREAM_ID_NONE != vid ) {
nextFrame = videoFramesFree.getBlocking();
nextFrame.setPTS( TimeFrameI.INVALID_PTS ); // mark invalid until processed!
gl = sharedGLCtx.getGL();
@@ -1178,6 +1233,7 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
}
static int StreamWorkerInstanceId = 0;
private StreamWorker streamWorker = null;
+ private volatile StreamException streamErr = null;
protected final int addStateEventMask(int event_mask, State newState) {
if( state != newState ) {
@@ -1396,8 +1452,14 @@ public abstract class GLMediaPlayerImpl implements GLMediaPlayer {
} else {
audioSinkInfo = "";
}
- final int freeVideoFrames = null != videoFramesFree ? videoFramesFree.size() : 0;
- final int decVideoFrames = null != videoFramesDecoded ? videoFramesDecoded.size() : 0;
+ final int freeVideoFrames, decVideoFrames;
+ if( null != videoFramesFree ) {
+ freeVideoFrames = videoFramesFree.size();
+ decVideoFrames = videoFramesDecoded.size();
+ } else {
+ freeVideoFrames = 0;
+ decVideoFrames = 0;
+ }
return state+", frames[(p "+presentedFrameCount+", d "+decodedFrameCount+") / "+videoFrames+", "+tt+" s], "+
"speed " + playSpeed+", dAV "+( d_vpts - d_apts )+", vSCR "+video_scr+", vpts "+video_pts+", dSCR["+d_vpts+", avrg "+video_dpts_avg_diff+"], "+
"aSCR "+audio_scr+", apts "+audio_pts+" ( "+d_apts+" ), "+audioSinkInfo+
diff --git a/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java b/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java
index 840149272..fc621a1dd 100644
--- a/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java
+++ b/src/jogl/classes/jogamp/opengl/util/av/NullGLMediaPlayer.java
@@ -150,12 +150,12 @@ public class NullGLMediaPlayer extends GLMediaPlayerImpl {
/**
* {@inheritDoc}
* <p>
- * Returns 2
+ * Returns {@link GLMediaPlayer#TEXTURE_COUNT_MIN}.
* </p>
*/
@Override
protected int validateTextureCount(int desiredTextureCount) {
- return 2;
+ return TEXTURE_COUNT_MIN;
}
@Override
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 fe11f6aca..a7636fce4 100644
--- 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
@@ -3,14 +3,14 @@
*
* 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
@@ -20,7 +20,7 @@
* 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.
@@ -58,7 +58,7 @@ import com.jogamp.opengl.util.av.GLMediaPlayerFactory;
import com.jogamp.opengl.util.texture.TextureSequence.TextureFrame;
/**
- * Simple cube movie player w/ aspect ration true projection on a cube.
+ * Simple cube movie player w/ aspect ration true projection on a cube.
*/
public class MovieCube implements GLEventListener {
private static boolean waitForKey = false;
@@ -68,7 +68,7 @@ public class MovieCube implements GLEventListener {
private int swapInterval = 1;
private long lastPerfPos = 0;
private volatile boolean resetGLState = false;
-
+
/** Blender's Big Buck Bunny Trailer: 24f 640p VP8, Vorbis 44100Hz mono, WebM/Matroska Stream. */
public static final URI defURI;
static {
@@ -80,18 +80,18 @@ public class MovieCube implements GLEventListener {
}
defURI = _defURI;
}
-
- /**
- * Default constructor which also issues {@link #initStream(URI, int, int, int)} w/ default values
+
+ /**
+ * Default constructor which also issues {@link #initStream(URI, int, int, int)} w/ default values
* and polls until the {@link GLMediaPlayer} is {@link GLMediaPlayer.State#Initialized}.
* If {@link GLMediaEventListener#EVENT_CHANGE_EOS} is reached, the stream is started over again.
* <p>
* This default constructor is merely useful for some <i>drop-in</i> test, e.g. using an applet.
- * </p>
+ * </p>
*/
public MovieCube() throws IOException, URISyntaxException {
this(-2.3f, 0f, 0f);
-
+
mPlayer.addEventListener(new GLMediaEventListener() {
@Override
public void newFrameAvailable(GLMediaPlayer ts, TextureFrame newFrame, long when) { }
@@ -108,9 +108,9 @@ public class MovieCube implements GLEventListener {
mPlayer.seek(0);
mPlayer.play();
}
- }
+ }
});
- initStream(defURI, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, 3 /* textureCount */);
+ initStream(defURI, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.STREAM_ID_AUTO, GLMediaPlayer.TEXTURE_COUNT_DEFAULT);
StreamException se = null;
while( null == se && GLMediaPlayer.State.Initialized != mPlayer.getState() ) {
try {
@@ -123,7 +123,7 @@ public class MovieCube implements GLEventListener {
throw new RuntimeException(se);
}
}
-
+
/** Custom constructor, user needs to issue {@link #initStream(URI, int, int, int)} afterwards. */
public MovieCube(float zoom0, float rotx, float roty) throws IOException {
this.zoom0 = zoom0;
@@ -136,20 +136,20 @@ public class MovieCube implements GLEventListener {
mPlayer.initStream(streamLoc, vid, aid, textureCount);
System.out.println("pC.1b "+mPlayer);
}
-
+
public void setSwapInterval(int v) { this.swapInterval = v; }
-
+
public GLMediaPlayer getGLMediaPlayer() { return mPlayer; }
-
+
public void resetGLState() {
resetGLState = true;
}
-
+
private final KeyListener keyAction = new KeyAdapter() {
public void keyReleased(KeyEvent e) {
if( e.isAutoRepeat() ) {
return;
- }
+ }
System.err.println("MC "+e);
int pts0 = mPlayer.getVideoPTS();
int pts1 = 0;
@@ -175,7 +175,7 @@ public class MovieCube implements GLEventListener {
break;
}
case KeyEvent.VK_MULTIPLY:
- mPlayer.setPlaySpeed(1.0f);
+ mPlayer.setPlaySpeed(1.0f);
break;
case KeyEvent.VK_SUBTRACT: {
float playSpeed = mPlayer.getPlaySpeed();
@@ -184,7 +184,7 @@ public class MovieCube implements GLEventListener {
} else {
playSpeed -= 0.1f;
}
- mPlayer.setPlaySpeed(playSpeed);
+ mPlayer.setPlaySpeed(playSpeed);
} break;
case KeyEvent.VK_ADD: {
float playSpeed = mPlayer.getPlaySpeed();
@@ -193,7 +193,7 @@ public class MovieCube implements GLEventListener {
} else {
playSpeed += 0.1f;
}
- mPlayer.setPlaySpeed(playSpeed);
+ mPlayer.setPlaySpeed(playSpeed);
} break;
case KeyEvent.VK_M: {
float audioVolume = mPlayer.getAudioVolume();
@@ -202,16 +202,16 @@ public class MovieCube implements GLEventListener {
} else {
audioVolume = 1f;
}
- mPlayer.setAudioVolume(audioVolume);
+ mPlayer.setAudioVolume(audioVolume);
} break;
}
-
+
if( 0 != pts1 ) {
mPlayer.seek(pts1);
}
- }
+ }
};
-
+
@Override
public void init(GLAutoDrawable drawable) {
if(null == mPlayer) {
@@ -224,16 +224,16 @@ public class MovieCube implements GLEventListener {
// throw new IllegalStateException("mPlayer has no VID/stream selected: "+mPlayer);
}
resetGLState = false;
-
+
GL2ES2 gl = drawable.getGL().getGL2ES2();
System.err.println(JoglVersion.getGLInfo(gl, null));
- cube = new TextureSequenceCubeES2(mPlayer, false, zoom0, rotx, roty);
-
+ cube = new TextureSequenceCubeES2(mPlayer, false, zoom0, rotx, roty);
+
if(waitForKey) {
UITestCase.waitForKey("Init>");
}
-
+
if( GLMediaPlayer.State.Initialized == mPlayer.getState() ) {
try {
mPlayer.initGL(gl);
@@ -252,11 +252,11 @@ public class MovieCube implements GLEventListener {
boolean added;
final Object upstreamWidget = drawable.getUpstreamWidget();
- if (upstreamWidget instanceof Window) {
+ if (upstreamWidget instanceof Window) {
final Window window = (Window) upstreamWidget;
window.addKeyListener(keyAction);
added = true;
- } else { added = false; }
+ } else { added = false; }
System.err.println("MC.init: kl-added "+added+", "+drawable.getClass().getName());
}
@@ -275,11 +275,11 @@ public class MovieCube implements GLEventListener {
System.err.println(Thread.currentThread()+" MovieCube.dispose ... ");
disposeImpl(drawable, true);
}
-
+
private void disposeImpl(GLAutoDrawable drawable, boolean disposePlayer) {
if(null == mPlayer) { return; }
final Object upstreamWidget = drawable.getUpstreamWidget();
- if (upstreamWidget instanceof Window) {
+ if (upstreamWidget instanceof Window) {
final Window window = (Window) upstreamWidget;
window.removeKeyListener(keyAction);
}
@@ -289,14 +289,14 @@ public class MovieCube implements GLEventListener {
mPlayer=null;
}
cube.dispose(drawable);
- cube=null;
+ cube=null;
}
-
+
@Override
public void display(GLAutoDrawable drawable) {
if(null == mPlayer) { return; }
-
+
if( resetGLState ) {
resetGLState = false;
System.err.println("XXX resetGLState");
@@ -304,11 +304,11 @@ public class MovieCube implements GLEventListener {
init(drawable);
reshape(drawable, 0, 0, drawable.getWidth(), drawable.getHeight());
}
-
+
final long currentPos = System.currentTimeMillis();
if( currentPos - lastPerfPos > 2000 ) {
System.err.println( mPlayer.getPerfString() );
- lastPerfPos = currentPos;
+ lastPerfPos = currentPos;
}
cube.display(drawable);
}
@@ -317,7 +317,7 @@ public class MovieCube implements GLEventListener {
int swapInterval = 1;
int width = 510;
int height = 300;
- int textureCount = 3; // default - threaded
+ int textureCount = GLMediaPlayer.TEXTURE_COUNT_DEFAULT; // default - threaded
boolean forceES2 = false;
boolean forceES3 = false;
@@ -326,10 +326,10 @@ public class MovieCube implements GLEventListener {
int vid = GLMediaPlayer.STREAM_ID_AUTO;
int aid = GLMediaPlayer.STREAM_ID_AUTO;
final boolean origSize;
-
+
String url_s=null;
{
- boolean _origSize = false;
+ boolean _origSize = false;
for(int i=0; i<args.length; i++) {
if(args[i].equals("-vid")) {
i++;
@@ -382,10 +382,10 @@ public class MovieCube implements GLEventListener {
System.err.println("forceGL3 "+forceGL3);
System.err.println("forceGLDef "+forceGLDef);
System.err.println("swapInterval "+swapInterval);
-
+
final MovieCube mc = new MovieCube(-2.3f, 0f, 0f);
mc.setSwapInterval(swapInterval);
-
+
final GLProfile glp;
if(forceGLDef) {
glp = GLProfile.getDefault();
@@ -397,19 +397,19 @@ public class MovieCube implements GLEventListener {
glp = GLProfile.get(GLProfile.GLES2);
} else {
glp = GLProfile.getGL2ES2();
- }
+ }
System.err.println("GLProfile: "+glp);
final GLWindow window = GLWindow.create(new GLCapabilities(glp));
final Animator anim = new Animator(window);
window.addWindowListener(new WindowAdapter() {
public void windowDestroyed(WindowEvent e) {
anim.stop();
- }
+ }
});
window.setSize(width, height);
window.setVisible(true);
anim.start();
-
+
mc.mPlayer.addEventListener(new GLMediaEventListener() {
@Override
public void newFrameAvailable(GLMediaPlayer ts, TextureFrame newFrame, long when) {
@@ -434,15 +434,15 @@ public class MovieCube implements GLEventListener {
if( 0 != ( ( GLMediaEventListener.EVENT_CHANGE_ERR | GLMediaEventListener.EVENT_CHANGE_EOS ) & event_mask ) ) {
final StreamException se = mc.mPlayer.getStreamException();
if( null != se ) {
- se.printStackTrace();
+ se.printStackTrace();
}
new Thread() {
public void run() {
window.destroy();
} }.start();
}
- }
- });
+ }
+ });
mc.initStream(streamLoc, vid, aid, textureCount);
}
}