Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(168)

Unified Diff: webrtc/api/android/java/src/org/webrtc/VideoCapturerAndroid.java

Issue 2122693002: Android: Add initialize() function to VideoCapturer interface (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Move init member variables to separate section Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/api/android/java/src/org/webrtc/VideoCapturerAndroid.java
diff --git a/webrtc/api/android/java/src/org/webrtc/VideoCapturerAndroid.java b/webrtc/api/android/java/src/org/webrtc/VideoCapturerAndroid.java
index 8f6f911b1da3c2c7a19035b6da2509ed020bd948..1e9c7ee712c2457620ab30ea69c16bf8030a62a1 100644
--- a/webrtc/api/android/java/src/org/webrtc/VideoCapturerAndroid.java
+++ b/webrtc/api/android/java/src/org/webrtc/VideoCapturerAndroid.java
@@ -23,6 +23,7 @@ import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -43,15 +44,14 @@ public class VideoCapturerAndroid implements
CameraVideoCapturer,
android.hardware.Camera.PreviewCallback,
SurfaceTextureHelper.OnTextureFrameAvailableListener {
- private final static String TAG = "VideoCapturerAndroid";
+ private static final String TAG = "VideoCapturerAndroid";
private static final int CAMERA_STOP_TIMEOUT_MS = 7000;
private android.hardware.Camera camera; // Only non-null while capturing.
- private final Object handlerLock = new Object();
- // |cameraThreadHandler| must be synchronized on |handlerLock| when not on the camera thread,
- // or when modifying the reference. Use maybePostOnCameraThread() instead of posting directly to
- // the handler - this way all callbacks with a specifed token can be removed at once.
- private Handler cameraThreadHandler;
+ private final AtomicBoolean isCameraRunning = new AtomicBoolean();
+ // Use maybePostOnCameraThread() instead of posting directly to the handler - this way all
+ // callbacks with a specifed token can be removed at once.
+ private volatile Handler cameraThreadHandler;
private Context applicationContext;
// Synchronization lock for |id|.
private final Object cameraIdLock = new Object();
@@ -117,10 +117,8 @@ public class VideoCapturerAndroid implements
public void printStackTrace() {
Thread cameraThread = null;
- synchronized (handlerLock) {
- if (cameraThreadHandler != null) {
- cameraThread = cameraThreadHandler.getLooper().getThread();
- }
+ if (cameraThreadHandler != null) {
+ cameraThread = cameraThreadHandler.getLooper().getThread();
}
if (cameraThread != null) {
StackTraceElement[] cameraStackTraces = cameraThread.getStackTrace();
@@ -232,12 +230,10 @@ public class VideoCapturerAndroid implements
}
private void checkIsOnCameraThread() {
- synchronized (handlerLock) {
- if (cameraThreadHandler == null) {
- Logging.e(TAG, "Camera is stopped - can't check thread.");
- } else if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) {
- throw new IllegalStateException("Wrong thread");
- }
+ if (cameraThreadHandler == null) {
+ Logging.e(TAG, "Camera is not initialized - can't check thread.");
+ } else if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) {
+ throw new IllegalStateException("Wrong thread");
}
}
@@ -246,11 +242,9 @@ public class VideoCapturerAndroid implements
}
private boolean maybePostDelayedOnCameraThread(int delayMs, Runnable runnable) {
- synchronized (handlerLock) {
- return cameraThreadHandler != null
- && cameraThreadHandler.postAtTime(
- runnable, this /* token */, SystemClock.uptimeMillis() + delayMs);
- }
+ return cameraThreadHandler != null && isCameraRunning.get()
+ && cameraThreadHandler.postAtTime(
+ runnable, this /* token */, SystemClock.uptimeMillis() + delayMs);
}
@Override
@@ -258,67 +252,75 @@ public class VideoCapturerAndroid implements
Logging.d(TAG, "dispose");
}
+ private boolean isInitialized() {
+ return applicationContext != null && frameObserver != null;
+ }
+
+ @Override
+ public void initialize(SurfaceTextureHelper surfaceTextureHelper, Context applicationContext,
+ CapturerObserver frameObserver) {
+ Logging.d(TAG, "initialize");
+ if (applicationContext == null) {
+ throw new IllegalArgumentException("applicationContext not set.");
+ }
+ if (frameObserver == null) {
+ throw new IllegalArgumentException("frameObserver not set.");
+ }
+ if (isInitialized()) {
+ throw new IllegalStateException("Already initialized");
+ }
+ this.applicationContext = applicationContext;
+ this.frameObserver = frameObserver;
+ this.surfaceHelper = surfaceTextureHelper;
+ this.cameraThreadHandler =
+ surfaceTextureHelper == null ? null : surfaceTextureHelper.getHandler();
+ }
+
// Note that this actually opens the camera, and Camera callbacks run on the
// thread that calls open(), so this is done on the CameraThread.
@Override
- public void startCapture(
- final int width, final int height, final int framerate,
- final SurfaceTextureHelper surfaceTextureHelper, final Context applicationContext,
- final CapturerObserver frameObserver) {
+ public void startCapture(final int width, final int height, final int framerate) {
Logging.d(TAG, "startCapture requested: " + width + "x" + height + "@" + framerate);
- if (surfaceTextureHelper == null) {
+ if (!isInitialized()) {
+ throw new IllegalStateException("startCapture called in uninitialized state");
+ }
+ if (surfaceHelper == null) {
frameObserver.onCapturerStarted(false /* success */);
if (eventsHandler != null) {
eventsHandler.onCameraError("No SurfaceTexture created.");
}
return;
}
- if (applicationContext == null) {
- throw new IllegalArgumentException("applicationContext not set.");
- }
- if (frameObserver == null) {
- throw new IllegalArgumentException("frameObserver not set.");
+ if (isCameraRunning.getAndSet(true)) {
+ Logging.e(TAG, "Camera has already been started.");
+ return;
}
- synchronized (handlerLock) {
- if (this.cameraThreadHandler != null) {
- throw new RuntimeException("Camera has already been started.");
+ final boolean didPost = maybePostOnCameraThread(new Runnable() {
+ @Override
+ public void run() {
+ openCameraAttempts = 0;
+ startCaptureOnCameraThread(width, height, framerate);
}
- this.cameraThreadHandler = surfaceTextureHelper.getHandler();
- this.surfaceHelper = surfaceTextureHelper;
- final boolean didPost = maybePostOnCameraThread(new Runnable() {
- @Override
- public void run() {
- openCameraAttempts = 0;
- startCaptureOnCameraThread(width, height, framerate, frameObserver,
- applicationContext);
- }
- });
- if (!didPost) {
- frameObserver.onCapturerStarted(false);
- if (eventsHandler != null) {
- eventsHandler.onCameraError("Could not post task to camera thread.");
- }
+ });
+ if (!didPost) {
+ frameObserver.onCapturerStarted(false);
+ if (eventsHandler != null) {
+ eventsHandler.onCameraError("Could not post task to camera thread.");
}
+ isCameraRunning.set(false);
}
}
- private void startCaptureOnCameraThread(
- final int width, final int height, final int framerate, final CapturerObserver frameObserver,
- final Context applicationContext) {
- synchronized (handlerLock) {
- if (cameraThreadHandler == null) {
- Logging.e(TAG, "startCaptureOnCameraThread: Camera is stopped");
- return;
- } else {
- checkIsOnCameraThread();
- }
+ private void startCaptureOnCameraThread(final int width, final int height, final int framerate) {
+ checkIsOnCameraThread();
+ if (!isCameraRunning.get()) {
+ Logging.e(TAG, "startCaptureOnCameraThread: Camera is stopped");
+ return;
}
if (camera != null) {
Logging.e(TAG, "startCaptureOnCameraThread: Camera has already been started.");
return;
}
- this.applicationContext = applicationContext;
- this.frameObserver = frameObserver;
this.firstFrameReported = false;
try {
@@ -337,9 +339,9 @@ public class VideoCapturerAndroid implements
if (openCameraAttempts < MAX_OPEN_CAMERA_ATTEMPTS) {
Logging.e(TAG, "Camera.open failed, retrying", e);
maybePostDelayedOnCameraThread(OPEN_CAMERA_DELAY_MS, new Runnable() {
- @Override public void run() {
- startCaptureOnCameraThread(width, height, framerate, frameObserver,
- applicationContext);
+ @Override
+ public void run() {
+ startCaptureOnCameraThread(width, height, framerate);
}
});
return;
@@ -373,13 +375,10 @@ public class VideoCapturerAndroid implements
// (Re)start preview with the closest supported format to |width| x |height| @ |framerate|.
private void startPreviewOnCameraThread(int width, int height, int framerate) {
- synchronized (handlerLock) {
- if (cameraThreadHandler == null || camera == null) {
- Logging.e(TAG, "startPreviewOnCameraThread: Camera is stopped");
- return;
- } else {
- checkIsOnCameraThread();
- }
+ checkIsOnCameraThread();
+ if (!isCameraRunning.get() || camera == null) {
+ Logging.e(TAG, "startPreviewOnCameraThread: Camera is stopped");
+ return;
}
Logging.d(
TAG, "startPreviewOnCameraThread requested: " + width + "x" + height + "@" + framerate);
@@ -489,13 +488,7 @@ public class VideoCapturerAndroid implements
}
private void stopCaptureOnCameraThread(boolean stopHandler) {
- synchronized (handlerLock) {
- if (cameraThreadHandler == null) {
- Logging.e(TAG, "stopCaptureOnCameraThread: Camera is stopped");
- } else {
- checkIsOnCameraThread();
- }
- }
+ checkIsOnCameraThread();
Logging.d(TAG, "stopCaptureOnCameraThread");
// Note that the camera might still not be started here if startCaptureOnCameraThread failed
// and we posted a retry.
@@ -505,21 +498,15 @@ public class VideoCapturerAndroid implements
surfaceHelper.stopListening();
}
if (stopHandler) {
- synchronized (handlerLock) {
- // Clear the cameraThreadHandler first, in case stopPreview or
- // other driver code deadlocks. Deadlock in
- // android.hardware.Camera._stopPreview(Native Method) has
- // been observed on Nexus 5 (hammerhead), OS version LMY48I.
- // The camera might post another one or two preview frames
- // before stopped, so we have to check for a null
- // cameraThreadHandler in our handler. Remove all pending
- // Runnables posted from |this|.
- if (cameraThreadHandler != null) {
- cameraThreadHandler.removeCallbacksAndMessages(this /* token */);
- cameraThreadHandler = null;
- }
- surfaceHelper = null;
- }
+ // Clear the cameraThreadHandler first, in case stopPreview or
+ // other driver code deadlocks. Deadlock in
+ // android.hardware.Camera._stopPreview(Native Method) has
+ // been observed on Nexus 5 (hammerhead), OS version LMY48I.
+ // The camera might post another one or two preview frames
+ // before stopped, so we have to check |isCameraRunning|.
+ // Remove all pending Runnables posted from |this|.
+ isCameraRunning.set(false);
+ cameraThreadHandler.removeCallbacksAndMessages(this /* token */);
}
if (cameraStatistics != null) {
cameraStatistics.release();
@@ -545,33 +532,22 @@ public class VideoCapturerAndroid implements
}
private void switchCameraOnCameraThread() {
- synchronized (handlerLock) {
- if (cameraThreadHandler == null) {
- Logging.e(TAG, "switchCameraOnCameraThread: Camera is stopped");
- return;
- } else {
- checkIsOnCameraThread();
- }
+ checkIsOnCameraThread();
+ if (!isCameraRunning.get()) {
+ Logging.e(TAG, "switchCameraOnCameraThread: Camera is stopped");
+ return;
}
Logging.d(TAG, "switchCameraOnCameraThread");
stopCaptureOnCameraThread(false /* stopHandler */);
synchronized (cameraIdLock) {
id = (id + 1) % android.hardware.Camera.getNumberOfCameras();
}
- startCaptureOnCameraThread(requestedWidth, requestedHeight, requestedFramerate, frameObserver,
- applicationContext);
+ startCaptureOnCameraThread(requestedWidth, requestedHeight, requestedFramerate);
Logging.d(TAG, "switchCameraOnCameraThread done");
}
private void onOutputFormatRequestOnCameraThread(int width, int height, int framerate) {
- synchronized (handlerLock) {
- if (cameraThreadHandler == null || camera == null) {
- Logging.e(TAG, "onOutputFormatRequestOnCameraThread: Camera is stopped");
- return;
- } else {
- checkIsOnCameraThread();
- }
- }
+ checkIsOnCameraThread();
Logging.d(TAG, "onOutputFormatRequestOnCameraThread: " + width + "x" + height +
"@" + framerate);
frameObserver.onOutputFormatRequest(width, height, framerate);
@@ -611,13 +587,10 @@ public class VideoCapturerAndroid implements
// Called on cameraThread so must not "synchronized".
@Override
public void onPreviewFrame(byte[] data, android.hardware.Camera callbackCamera) {
- synchronized (handlerLock) {
- if (cameraThreadHandler == null) {
- Logging.e(TAG, "onPreviewFrame: Camera is stopped");
- return;
- } else {
- checkIsOnCameraThread();
- }
+ checkIsOnCameraThread();
+ if (!isCameraRunning.get()) {
+ Logging.e(TAG, "onPreviewFrame: Camera is stopped");
+ return;
}
if (!queuedBuffers.contains(data)) {
// |data| is an old invalid buffer.
@@ -644,14 +617,11 @@ public class VideoCapturerAndroid implements
@Override
public void onTextureFrameAvailable(
int oesTextureId, float[] transformMatrix, long timestampNs) {
- synchronized (handlerLock) {
- if (cameraThreadHandler == null) {
- Logging.e(TAG, "onTextureFrameAvailable: Camera is stopped");
- surfaceHelper.returnTextureFrame();
- return;
- } else {
- checkIsOnCameraThread();
- }
+ checkIsOnCameraThread();
+ if (!isCameraRunning.get()) {
+ Logging.e(TAG, "onTextureFrameAvailable: Camera is stopped");
+ surfaceHelper.returnTextureFrame();
+ return;
}
if (eventsHandler != null && !firstFrameReported) {
eventsHandler.onFirstFrameAvailable();
« no previous file with comments | « webrtc/api/android/java/src/org/webrtc/VideoCapturer.java ('k') | webrtc/api/android/jni/androidvideocapturer_jni.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698