Android SurfaceTextureHelper: Replace API 21 with API 11 version of setOnFrameAvailableListener()

BUG=b/24809429
R=glaznev@webrtc.org, perkj@webrtc.org

Review URL: https://codereview.webrtc.org/1395543004 .

Cr-Commit-Position: refs/heads/master@{#10247}
This commit is contained in:
Magnus Jedvert 2015-10-12 09:27:48 +02:00
parent e9e3668759
commit 747c1bccd9
5 changed files with 62 additions and 47 deletions

View File

@ -271,7 +271,7 @@ public final class GlRectDrawerTest extends ActivityTestCase {
// Create resources for generating OES textures.
final SurfaceTextureHelper surfaceTextureHelper =
new SurfaceTextureHelper(eglBase.getContext());
SurfaceTextureHelper.create(eglBase.getContext());
final StubOesTextureProducer oesProducer = new StubOesTextureProducer(
eglBase.getContext(), surfaceTextureHelper.getSurfaceTexture(), WIDTH, HEIGHT);
final SurfaceTextureHelperTest.MockTextureListener listener =

View File

@ -32,6 +32,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.graphics.SurfaceTexture;
import android.opengl.EGL14;
import android.opengl.GLES20;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
@ -113,7 +114,7 @@ public final class SurfaceTextureHelperTest extends ActivityTestCase {
// Create SurfaceTextureHelper and listener.
final SurfaceTextureHelper surfaceTextureHelper =
new SurfaceTextureHelper(eglBase.getContext());
SurfaceTextureHelper.create(eglBase.getContext());
final MockTextureListener listener = new MockTextureListener();
surfaceTextureHelper.setListener(listener);
surfaceTextureHelper.getSurfaceTexture().setDefaultBufferSize(width, height);
@ -179,7 +180,7 @@ public final class SurfaceTextureHelperTest extends ActivityTestCase {
// Create SurfaceTextureHelper and listener.
final SurfaceTextureHelper surfaceTextureHelper =
new SurfaceTextureHelper(eglBase.getContext());
SurfaceTextureHelper.create(eglBase.getContext());
final MockTextureListener listener = new MockTextureListener();
surfaceTextureHelper.setListener(listener);
surfaceTextureHelper.getSurfaceTexture().setDefaultBufferSize(width, height);
@ -238,7 +239,7 @@ public final class SurfaceTextureHelperTest extends ActivityTestCase {
public static void testDisconnect() throws InterruptedException {
// Create SurfaceTextureHelper and listener.
final SurfaceTextureHelper surfaceTextureHelper =
new SurfaceTextureHelper(EGL14.EGL_NO_CONTEXT);
SurfaceTextureHelper.create(EGL14.EGL_NO_CONTEXT);
final MockTextureListener listener = new MockTextureListener();
surfaceTextureHelper.setListener(listener);
// Create EglBase with the SurfaceTexture as target EGLSurface.
@ -274,7 +275,7 @@ public final class SurfaceTextureHelperTest extends ActivityTestCase {
@SmallTest
public static void testDisconnectImmediately() {
final SurfaceTextureHelper surfaceTextureHelper =
new SurfaceTextureHelper(EGL14.EGL_NO_CONTEXT);
SurfaceTextureHelper.create(EGL14.EGL_NO_CONTEXT);
surfaceTextureHelper.disconnect();
}
@ -286,10 +287,11 @@ public final class SurfaceTextureHelperTest extends ActivityTestCase {
public static void testFrameOnSeparateThread() throws InterruptedException {
final HandlerThread thread = new HandlerThread("SurfaceTextureHelperTestThread");
thread.start();
final Handler handler = new Handler(thread.getLooper());
// Create SurfaceTextureHelper and listener.
final SurfaceTextureHelper surfaceTextureHelper =
new SurfaceTextureHelper(EGL14.EGL_NO_CONTEXT, thread);
SurfaceTextureHelper.create(EGL14.EGL_NO_CONTEXT, handler);
// Create a mock listener and expect frames to be delivered on |thread|.
final MockTextureListener listener = new MockTextureListener(thread);
surfaceTextureHelper.setListener(listener);

View File

@ -36,6 +36,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -63,7 +64,35 @@ final class SurfaceTextureHelper {
int oesTextureId, float[] transformMatrix, long timestampNs);
}
private final HandlerThread thread;
public static SurfaceTextureHelper create(EGLContext sharedContext) {
return create(sharedContext, null);
}
/**
* Construct a new SurfaceTextureHelper sharing OpenGL resources with |sharedContext|. If
* |handler| is non-null, the callback will be executed on that handler's thread. If |handler| is
* null, a dedicated private thread is created for the callbacks.
*/
public static SurfaceTextureHelper create(final EGLContext sharedContext, final Handler handler) {
final Handler finalHandler;
if (handler != null) {
finalHandler = handler;
} else {
final HandlerThread thread = new HandlerThread(TAG);
thread.start();
finalHandler = new Handler(thread.getLooper());
}
// The onFrameAvailable() callback will be executed on the SurfaceTexture ctor thread. See:
// http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/graphics/SurfaceTexture.java#195.
// Therefore, in order to control the callback thread on API lvl < 21, the SurfaceTextureHelper
// is constructed on the |handler| thread.
return ThreadUtils.invokeUninterruptibly(finalHandler, new Callable<SurfaceTextureHelper>() {
@Override public SurfaceTextureHelper call() {
return new SurfaceTextureHelper(sharedContext, finalHandler, (handler == null));
}
});
}
private final Handler handler;
private final boolean isOwningThread;
private final EglBase eglBase;
@ -75,23 +104,12 @@ final class SurfaceTextureHelper {
private boolean isTextureInUse = false;
private boolean isQuitting = false;
/**
* Construct a new SurfaceTextureHelper sharing OpenGL resources with |sharedContext|.
*/
public SurfaceTextureHelper(EGLContext sharedContext) {
this(sharedContext, null);
}
public SurfaceTextureHelper(EGLContext sharedContext, HandlerThread thread) {
if (thread == null) {
this.thread = new HandlerThread(TAG);
this.thread.start();
this.isOwningThread = true;
} else {
this.thread = thread;
this.isOwningThread = false;
private SurfaceTextureHelper(EGLContext sharedContext, Handler handler, boolean isOwningThread) {
if (!handler.getLooper().isCurrentThread()) {
throw new IllegalStateException("SurfaceTextureHelper must be created on the handler thread");
}
this.handler = new Handler(this.thread.getLooper());
this.handler = handler;
this.isOwningThread = isOwningThread;
eglBase = new EglBase(sharedContext, EglBase.ConfigType.PIXEL_BUFFER);
eglBase.createDummyPbufferSurface();
@ -99,9 +117,6 @@ final class SurfaceTextureHelper {
oesTextureId = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
surfaceTexture = new SurfaceTexture(oesTextureId);
// The EGL context will be re-attached to the private thread.
eglBase.detachCurrent();
}
/**
@ -119,7 +134,7 @@ final class SurfaceTextureHelper {
hasPendingTexture = true;
tryDeliverTextureFrame();
}
}, handler);
});
}
/**
@ -154,7 +169,7 @@ final class SurfaceTextureHelper {
* onTextureFrameAvailable() after this function returns.
*/
public void disconnect() {
if (Thread.currentThread() == thread) {
if (handler.getLooper().isCurrentThread()) {
isQuitting = true;
if (!isTextureInUse) {
release();
@ -175,7 +190,7 @@ final class SurfaceTextureHelper {
}
private void tryDeliverTextureFrame() {
if (Thread.currentThread() != thread) {
if (!handler.getLooper().isCurrentThread()) {
throw new IllegalStateException("Wrong thread.");
}
if (isQuitting || !hasPendingTexture || isTextureInUse) {
@ -196,7 +211,7 @@ final class SurfaceTextureHelper {
}
private void release() {
if (Thread.currentThread() != thread) {
if (!handler.getLooper().isCurrentThread()) {
throw new IllegalStateException("Wrong thread.");
}
if (isTextureInUse || !isQuitting) {
@ -207,7 +222,7 @@ final class SurfaceTextureHelper {
surfaceTexture.release();
eglBase.release();
if (isOwningThread) {
thread.quitSafely();
handler.getLooper().quitSafely();
}
}
}

View File

@ -314,9 +314,8 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba
cameraThread.start();
cameraThreadHandler = new Handler(cameraThread.getLooper());
videoBuffers = new FramePool(cameraThread);
surfaceHelper =
new SurfaceTextureHelper(sharedContext == null ? EGL14.EGL_NO_CONTEXT : sharedContext,
cameraThread);
surfaceHelper = SurfaceTextureHelper.create(
sharedContext == null ? EGL14.EGL_NO_CONTEXT : sharedContext, cameraThreadHandler);
if (sharedContext != null) {
surfaceHelper.setListener(this);
}

View File

@ -64,19 +64,18 @@ SurfaceTextureHelper::SurfaceTextureHelper(JNIEnv* jni,
: j_surface_texture_helper_class_(
jni,
FindClass(jni, "org/webrtc/SurfaceTextureHelper")),
j_surface_texture_helper_(
jni,
jni->NewObject(*j_surface_texture_helper_class_,
GetMethodID(jni,
*j_surface_texture_helper_class_,
"<init>",
"(Landroid/opengl/EGLContext;)V"),
egl_shared_context)),
j_return_texture_method_(
GetMethodID(jni,
*j_surface_texture_helper_class_,
"returnTextureFrame",
"()V")) {
j_surface_texture_helper_(jni, jni->CallStaticObjectMethod(
*j_surface_texture_helper_class_,
GetStaticMethodID(
jni,
*j_surface_texture_helper_class_,
"create",
"(Landroid/opengl/EGLContext;)Lorg/webrtc/SurfaceTextureHelper;"),
egl_shared_context)),
j_return_texture_method_(GetMethodID(jni,
*j_surface_texture_helper_class_,
"returnTextureFrame",
"()V")) {
CHECK_EXCEPTION(jni) << "error during initialization of SurfaceTextureHelper";
}