Android SurfaceTextureHelper: Don't wait for pending frames in disconnect()

This CL also makes some small non-functional changes in ThreadUtils and EglBase to support SurfaceTextures and SurfaceTextureHelper.

BUG=webrtc:4993
R=hbos@webrtc.org

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

Cr-Commit-Position: refs/heads/master@{#10085}
This commit is contained in:
Magnus Jedvert
2015-09-28 11:05:44 +02:00
parent 3e9eb4ba01
commit 1ab271c1c4
3 changed files with 58 additions and 31 deletions

View File

@ -27,6 +27,7 @@
package org.webrtc;
import android.graphics.SurfaceTexture;
import android.opengl.EGL14;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
@ -85,6 +86,19 @@ public final class EglBase {
// Create EGLSurface from the Android Surface.
public void createSurface(Surface surface) {
createSurfaceInternal(surface);
}
// Create EGLSurface from the Android SurfaceTexture.
public void createSurface(SurfaceTexture surfaceTexture) {
createSurfaceInternal(surfaceTexture);
}
// Create EGLSurface from either Surface or SurfaceTexture.
private void createSurfaceInternal(Object surface) {
if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture)) {
throw new IllegalStateException("Input must be either a Surface or SurfaceTexture");
}
checkIsNotReleased();
if (configType == ConfigType.PIXEL_BUFFER) {
Logging.w(TAG, "This EGL context is configured for PIXEL_BUFFER, but uses regular Surface");

View File

@ -35,7 +35,6 @@ import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
import android.util.Log;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@ -159,20 +158,7 @@ final class SurfaceTextureHelper {
}
}
});
boolean wasInterrupted = true;
while(true) {
try {
barrier.await();
break;
} catch (InterruptedException e) {
// Someone is asking us to return early at our convenience. We must wait until the
// |isQuitting| flag has been set but we should preserve the information and pass it along.
wasInterrupted = true;
}
}
if (wasInterrupted) {
Thread.currentThread().interrupt();
}
ThreadUtils.awaitUninterruptibly(barrier);
}
private void tryDeliverTextureFrame() {
@ -195,18 +181,15 @@ final class SurfaceTextureHelper {
}
private void release() {
if (Thread.currentThread() != thread) {
throw new IllegalStateException("Wrong thread.");
}
if (isTextureInUse || !isQuitting) {
throw new IllegalStateException("Unexpected release.");
}
// Release GL resources on dedicated thread.
handler.post(new Runnable() {
@Override public void run() {
GLES20.glDeleteTextures(1, new int[] {oesTextureId}, 0);
surfaceTexture.release();
eglBase.release();
}
});
// Quit safely to make sure the clean-up posted above is executed.
GLES20.glDeleteTextures(1, new int[] {oesTextureId}, 0);
surfaceTexture.release();
eglBase.release();
thread.quitSafely();
}
}

View File

@ -27,20 +27,32 @@
package org.webrtc;
public class ThreadUtils {
import java.util.concurrent.CountDownLatch;
final class ThreadUtils {
/**
* Helper function to make sure a thread is joined without getting interrupted. This should be
* used in cases where |thread| is doing some critical work, e.g. cleanup, that must complete
* before returning. The thread interruption flag is set if an interrupt occurs during join().
* Utility interface to be used with executeUninterruptibly() to wait for blocking operations
* to complete without getting interrupted..
*/
public static void joinUninterruptibly(Thread thread) {
public interface BlockingOperation {
void run() throws InterruptedException;
}
/**
* Utility method to make sure a blocking operation is executed to completion without getting
* interrupted. This should be used in cases where the operation is waiting for some critical
* work, e.g. cleanup, that must complete before returning. If the thread is interrupted during
* the blocking operation, this function will re-run the operation until completion, and only then
* re-interrupt the thread.
*/
public static void executeUninterruptibly(BlockingOperation operation) {
boolean wasInterrupted = false;
while (true) {
try {
thread.join();
operation.run();
break;
} catch (InterruptedException e) {
// Someone is asking us to return early at our convenience. We can't cancel this join(),
// Someone is asking us to return early at our convenience. We can't cancel this operation,
// but we should preserve the information and pass it along.
wasInterrupted = true;
}
@ -50,4 +62,22 @@ public class ThreadUtils {
Thread.currentThread().interrupt();
}
}
public static void joinUninterruptibly(final Thread thread) {
executeUninterruptibly(new BlockingOperation() {
@Override
public void run() throws InterruptedException {
thread.join();
}
});
}
public static void awaitUninterruptibly(final CountDownLatch latch) {
executeUninterruptibly(new BlockingOperation() {
@Override
public void run() throws InterruptedException {
latch.await();
}
});
}
}