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