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:
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
package org.webrtc;
|
package org.webrtc;
|
||||||
|
|
||||||
|
import android.graphics.SurfaceTexture;
|
||||||
import android.opengl.EGL14;
|
import android.opengl.EGL14;
|
||||||
import android.opengl.EGLConfig;
|
import android.opengl.EGLConfig;
|
||||||
import android.opengl.EGLContext;
|
import android.opengl.EGLContext;
|
||||||
@ -85,6 +86,19 @@ public final class EglBase {
|
|||||||
|
|
||||||
// Create EGLSurface from the Android Surface.
|
// Create EGLSurface from the Android Surface.
|
||||||
public void createSurface(Surface 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();
|
checkIsNotReleased();
|
||||||
if (configType == ConfigType.PIXEL_BUFFER) {
|
if (configType == ConfigType.PIXEL_BUFFER) {
|
||||||
Logging.w(TAG, "This EGL context is configured for PIXEL_BUFFER, but uses regular Surface");
|
Logging.w(TAG, "This EGL context is configured for PIXEL_BUFFER, but uses regular Surface");
|
||||||
|
@ -35,7 +35,6 @@ import android.os.Build;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -159,20 +158,7 @@ final class SurfaceTextureHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
boolean wasInterrupted = true;
|
ThreadUtils.awaitUninterruptibly(barrier);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryDeliverTextureFrame() {
|
private void tryDeliverTextureFrame() {
|
||||||
@ -195,18 +181,15 @@ final class SurfaceTextureHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void release() {
|
private void release() {
|
||||||
|
if (Thread.currentThread() != thread) {
|
||||||
|
throw new IllegalStateException("Wrong thread.");
|
||||||
|
}
|
||||||
if (isTextureInUse || !isQuitting) {
|
if (isTextureInUse || !isQuitting) {
|
||||||
throw new IllegalStateException("Unexpected release.");
|
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);
|
GLES20.glDeleteTextures(1, new int[] {oesTextureId}, 0);
|
||||||
surfaceTexture.release();
|
surfaceTexture.release();
|
||||||
eglBase.release();
|
eglBase.release();
|
||||||
}
|
|
||||||
});
|
|
||||||
// Quit safely to make sure the clean-up posted above is executed.
|
|
||||||
thread.quitSafely();
|
thread.quitSafely();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,20 +27,32 @@
|
|||||||
|
|
||||||
package org.webrtc;
|
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
|
* Utility interface to be used with executeUninterruptibly() to wait for blocking operations
|
||||||
* used in cases where |thread| is doing some critical work, e.g. cleanup, that must complete
|
* to complete without getting interrupted..
|
||||||
* before returning. The thread interruption flag is set if an interrupt occurs during join().
|
|
||||||
*/
|
*/
|
||||||
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;
|
boolean wasInterrupted = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
thread.join();
|
operation.run();
|
||||||
break;
|
break;
|
||||||
} catch (InterruptedException e) {
|
} 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.
|
// but we should preserve the information and pass it along.
|
||||||
wasInterrupted = true;
|
wasInterrupted = true;
|
||||||
}
|
}
|
||||||
@ -50,4 +62,22 @@ public class ThreadUtils {
|
|||||||
Thread.currentThread().interrupt();
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user