Add SurfaceTextureHelper.disconnect(Handler handler) method

This method should be used when the SurfaceTextureHelper is created to use a specific handler.
This now guarantee that the looper used by handler is destroyed after a frame has been returned.

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

Cr-Commit-Position: refs/heads/master@{#10767}
This commit is contained in:
perkj 2015-11-24 03:03:13 -08:00 committed by Commit bot
parent d48015364d
commit 9237559b16
3 changed files with 57 additions and 9 deletions

View File

@ -313,7 +313,42 @@ public final class SurfaceTextureHelperTest extends ActivityTestCase {
// Return the frame from this thread.
surfaceTextureHelper.returnTextureFrame();
surfaceTextureHelper.disconnect();
thread.quitSafely();
surfaceTextureHelper.disconnect(handler);
}
/**
* Test use SurfaceTextureHelper on a separate thread. A uniform texture frame is created and
* received on a thread separate from the test thread and returned after disconnect.
*/
@MediumTest
public static void testLateReturnFrameOnSeparateThread() throws InterruptedException {
final HandlerThread thread = new HandlerThread("SurfaceTextureHelperTestThread");
thread.start();
final Handler handler = new Handler(thread.getLooper());
// Create SurfaceTextureHelper and listener.
final SurfaceTextureHelper surfaceTextureHelper =
SurfaceTextureHelper.create(EGL10.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);
// Create resources for stubbing an OES texture producer. |eglOesBase| has the
// SurfaceTexture in |surfaceTextureHelper| as the target EGLSurface.
final EglBase eglOesBase = new EglBase(EGL10.EGL_NO_CONTEXT, EglBase.ConfigType.PLAIN);
eglOesBase.createSurface(surfaceTextureHelper.getSurfaceTexture());
eglOesBase.makeCurrent();
// Draw a frame onto the SurfaceTexture.
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// swapBuffers() will ultimately trigger onTextureFrameAvailable().
eglOesBase.swapBuffers();
eglOesBase.release();
// Wait for an OES texture to arrive.
listener.waitForNewFrame();
surfaceTextureHelper.disconnect(handler);
surfaceTextureHelper.returnTextureFrame();
}
}

View File

@ -95,7 +95,7 @@ class SurfaceTextureHelper {
}
private final Handler handler;
private final boolean isOwningThread;
private boolean isOwningThread;
private final EglBase eglBase;
private final SurfaceTexture surfaceTexture;
private final int oesTextureId;
@ -170,6 +170,9 @@ class SurfaceTextureHelper {
* onTextureFrameAvailable() after this function returns.
*/
public void disconnect() {
if (!isOwningThread) {
throw new IllegalStateException("Must call disconnect(handler).");
}
if (handler.getLooper().getThread() == Thread.currentThread()) {
isQuitting = true;
if (!isTextureInUse) {
@ -190,6 +193,20 @@ class SurfaceTextureHelper {
ThreadUtils.awaitUninterruptibly(barrier);
}
/**
* Call disconnect() to stop receiving frames and quit the looper used by |handler|.
* Resources are released when the texture frame has been returned by a call to
* returnTextureFrame(). You are guaranteed to not receive any more
* onTextureFrameAvailable() after this function returns.
*/
public void disconnect(Handler handler) {
if (this.handler != handler) {
throw new IllegalStateException("Wrong handler.");
}
isOwningThread = true;
disconnect();
}
private void tryDeliverTextureFrame() {
if (handler.getLooper().getThread() != Thread.currentThread()) {
throw new IllegalStateException("Wrong thread.");
@ -222,8 +239,6 @@ class SurfaceTextureHelper {
GLES20.glDeleteTextures(1, new int[] {oesTextureId}, 0);
surfaceTexture.release();
eglBase.release();
if (isOwningThread) {
handler.getLooper().quit();
}
handler.getLooper().quit();
}
}

View File

@ -407,9 +407,7 @@ public class VideoCapturerAndroid extends VideoCapturer implements
}
}
});
surfaceHelper.disconnect();
cameraThread.quit();
ThreadUtils.joinUninterruptibly(cameraThread);
surfaceHelper.disconnect(cameraThreadHandler);
cameraThread = null;
}