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() {