[Android] LibVLC: AWindow: re-use the same SurfaceTexture
Thomas Guillem
git at videolan.org
Fri Apr 21 16:37:29 CEST 2017
vlc-android | branch: master | Thomas Guillem <thomas at gllm.fr> | Thu Apr 20 18:48:00 2017 +0200| [063da52898d90c2cd4498ba44a2b8ef48df94a2d] | committer: Thomas Guillem
LibVLC: AWindow: re-use the same SurfaceTexture
Call attachToGLContext/detachFromGLContext on a same SurfaceTexture instance.
That way, we don't have to re-configure MediaCodec in order to setup the new
Surface when the video size change mid-stream (and when a new OpenGL vout is
created).
> https://code.videolan.org/videolan/vlc-android/commit/063da52898d90c2cd4498ba44a2b8ef48df94a2d
---
compile.sh | 2 +-
libvlc/src/org/videolan/libvlc/AWindow.java | 148 ++++++++++++++++++----------
2 files changed, 96 insertions(+), 54 deletions(-)
diff --git a/compile.sh b/compile.sh
index 41b2998..78d5625 100755
--- a/compile.sh
+++ b/compile.sh
@@ -167,7 +167,7 @@ fi
# Fetch VLC source #
####################
-TESTED_HASH=a32c5ee
+TESTED_HASH=c547de6
if [ ! -d "vlc" ]; then
diagnostic "VLC source not found, cloning"
git clone http://git.videolan.org/git/vlc.git vlc
diff --git a/libvlc/src/org/videolan/libvlc/AWindow.java b/libvlc/src/org/videolan/libvlc/AWindow.java
index 8e8a2e6..262d391 100644
--- a/libvlc/src/org/videolan/libvlc/AWindow.java
+++ b/libvlc/src/org/videolan/libvlc/AWindow.java
@@ -206,6 +206,8 @@ public class AWindow implements IVLCVout {
private int mMouseAction = -1, mMouseButton = -1, mMouseX = -1, mMouseY = -1;
private int mWindowWidth = -1, mWindowHeight = -1;
+ private SurfaceTextureThread mSurfaceTextureThread = new SurfaceTextureThread();
+
/**
* Create an AWindow
*
@@ -359,6 +361,7 @@ public class AWindow implements IVLCVout {
cb.onSurfacesDestroyed(this);
if (mSurfaceCallback != null)
mSurfaceCallback.onSurfacesDestroyed(this);
+ mSurfaceTextureThread.release();
}
@Override
@@ -620,22 +623,47 @@ public class AWindow implements IVLCVout {
});
}
- @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
- private static class SurfaceTextureThread extends Thread
- implements SurfaceTexture.OnFrameAvailableListener {
- SurfaceTexture mSurfaceTexture = null;
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
+ private static class SurfaceTextureThread
+ implements Runnable, SurfaceTexture.OnFrameAvailableListener {
+ private SurfaceTexture mSurfaceTexture = null;
+ private Surface mSurface = null;
- final int mTexName;
- boolean mFrameAvailable = false;
- Looper mLooper = null;
+ private boolean mFrameAvailable = false;
+ private Looper mLooper = null;
+ private Thread mThread = null;
+ private boolean mIsAttached = false;
+ private boolean mDoRelease = false;
+
+ private SurfaceTextureThread() {
+ }
- private SurfaceTextureThread(int texName) {
- mTexName = texName;
+ private synchronized boolean attachToGLContext(int texName) {
+ /* Try to re-use the same SurfaceTexture until views are detached. By reusing the same
+ * SurfaceTexture, we don't have to reconfigure MediaCodec when it signals a video size
+ * change (and when a new VLC vout is created) */
+ if (mSurfaceTexture == null) {
+ /* Yes, a new Thread, see comments in the run method */
+ mThread = new Thread(this);
+ mThread.start();
+ while (mSurfaceTexture == null) {
+ try {
+ wait();
+ } catch (InterruptedException ignored) {
+ return false;
+ }
+ }
+ mSurface = new Surface(mSurfaceTexture);
+ }
+ mSurfaceTexture.attachToGLContext(texName);
+ mFrameAvailable = false;
+ mIsAttached = true;
+ return true;
}
@Override
- public void onFrameAvailable(SurfaceTexture surfaceTexture) {
- synchronized (this) {
+ public synchronized void onFrameAvailable(SurfaceTexture surfaceTexture) {
+ if (surfaceTexture == mSurfaceTexture) {
if (mFrameAvailable)
throw new IllegalStateException("An available frame was not updated");
mFrameAvailable = true;
@@ -648,35 +676,46 @@ public class AWindow implements IVLCVout {
Looper.prepare();
synchronized (this) {
+ /* Ideally, all devices are running Android O, and we can create a SurfaceTexture
+ * without an OpenGL context and we can specify the thread (Handler) where to run
+ * SurfaceTexture callbacks. But this is not the case. The SurfaceTexture has to be
+ * created from a new thread with a prepared looper in order to don't use the
+ * MainLooper one (and have deadlock when we stop VLC from the mainloop).
+ */
mLooper = Looper.myLooper();
- mSurfaceTexture = new SurfaceTexture(mTexName);
+ mSurfaceTexture = new SurfaceTexture(0);
+ /* The OpenGL texture will be attached from the OpenGL Thread */
+ mSurfaceTexture.detachFromGLContext();
mSurfaceTexture.setOnFrameAvailableListener(this);
notify();
}
Looper.loop();
-
- mSurfaceTexture.setOnFrameAvailableListener(null);
- mSurfaceTexture.release();
}
- void release() {
- synchronized (this) {
- while (mLooper == null) {
- try {
- wait();
- } catch (InterruptedException ignored) {
- }
+ private synchronized void detachFromGLContext() {
+ if (mDoRelease) {
+ mLooper.quit();
+ mLooper = null;
+
+ try {
+ mThread.join();
+ } catch (InterruptedException ignored) {
}
+ mThread = null;
+
+ mSurface.release();
+ mSurface = null;
+ mSurfaceTexture.release();
+ mSurfaceTexture = null;
+ mDoRelease = false;
+ } else {
+ mSurfaceTexture.detachFromGLContext();
}
- mLooper.quit();
- try {
- join();
- } catch (InterruptedException ignored) {
- }
+ mIsAttached = false;
}
- boolean waitAndUpdateTexImage(float[] transformMatrix) {
+ private boolean waitAndUpdateTexImage(float[] transformMatrix) {
synchronized (this) {
while (!mFrameAvailable) {
try {
@@ -693,41 +732,45 @@ public class AWindow implements IVLCVout {
return true;
}
- Surface getSurface() {
- synchronized (this) {
- while (mSurfaceTexture == null) {
- try {
- wait();
- } catch (InterruptedException ignored) {
- }
+ private synchronized Surface getSurface() {
+ return mSurface;
+ }
+
+ private synchronized void release() {
+ if (mSurfaceTexture != null) {
+ if (mIsAttached) {
+ /* Release from detachFromGLContext */
+ mDoRelease = true;
+ } else {
+ mSurface.release();
+ mSurface = null;
+ mSurfaceTexture.release();
+ mSurfaceTexture = null;
}
- return new Surface(mSurfaceTexture);
}
}
}
/**
- * Create a SurfaceTextureThread
+ * Attach the SurfaceTexture to the OpenGL ES context that is current on the calling thread.
*
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
- * @return a valid and started SurfaceTextureThread
+ * @return true in case of success
*/
@SuppressWarnings("unused") /* used by JNI */
- static private SurfaceTextureThread SurfaceTextureThread_create(int texName) {
- if (AndroidUtil.isICSOrLater) {
- final SurfaceTextureThread st = new SurfaceTextureThread(texName);
- st.start();
- return st;
+ boolean SurfaceTexture_attachToGLContext(int texName) {
+ if (AndroidUtil.isJellyBeanOrLater) {
+ return mSurfaceTextureThread.attachToGLContext(texName);
} else
- return null;
+ return false;
}
/**
- * Release the SurfaceTexture and join the thread
+ * Detach the SurfaceTexture from the OpenGL ES context that owns the OpenGL ES texture object.
*/
@SuppressWarnings("unused") /* used by JNI */
- static private void SurfaceTextureThread_release(SurfaceTextureThread st) {
- st.release();
+ private void SurfaceTexture_detachFromGLContext() {
+ mSurfaceTextureThread.detachFromGLContext();
}
/**
@@ -736,16 +779,15 @@ public class AWindow implements IVLCVout {
* @return true on success, false on error or timeout
*/
@SuppressWarnings("unused") /* used by JNI */
- static private boolean SurfaceTextureThread_waitAndUpdateTexImage(SurfaceTextureThread st,
- float[] transformMatrix) {
- return st.waitAndUpdateTexImage(transformMatrix);
+ private boolean SurfaceTexture_waitAndUpdateTexImage(float[] transformMatrix) {
+ return mSurfaceTextureThread.waitAndUpdateTexImage(transformMatrix);
}
/**
* Get a Surface from the SurfaceTexture
*/
@SuppressWarnings("unused") /* used by JNI */
- static private Surface SurfaceTextureThread_getSurface(SurfaceTextureThread st) {
- return st.getSurface();
+ private Surface SurfaceTexture_getSurface() {
+ return mSurfaceTextureThread.getSurface();
}
-}
\ No newline at end of file
+}
More information about the Android
mailing list