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

Unified Diff: webrtc/api/android/java/src/org/webrtc/Camera2Capturer.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
« no previous file with comments | « no previous file | webrtc/api/android/java/src/org/webrtc/VideoCapturer.java » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/api/android/java/src/org/webrtc/Camera2Capturer.java
diff --git a/webrtc/api/android/java/src/org/webrtc/Camera2Capturer.java b/webrtc/api/android/java/src/org/webrtc/Camera2Capturer.java
index 8e44d69eaf58bb21dd8828ef5e76cb54882be303..8110945a33c9a623ae764806202d53a0a0eb87cd 100644
--- a/webrtc/api/android/java/src/org/webrtc/Camera2Capturer.java
+++ b/webrtc/api/android/java/src/org/webrtc/Camera2Capturer.java
@@ -35,7 +35,7 @@ import android.view.WindowManager;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Semaphore;
+import java.util.concurrent.atomic.AtomicBoolean;
@TargetApi(21)
public class Camera2Capturer implements
@@ -58,17 +58,20 @@ public class Camera2Capturer implements
private final CameraManager cameraManager;
private final CameraEventsHandler eventsHandler;
+ // Set once in initialization(), before any other calls, so therefore thread safe.
+ // ---------------------------------------------------------------------------------------------
+ private SurfaceTextureHelper surfaceTextureHelper;
+ private Context applicationContext;
+ private CapturerObserver capturerObserver;
+ // Use postOnCameraThread() instead of posting directly to the handler - this way all callbacks
+ // with a specifed token can be removed at once.
+ private Handler cameraThreadHandler;
// Shared state - guarded by cameraStateLock. Will only be edited from camera thread (when it is
// running).
// ---------------------------------------------------------------------------------------------
private final Object cameraStateLock = new Object();
- private CameraState cameraState = CameraState.IDLE;
- // |cameraThreadHandler| must be synchronized on |cameraStateLock| when not on the camera thread,
- // or when modifying the reference. Use postOnCameraThread() instead of posting directly to
- // the handler - this way all callbacks with a specifed token can be removed at once.
- // |cameraThreadHandler| must be null if and only if CameraState is IDLE.
- private Handler cameraThreadHandler;
+ private volatile CameraState cameraState = CameraState.IDLE;
// Remember the requested format in case we want to switch cameras.
private int requestedWidth;
private int requestedHeight;
@@ -79,22 +82,18 @@ public class Camera2Capturer implements
private boolean isFrontCamera;
private int cameraOrientation;
- // Semaphore for allowing only one switch at a time.
- private final Semaphore pendingCameraSwitchSemaphore = new Semaphore(1);
- // Guarded by pendingCameraSwitchSemaphore
+ // Atomic boolean for allowing only one switch at a time.
+ private final AtomicBoolean isPendingCameraSwitch = new AtomicBoolean();
+ // Guarded by isPendingCameraSwitch.
private CameraSwitchHandler switchEventsHandler;
// Internal state - must only be modified from camera thread
// ---------------------------------------------------------
private CaptureFormat captureFormat;
- private Context applicationContext;
- private CapturerObserver capturerObserver;
private CameraStatistics cameraStatistics;
- private SurfaceTextureHelper surfaceTextureHelper;
private CameraCaptureSession captureSession;
private Surface surface;
private CameraDevice cameraDevice;
- private CameraStateCallback cameraStateCallback;
// Factor to convert between Android framerates and CaptureFormat.FramerateRange. It will be
// either 1 or 1000.
@@ -111,28 +110,16 @@ public class Camera2Capturer implements
setCameraName(cameraName);
}
- /**
- * Helper method for checking method is executed on camera thread. Also allows calls from other
- * threads if camera is closed.
- */
- private void checkIsOnCameraThread() {
- if (cameraState == CameraState.IDLE) {
- return;
- }
-
- checkIsStrictlyOnCameraThread();
+ private boolean isOnCameraThread() {
+ return Thread.currentThread() == cameraThreadHandler.getLooper().getThread();
}
/**
- * Like checkIsOnCameraThread but doesn't allow the camera to be stopped.
+ * Helper method for checking method is executed on camera thread.
*/
- private void checkIsStrictlyOnCameraThread() {
- if (cameraThreadHandler == null) {
- throw new IllegalStateException("Camera is closed.");
- }
-
- if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) {
- throw new IllegalStateException("Wrong thread");
+ private void checkIsOnCameraThread() {
+ if (!isOnCameraThread()) {
+ throw new IllegalStateException("Not on camera thread");
}
}
@@ -247,14 +234,14 @@ public class Camera2Capturer implements
* thread and camera must not be stopped.
*/
private void reportError(String errorDescription) {
- checkIsStrictlyOnCameraThread();
+ checkIsOnCameraThread();
Logging.e(TAG, "Error in camera at state " + cameraState + ": " + errorDescription);
if (switchEventsHandler != null) {
switchEventsHandler.onCameraSwitchError(errorDescription);
switchEventsHandler = null;
- pendingCameraSwitchSemaphore.release();
}
+ isPendingCameraSwitch.set(false);
switch (cameraState) {
case STARTING:
@@ -276,22 +263,19 @@ public class Camera2Capturer implements
}
private void closeAndRelease() {
- checkIsStrictlyOnCameraThread();
+ checkIsOnCameraThread();
Logging.d(TAG, "Close and release.");
setCameraState(CameraState.STOPPING);
// Remove all pending Runnables posted from |this|.
cameraThreadHandler.removeCallbacksAndMessages(this /* token */);
- applicationContext = null;
- capturerObserver = null;
if (cameraStatistics != null) {
cameraStatistics.release();
cameraStatistics = null;
}
if (surfaceTextureHelper != null) {
surfaceTextureHelper.stopListening();
- surfaceTextureHelper = null;
}
if (captureSession != null) {
captureSession.close();
@@ -320,7 +304,6 @@ public class Camera2Capturer implements
Logging.w(TAG, "closeAndRelease called while cameraDevice is null");
setCameraState(CameraState.IDLE);
}
- this.cameraStateCallback = null;
}
/**
@@ -328,16 +311,9 @@ public class Camera2Capturer implements
*/
private void setCameraState(CameraState newState) {
// State must only be modified on the camera thread. It can be edited from other threads
- // if cameraState is IDLE since there is no camera thread.
- checkIsOnCameraThread();
-
- if (newState != CameraState.IDLE) {
- if (cameraThreadHandler == null) {
- throw new IllegalStateException(
- "cameraThreadHandler must be null if and only if CameraState is IDLE.");
- }
- } else {
- cameraThreadHandler = null;
+ // if cameraState is IDLE since the camera thread is idle and not modifying the state.
+ if (cameraState != CameraState.IDLE) {
+ checkIsOnCameraThread();
}
switch (newState) {
@@ -376,37 +352,49 @@ public class Camera2Capturer implements
*/
private void openCamera() {
try {
- checkIsStrictlyOnCameraThread();
+ checkIsOnCameraThread();
if (cameraState != CameraState.STARTING) {
throw new IllegalStateException("Camera should be in state STARTING in openCamera.");
}
- if (cameraThreadHandler == null) {
- throw new RuntimeException("Someone set cameraThreadHandler to null while the camera "
- + "state was STARTING. This should never happen");
- }
-
// Camera is in state STARTING so cameraName will not be edited.
- cameraManager.openCamera(cameraName, cameraStateCallback, cameraThreadHandler);
+ cameraManager.openCamera(cameraName, new CameraStateCallback(), cameraThreadHandler);
} catch (CameraAccessException e) {
reportError("Failed to open camera: " + e);
}
}
- private void startCaptureOnCameraThread(
- final int requestedWidth, final int requestedHeight, final int requestedFramerate,
- final SurfaceTextureHelper surfaceTextureHelper, final Context applicationContext,
- final CapturerObserver capturerObserver) {
- checkIsStrictlyOnCameraThread();
-
- firstFrameReported = false;
- consecutiveCameraOpenFailures = 0;
+ private boolean isInitialized() {
+ return applicationContext != null && capturerObserver != null;
+ }
+ @Override
+ public void initialize(SurfaceTextureHelper surfaceTextureHelper, Context applicationContext,
+ CapturerObserver capturerObserver) {
+ Logging.d(TAG, "initialize");
+ if (applicationContext == null) {
+ throw new IllegalArgumentException("applicationContext not set.");
+ }
+ if (capturerObserver == null) {
+ throw new IllegalArgumentException("capturerObserver not set.");
+ }
+ if (isInitialized()) {
+ throw new IllegalStateException("Already initialized");
+ }
this.applicationContext = applicationContext;
this.capturerObserver = capturerObserver;
this.surfaceTextureHelper = surfaceTextureHelper;
- this.cameraStateCallback = new CameraStateCallback();
+ this.cameraThreadHandler =
+ surfaceTextureHelper == null ? null : surfaceTextureHelper.getHandler();
+ }
+
+ private void startCaptureOnCameraThread(
+ final int requestedWidth, final int requestedHeight, final int requestedFramerate) {
+ checkIsOnCameraThread();
+
+ firstFrameReported = false;
+ consecutiveCameraOpenFailures = 0;
synchronized (cameraStateLock) {
// Remember the requested format in case we want to switch cameras.
@@ -466,36 +454,32 @@ public class Camera2Capturer implements
*/
@Override
public void startCapture(
- final int requestedWidth, final int requestedHeight, final int requestedFramerate,
- final SurfaceTextureHelper surfaceTextureHelper, final Context applicationContext,
- final CapturerObserver capturerObserver) {
+ final int requestedWidth, final int requestedHeight, final int requestedFramerate) {
Logging.d(TAG, "startCapture requested: " + requestedWidth + "x" + requestedHeight
+ "@" + requestedFramerate);
- if (surfaceTextureHelper == null) {
- throw new IllegalArgumentException("surfaceTextureHelper not set.");
+ if (!isInitialized()) {
+ throw new IllegalStateException("startCapture called in uninitialized state");
}
- if (applicationContext == null) {
- throw new IllegalArgumentException("applicationContext not set.");
- }
- if (capturerObserver == null) {
- throw new IllegalArgumentException("capturerObserver not set.");
+ if (surfaceTextureHelper == null) {
+ capturerObserver.onCapturerStarted(false /* success */);
+ if (eventsHandler != null) {
+ eventsHandler.onCameraError("No SurfaceTexture created.");
+ }
+ return;
}
-
synchronized (cameraStateLock) {
waitForCameraToStopIfStopping();
if (cameraState != CameraState.IDLE) {
Logging.e(TAG, "Unexpected camera state for startCapture: " + cameraState);
return;
}
- this.cameraThreadHandler = surfaceTextureHelper.getHandler();
setCameraState(CameraState.STARTING);
}
postOnCameraThread(new Runnable() {
@Override
public void run() {
- startCaptureOnCameraThread(requestedWidth, requestedHeight, requestedFramerate,
- surfaceTextureHelper, applicationContext, capturerObserver);
+ startCaptureOnCameraThread(requestedWidth, requestedHeight, requestedFramerate);
}
});
}
@@ -521,14 +505,14 @@ public class Camera2Capturer implements
@Override
public void onDisconnected(CameraDevice camera) {
- checkIsStrictlyOnCameraThread();
+ checkIsOnCameraThread();
cameraDevice = camera;
reportError("Camera disconnected.");
}
@Override
public void onError(CameraDevice camera, int errorCode) {
- checkIsStrictlyOnCameraThread();
+ checkIsOnCameraThread();
cameraDevice = camera;
if (cameraState == CameraState.STARTING && (
@@ -555,7 +539,7 @@ public class Camera2Capturer implements
@Override
public void onOpened(CameraDevice camera) {
- checkIsStrictlyOnCameraThread();
+ checkIsOnCameraThread();
Logging.d(TAG, "Camera opened.");
if (cameraState != CameraState.STARTING) {
@@ -576,7 +560,7 @@ public class Camera2Capturer implements
@Override
public void onClosed(CameraDevice camera) {
- checkIsStrictlyOnCameraThread();
+ checkIsOnCameraThread();
Logging.d(TAG, "Camera device closed.");
@@ -597,14 +581,14 @@ public class Camera2Capturer implements
final class CaptureSessionCallback extends CameraCaptureSession.StateCallback {
@Override
public void onConfigureFailed(CameraCaptureSession session) {
- checkIsStrictlyOnCameraThread();
+ checkIsOnCameraThread();
captureSession = session;
reportError("Failed to configure capture session.");
}
@Override
public void onConfigured(CameraCaptureSession session) {
- checkIsStrictlyOnCameraThread();
+ checkIsOnCameraThread();
Logging.d(TAG, "Camera capture session configured.");
captureSession = session;
try {
@@ -642,8 +626,8 @@ public class Camera2Capturer implements
if (switchEventsHandler != null) {
switchEventsHandler.onCameraSwitchDone(isFrontCamera);
switchEventsHandler = null;
- pendingCameraSwitchSemaphore.release();
}
+ isPendingCameraSwitch.set(false);
}
}
@@ -692,8 +676,9 @@ public class Camera2Capturer implements
return;
}
// Do not handle multiple camera switch request to avoid blocking camera thread by handling too
- // many switch request from a queue. We have to be careful to always release this.
- if (!pendingCameraSwitchSemaphore.tryAcquire()) {
+ // many switch request from a queue. We have to be careful to always release
+ // |isPendingCameraSwitch| by setting it to false when done.
+ if (isPendingCameraSwitch.getAndSet(true)) {
Logging.w(TAG, "Ignoring camera switch request.");
if (switchEventsHandler != null) {
switchEventsHandler.onCameraSwitchError("Pending camera switch already in progress.");
@@ -702,9 +687,6 @@ public class Camera2Capturer implements
}
final String newCameraId;
- final SurfaceTextureHelper surfaceTextureHelper;
- final Context applicationContext;
- final CapturerObserver capturerObserver;
final int requestedWidth;
final int requestedHeight;
final int requestedFramerate;
@@ -717,7 +699,7 @@ public class Camera2Capturer implements
if (switchEventsHandler != null) {
switchEventsHandler.onCameraSwitchError("Camera is stopped.");
}
- pendingCameraSwitchSemaphore.release();
+ isPendingCameraSwitch.set(false);
return;
}
@@ -731,11 +713,6 @@ public class Camera2Capturer implements
final int newCameraIndex = (currentCameraIndex + 1) % cameraIds.length;
newCameraId = cameraIds[newCameraIndex];
- // Remember parameters. These are not null since camera is in RUNNING state. They aren't
- // edited either while camera is in RUNNING state.
- surfaceTextureHelper = this.surfaceTextureHelper;
- applicationContext = this.applicationContext;
- capturerObserver = this.capturerObserver;
requestedWidth = this.requestedWidth;
requestedHeight = this.requestedHeight;
requestedFramerate = this.requestedFramerate;
@@ -745,8 +722,7 @@ public class Camera2Capturer implements
// Make the switch.
stopCapture();
setCameraName(newCameraId);
- startCapture(requestedWidth, requestedHeight, requestedFramerate, surfaceTextureHelper,
- applicationContext, capturerObserver);
+ startCapture(requestedWidth, requestedHeight, requestedFramerate);
// Note: switchEventsHandler will be called from onConfigured / reportError.
}
@@ -761,10 +737,6 @@ public class Camera2Capturer implements
postOnCameraThread(new Runnable() {
@Override
public void run() {
- if (capturerObserver == null) {
- Logging.e(TAG, "Calling onOutputFormatRequest() on stopped camera.");
- return;
- }
Logging.d(TAG,
"onOutputFormatRequestOnCameraThread: " + width + "x" + height + "@" + framerate);
capturerObserver.onOutputFormatRequest(width, height, framerate);
@@ -776,10 +748,6 @@ public class Camera2Capturer implements
// is running.
@Override
public void changeCaptureFormat(final int width, final int height, final int framerate) {
- final SurfaceTextureHelper surfaceTextureHelper;
- final Context applicationContext;
- final CapturerObserver capturerObserver;
-
synchronized (cameraStateLock) {
waitForCameraToStartIfStarting();
@@ -791,17 +759,12 @@ public class Camera2Capturer implements
requestedWidth = width;
requestedHeight = height;
requestedFramerate = framerate;
-
- surfaceTextureHelper = this.surfaceTextureHelper;
- applicationContext = this.applicationContext;
- capturerObserver = this.capturerObserver;
}
// Make the switch.
stopCapture();
// TODO(magjed/sakal): Just recreate session.
- startCapture(width, height, framerate,
- surfaceTextureHelper, applicationContext, capturerObserver);
+ startCapture(width, height, framerate);
}
@Override
@@ -896,7 +859,7 @@ public class Camera2Capturer implements
@Override
public void onTextureFrameAvailable(
int oesTextureId, float[] transformMatrix, long timestampNs) {
- checkIsStrictlyOnCameraThread();
+ checkIsOnCameraThread();
if (eventsHandler != null && !firstFrameReported) {
eventsHandler.onFirstFrameAvailable();
« no previous file with comments | « no previous file | webrtc/api/android/java/src/org/webrtc/VideoCapturer.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698