From 73f44f6481b2a767c80693224ec3b334c26bc4e7 Mon Sep 17 00:00:00 2001 From: perkj Date: Tue, 13 Oct 2015 08:15:05 -0700 Subject: [PATCH] VideoCapturerAndroid, only you SurfaceViewHelper when capturing to textures. SurfaceViewHelper requires EGL14 that was added in API level 17. Since the SurfaceViewHelper is only neeed when we capture to textures, this cl change back to not use it when we are capturing to byte buffers. Also, thread.quitsafely was added in level 18. Instead a new ThreadUtil method has been added for this. BUG=b/24782220 TEST = run ninja -C out/Debug libjingle_peerconnection_android_unittest && CHECKOUT_SOURCE_ROOT=`pwd` build/android/adb_install_apk.py --debug out/Debug/apks/libjingle_peerconnection_android_unittest.apk && ./third_party/android_tools/sdk/platform-tools/adb shell am instrument -w -e class org.webrtc.VideoCapturerAndroidTest org.webrtc.test/android.test.InstrumentationTestRunner on a device running Android 4.1 (I tried Nexus 7, the first version) Review URL: https://codereview.webrtc.org/1401023003 Cr-Commit-Position: refs/heads/master@{#10265} --- .../webrtc/androidtests/AndroidManifest.xml | 2 +- .../org/webrtc/VideoCapturerAndroidTest.java | 37 ++++++++++++++ .../java/android/org/webrtc/ThreadUtils.java | 14 ++++++ .../org/webrtc/VideoCapturerAndroid.java | 50 +++++++++++++++---- 4 files changed, 91 insertions(+), 12 deletions(-) diff --git a/talk/app/webrtc/androidtests/AndroidManifest.xml b/talk/app/webrtc/androidtests/AndroidManifest.xml index a22611f292..ef6beb8f23 100644 --- a/talk/app/webrtc/androidtests/AndroidManifest.xml +++ b/talk/app/webrtc/androidtests/AndroidManifest.xml @@ -7,7 +7,7 @@ - + diff --git a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java index c139e2f303..1dea3bfdbc 100644 --- a/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java +++ b/talk/app/webrtc/androidtests/src/org/webrtc/VideoCapturerAndroidTest.java @@ -27,17 +27,22 @@ package org.webrtc; import android.opengl.EGL14; +import android.os.Build; import android.test.ActivityTestCase; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; import android.util.Size; import org.webrtc.CameraEnumerationAndroid.CaptureFormat; + import java.util.HashSet; import java.util.Set; @SuppressWarnings("deprecation") public class VideoCapturerAndroidTest extends ActivityTestCase { + static final String TAG = "VideoCapturerAndroidTest"; + @Override protected void setUp() { assertTrue(PeerConnectionFactory.initializeAndroidGlobals( @@ -82,6 +87,10 @@ public class VideoCapturerAndroidTest extends ActivityTestCase { @SmallTest public void testCreateAndReleaseUsingTextures() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + Log.i(TAG, "Capturing to textures is not supported, requires EGL14."); + return; + } VideoCapturerAndroidTestFixtures.release( VideoCapturerAndroid.create("", null, EGL14.EGL_NO_CONTEXT)); } @@ -105,6 +114,10 @@ public class VideoCapturerAndroidTest extends ActivityTestCase { @SmallTest public void testStartVideoCapturerUsingTextures() throws InterruptedException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + Log.i(TAG, "Capturing to textures is not supported, requires EGL14."); + return; + } VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null, EGL14.EGL_NO_CONTEXT); VideoCapturerAndroidTestFixtures.startCapturerAndRender(capturer); @@ -147,6 +160,10 @@ public class VideoCapturerAndroidTest extends ActivityTestCase { @SmallTest public void testSwitchVideoCapturerUsingTextures() throws InterruptedException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + Log.i(TAG, "Capturing to textures is not supported, requires EGL14."); + return; + } VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null, EGL14.EGL_NO_CONTEXT); VideoCapturerAndroidTestFixtures.switchCamera(capturer); } @@ -163,6 +180,10 @@ public class VideoCapturerAndroidTest extends ActivityTestCase { @MediumTest public void testCameraCallsAfterStopUsingTextures() throws InterruptedException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + Log.i(TAG, "Capturing to textures is not supported, requires EGL14."); + return; + } final String deviceName = CameraEnumerationAndroid.getDeviceName(0); final VideoCapturerAndroid capturer = VideoCapturerAndroid.create(deviceName, null, EGL14.EGL_NO_CONTEXT); @@ -181,6 +202,10 @@ public class VideoCapturerAndroidTest extends ActivityTestCase { @SmallTest public void testStopRestartVideoSourceUsingTextures() throws InterruptedException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + Log.i(TAG, "Capturing to textures is not supported, requires EGL14."); + return; + } VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null, EGL14.EGL_NO_CONTEXT); VideoCapturerAndroidTestFixtures.stopRestartVideoSource(capturer); } @@ -198,6 +223,10 @@ public class VideoCapturerAndroidTest extends ActivityTestCase { @SmallTest public void testStartStopWithDifferentResolutionsUsingTextures() throws InterruptedException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + Log.i(TAG, "Capturing to textures is not supported, requires EGL14."); + return; + } String deviceName = CameraEnumerationAndroid.getDeviceName(0); VideoCapturerAndroid capturer = VideoCapturerAndroid.create(deviceName, null, EGL14.EGL_NO_CONTEXT); @@ -218,6 +247,10 @@ public class VideoCapturerAndroidTest extends ActivityTestCase { @SmallTest public void testReturnBufferLateUsingTextures() throws InterruptedException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + Log.i(TAG, "Capturing to textures is not supported, requires EGL14."); + return; + } String deviceName = CameraEnumerationAndroid.getDeviceName(0); VideoCapturerAndroid capturer = VideoCapturerAndroid.create(deviceName, null, EGL14.EGL_NO_CONTEXT); @@ -236,6 +269,10 @@ public class VideoCapturerAndroidTest extends ActivityTestCase { @MediumTest public void testReturnBufferLateEndToEndUsingTextures() throws InterruptedException { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + Log.i(TAG, "Capturing to textures is not supported, requires EGL14."); + return; + } final VideoCapturerAndroid capturer = VideoCapturerAndroid.create("", null, EGL14.EGL_NO_CONTEXT); VideoCapturerAndroidTestFixtures.returnBufferLateEndToEnd(capturer); diff --git a/talk/app/webrtc/java/android/org/webrtc/ThreadUtils.java b/talk/app/webrtc/java/android/org/webrtc/ThreadUtils.java index 33402f700b..0d8968aba9 100644 --- a/talk/app/webrtc/java/android/org/webrtc/ThreadUtils.java +++ b/talk/app/webrtc/java/android/org/webrtc/ThreadUtils.java @@ -126,4 +126,18 @@ final class ThreadUtils { awaitUninterruptibly(barrier); return result.value; } + + /** + * Post |runner| to |handler| and wait for the result. + */ + public static void invokeUninterruptibly(final Handler handler, final Runnable runner) { + final CountDownLatch barrier = new CountDownLatch(1); + handler.post(new Runnable() { + @Override public void run() { + runner.run(); + barrier.countDown(); + } + }); + awaitUninterruptibly(barrier); + } } diff --git a/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java b/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java index 27a7d9ba2d..50fbdf9f75 100644 --- a/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java +++ b/talk/app/webrtc/java/android/org/webrtc/VideoCapturerAndroid.java @@ -28,10 +28,13 @@ package org.webrtc; import android.content.Context; +import android.graphics.SurfaceTexture; import android.hardware.Camera; import android.hardware.Camera.PreviewCallback; import android.opengl.EGL14; import android.opengl.EGLContext; +import android.opengl.GLES11Ext; +import android.opengl.GLES20; import android.os.Handler; import android.os.HandlerThread; import android.os.SystemClock; @@ -92,6 +95,14 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba private CapturerObserver frameObserver = null; private final CameraErrorHandler errorHandler; private final boolean isCapturingToTexture; + // |cameraGlTexture| is used with setPreviewTexture if the capturer is capturing to + // ByteBuffers. + private int cameraGlTexture; + // |cameraSurfaceTexture| is used with setPreviewTexture if the capturer is capturing to + // ByteBuffers. Must be a member, see issue webrtc:5021. + private SurfaceTexture cameraSurfaceTexture; + //|surfaceHelper| is used if the capturer is capturing to a texture. Capturing to textures require + // API level 17. private final SurfaceTextureHelper surfaceHelper; // The camera API can output one old frame after the camera has been switched or the resolution // has been changed. This flag is used for dropping the first frame after camera restart. @@ -204,14 +215,14 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba } public static VideoCapturerAndroid create(String name, - CameraErrorHandler errorHandler, EGLContext sharedContext) { + CameraErrorHandler errorHandler, Object sharedEglContext) { final int cameraId = lookupDeviceName(name); if (cameraId == -1) { return null; } final VideoCapturerAndroid capturer = new VideoCapturerAndroid(cameraId, errorHandler, - sharedContext); + sharedEglContext); capturer.setNativeCapturer(nativeCreateVideoCapturer(capturer)); return capturer; } @@ -317,7 +328,7 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba } private VideoCapturerAndroid(int cameraId, CameraErrorHandler errorHandler, - EGLContext sharedContext) { + Object sharedContext) { Logging.d(TAG, "VideoCapturerAndroid"); this.id = cameraId; this.errorHandler = errorHandler; @@ -325,12 +336,14 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba cameraThread.start(); cameraThreadHandler = new Handler(cameraThread.getLooper()); videoBuffers = new FramePool(cameraThread); - surfaceHelper = SurfaceTextureHelper.create( - sharedContext == null ? EGL14.EGL_NO_CONTEXT : sharedContext, cameraThreadHandler); if (sharedContext != null) { + surfaceHelper = SurfaceTextureHelper.create((EGLContext)sharedContext, cameraThreadHandler); surfaceHelper.setListener(this); + isCapturingToTexture = true; + } else { + surfaceHelper = null; + isCapturingToTexture = false; } - isCapturingToTexture = sharedContext != null; } private void checkIsOnCameraThread() { @@ -364,7 +377,7 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba if (isReleased()) { throw new IllegalStateException("Already released"); } - cameraThreadHandler.post(new Runnable() { + ThreadUtils.invokeUninterruptibly(cameraThreadHandler, new Runnable() { @Override public void run() { if (camera != null) { @@ -375,9 +388,10 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba } } }); - surfaceHelper.disconnect(); - - cameraThread.quitSafely(); + if (isCapturingToTexture) { + surfaceHelper.disconnect(); + } + cameraThread.quit(); ThreadUtils.joinUninterruptibly(cameraThread); cameraThread = null; } @@ -428,7 +442,13 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba Camera.getCameraInfo(id, info); } try { - camera.setPreviewTexture(surfaceHelper.getSurfaceTexture()); + if (isCapturingToTexture) { + camera.setPreviewTexture(surfaceHelper.getSurfaceTexture()); + } else { + cameraGlTexture = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); + cameraSurfaceTexture = new SurfaceTexture(cameraGlTexture); + camera.setPreviewTexture(cameraSurfaceTexture); + } } catch (IOException e) { Logging.e(TAG, "setPreviewTexture failed", error); throw new RuntimeException(e); @@ -568,6 +588,14 @@ public class VideoCapturerAndroid extends VideoCapturer implements PreviewCallba Logging.d(TAG, "Release camera."); camera.release(); camera = null; + + if (cameraGlTexture != 0) { + GLES20.glDeleteTextures(1, new int[] {cameraGlTexture}, 0); + cameraGlTexture = 0; + } + if (cameraSurfaceTexture != null) { + cameraSurfaceTexture.release(); + } } private void switchCameraOnCameraThread() {