| Index: ui/android/java/src/org/chromium/ui/gl/SurfaceTexturePlatformWrapper.java
|
| diff --git a/ui/android/java/src/org/chromium/ui/gl/SurfaceTexturePlatformWrapper.java b/ui/android/java/src/org/chromium/ui/gl/SurfaceTexturePlatformWrapper.java
|
| index c6197861feeda88b20cc5629536ae3bca98bd430..0f20798433db3c3fa9194ad0c5ca9a11bc09c17c 100644
|
| --- a/ui/android/java/src/org/chromium/ui/gl/SurfaceTexturePlatformWrapper.java
|
| +++ b/ui/android/java/src/org/chromium/ui/gl/SurfaceTexturePlatformWrapper.java
|
| @@ -4,20 +4,38 @@
|
|
|
| package org.chromium.ui.gl;
|
|
|
| +import android.annotation.SuppressLint;
|
| import android.graphics.SurfaceTexture;
|
| -import android.util.Log;
|
| +import android.os.Build;
|
| +import android.os.Handler;
|
| +import android.os.Looper;
|
|
|
| +import org.chromium.base.Log;
|
| import org.chromium.base.annotations.CalledByNative;
|
| import org.chromium.base.annotations.JNINamespace;
|
|
|
| +import java.util.HashSet;
|
| +
|
| /**
|
| * Wrapper class for the underlying platform's SurfaceTexture in order to
|
| * provide a stable JNI API.
|
| */
|
| @JNINamespace("gfx")
|
| class SurfaceTexturePlatformWrapper {
|
| + // Truncated to fit into 20 character max.
|
| + private static final String TAG = "SurfaceTexturePlat";
|
| +
|
| + // Thread for callbacks for those SurfaceTextures that request a separate
|
| + // thread to receive them on. This may be shared by multiple STs.
|
| + private static CallbackThread sCallbackThread;
|
|
|
| - private static final String TAG = "SurfaceTexturePlatformWrapper";
|
| + // Handler for OnFrameAvailable listeners on sCallbackThread. This will be
|
| + // null if no thread is currently running. See ensureHandler().
|
| + private static Handler sCallbackHandler;
|
| +
|
| + // Set of SurfaceTextures that are using sCallbackThread, so that we know
|
| + // when to stop it.
|
| + private static HashSet<SurfaceTexture> sThreadTextures = new HashSet<SurfaceTexture>();
|
|
|
| @CalledByNative
|
| private static SurfaceTexture create(int textureId) {
|
| @@ -27,6 +45,7 @@ class SurfaceTexturePlatformWrapper {
|
| @CalledByNative
|
| private static void destroy(SurfaceTexture surfaceTexture) {
|
| surfaceTexture.setOnFrameAvailableListener(null);
|
| + removeFromCallbackSet(surfaceTexture);
|
| surfaceTexture.release();
|
| }
|
|
|
| @@ -35,6 +54,22 @@ class SurfaceTexturePlatformWrapper {
|
| long nativeSurfaceTextureListener) {
|
| surfaceTexture.setOnFrameAvailableListener(
|
| new SurfaceTextureListener(nativeSurfaceTextureListener));
|
| + removeFromCallbackSet(surfaceTexture);
|
| + }
|
| +
|
| + @SuppressLint("NewApi")
|
| + @CalledByNative
|
| + private static void setFrameAvailableCallbackOnSeparateThread(
|
| + SurfaceTexture surfaceTexture, long nativeSurfaceTextureListener) {
|
| + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
| + ensureHandler(surfaceTexture);
|
| + surfaceTexture.setOnFrameAvailableListener(
|
| + new SurfaceTextureListener(nativeSurfaceTextureListener), sCallbackHandler);
|
| + } else {
|
| + Log.e(TAG, "Separate thread not supported, using default");
|
| + surfaceTexture.setOnFrameAvailableListener(
|
| + new SurfaceTextureListener(nativeSurfaceTextureListener), sCallbackHandler);
|
| + }
|
| }
|
|
|
| @CalledByNative
|
| @@ -60,4 +95,74 @@ class SurfaceTexturePlatformWrapper {
|
| private static void detachFromGLContext(SurfaceTexture surfaceTexture) {
|
| surfaceTexture.detachFromGLContext();
|
| }
|
| +
|
| + // Implement something similar to HandlerThread. The difference is that
|
| + // this uses only one thread, while HandlerThread seems to spin up several
|
| + // for unclear reasons.
|
| + private static class CallbackThread extends Thread {
|
| + private Handler mCallbackHandler;
|
| + private Looper mLooper;
|
| +
|
| + public CallbackThread() {
|
| + super("SurfaceTextureCallbackThread");
|
| + }
|
| +
|
| + public void run() {
|
| + Looper.prepare();
|
| + mLooper = Looper.myLooper();
|
| + mCallbackHandler = new Handler(mLooper);
|
| + synchronized (this) {
|
| + notifyAll();
|
| + }
|
| + Looper.loop();
|
| + }
|
| +
|
| + public synchronized void start() {
|
| + super.start();
|
| + // Make sure that mCallbackHandler is initialized.
|
| + try {
|
| + wait();
|
| + } catch (InterruptedException e) {
|
| + Log.e(TAG, "Interrupted while starting callback thread", e);
|
| + }
|
| + }
|
| +
|
| + public Handler getHandler() {
|
| + return mCallbackHandler;
|
| + }
|
| +
|
| + public void quit() {
|
| + mLooper.quit();
|
| + try {
|
| + join();
|
| + } catch (InterruptedException e) {
|
| + Log.e(TAG, "Interrupted while stopping callback thread", e);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Ensure that there's a callback thread to handle onFrameAvailable
|
| + // callbacks for |surfaceTexture|.
|
| + private static void ensureHandler(SurfaceTexture surfaceTexture) {
|
| + sThreadTextures.add(surfaceTexture);
|
| +
|
| + // Start the thread if needed.
|
| + if (sCallbackHandler != null) return;
|
| +
|
| + sCallbackThread = new CallbackThread();
|
| + sCallbackThread.start();
|
| + sCallbackHandler = sCallbackThread.getHandler();
|
| + }
|
| +
|
| + private static void removeFromCallbackSet(SurfaceTexture surfaceTexture) {
|
| + // |surfaceTexture| might not be in the set, which is okay.
|
| + sThreadTextures.remove(surfaceTexture);
|
| +
|
| + if (sCallbackHandler != null && sThreadTextures.isEmpty()) {
|
| + // Nobody is using the thread, so tear it down.
|
| + sCallbackThread.quit();
|
| + sCallbackHandler = null;
|
| + sCallbackThread = null;
|
| + }
|
| + }
|
| }
|
|
|