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

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

Issue 2168623002: Refactor stopCapture to be asynchronous in VideoCapturerAndroid. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@androidvideotracksource
Patch Set: Cleanup 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 d3a9faff21b9bcb18c1daee086aedf3ec4305c0c..7103e752f6acceefbb02bd88d384000af11e39c3 100644
--- a/webrtc/api/android/java/src/org/webrtc/VideoCapturerAndroid.java
+++ b/webrtc/api/android/java/src/org/webrtc/VideoCapturerAndroid.java
@@ -46,40 +46,54 @@ public class VideoCapturerAndroid implements
SurfaceTextureHelper.OnTextureFrameAvailableListener {
private static final String TAG = "VideoCapturerAndroid";
private static final int CAMERA_STOP_TIMEOUT_MS = 7000;
+ // Arbitrary queue depth. Higher number means more memory allocated & held,
+ // lower number means more sensitivity to processing time in the client (and
+ // potentially stalling the capturer if it runs out of buffers to write to).
+ private static final int NUMBER_OF_CAPTURE_BUFFERS = 3;
+ private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3;
+ private final static int OPEN_CAMERA_DELAY_MS = 500;
+ private static enum CameraState { UNINITIALIAZED, IDLE, STARTING, RUNNING }
- private android.hardware.Camera camera; // Only non-null while capturing.
- private final AtomicBoolean isCameraRunning = new AtomicBoolean();
- // Use maybePostOnCameraThread() instead of posting directly to the handler - this way all
+ private final Set<byte[]> queuedBuffers = new HashSet<byte[]>();
+ private final AtomicBoolean generateCapturerEvents = new AtomicBoolean();
+ private final boolean isCapturingToTexture;
+ private final CameraEventsHandler eventsHandler;
+
+ // Initialized on initialize
+ // -------------------------
+ // Use postOnCameraThread() 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 Handler cameraThreadHandler;
private Context applicationContext;
- // Synchronization lock for |id|.
- private final Object cameraIdLock = new Object();
- private int id;
- private android.hardware.Camera.CameraInfo info;
- private CameraStatistics cameraStatistics;
+ private CapturerObserver capturerObserver = null;
+ private SurfaceTextureHelper surfaceHelper;
+
+ // Internal state - will only be touch from the camera thread
+ // ----------------------------------------------------------
+ private android.hardware.Camera camera; // Only non-null while capturing.
+ private CameraState cameraState;
// Remember the requested format in case we want to switch cameras.
private int requestedWidth;
private int requestedHeight;
private int requestedFramerate;
- // The capture format will be the closest supported format to the requested format.
+ // Populated with the information of the active camera.
+ private android.hardware.Camera.CameraInfo info;
+ // Active capture format.
private CaptureFormat captureFormat;
- private final Object pendingCameraSwitchLock = new Object();
- private volatile boolean pendingCameraSwitch;
- private CapturerObserver frameObserver = null;
- private final CameraEventsHandler eventsHandler;
+ private CameraStatistics cameraStatistics;
private boolean firstFrameReported;
- // Arbitrary queue depth. Higher number means more memory allocated & held,
- // lower number means more sensitivity to processing time in the client (and
- // potentially stalling the capturer if it runs out of buffers to write to).
- private static final int NUMBER_OF_CAPTURE_BUFFERS = 3;
- private final Set<byte[]> queuedBuffers = new HashSet<byte[]>();
- private final boolean isCapturingToTexture;
- private SurfaceTextureHelper surfaceHelper;
- private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3;
- private final static int OPEN_CAMERA_DELAY_MS = 500;
private int openCameraAttempts;
+ // Locked objected
magjed_webrtc 2016/07/20 14:56:08 objects
sakal 2016/07/21 11:17:24 Done.
+ // ---------------
+ private final Object cameraIdLock = new Object();
+ private int id; // Only edited from camera thread while holding the lock.
+
+ // Only allow one camera switch a time.
+ private final Object cameraSwitchLock = new Object();
+ private boolean pendingCameraSwitch;
+ private CameraSwitchHandler switchEventsHandler;
+
// Camera error callback.
private final android.hardware.Camera.ErrorCallback cameraErrorCallback =
new android.hardware.Camera.ErrorCallback() {
@@ -98,6 +112,10 @@ public class VideoCapturerAndroid implements
}
};
+ private void setCameraState(CameraState newState) {
+ cameraState = newState;
magjed_webrtc 2016/07/20 14:56:08 Add a debug log with the current state and the new
sakal 2016/07/21 11:17:23 Done.
+ }
+
public static VideoCapturerAndroid create(String name,
CameraEventsHandler eventsHandler) {
return VideoCapturerAndroid.create(name, eventsHandler, false /* captureToTexture */);
@@ -141,7 +159,8 @@ public class VideoCapturerAndroid implements
}
return;
}
- synchronized (pendingCameraSwitchLock) {
+
+ synchronized (cameraSwitchLock) {
if (pendingCameraSwitch) {
// Do not handle multiple camera switch request to avoid blocking
// camera thread by handling too many switch request from a queue.
@@ -151,24 +170,24 @@ public class VideoCapturerAndroid implements
}
return;
}
+
pendingCameraSwitch = true;
}
- final boolean didPost = maybePostOnCameraThread(new Runnable() {
+
+ postOnCameraThread(new Runnable() {
@Override
public void run() {
+ // Set switchEventsHandler only here because now openCameraOnCameraThread cannot be called
+ // in-between these calls.
+ synchronized (cameraSwitchLock) {
+ VideoCapturerAndroid.this.switchEventsHandler = switchEventsHandler;
+ }
switchCameraOnCameraThread();
- synchronized (pendingCameraSwitchLock) {
+ synchronized (cameraSwitchLock) {
pendingCameraSwitch = false;
}
- if (switchEventsHandler != null) {
- switchEventsHandler.onCameraSwitchDone(
- info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
- }
}
});
- if (!didPost && switchEventsHandler != null) {
- switchEventsHandler.onCameraSwitchError("Camera is stopped.");
- }
}
// Requests a new output format from the video capturer. Captured frames
@@ -178,7 +197,7 @@ public class VideoCapturerAndroid implements
// TODO(magjed/perkj): Document what this function does. Change name?
@Override
public void onOutputFormatRequest(final int width, final int height, final int framerate) {
- maybePostOnCameraThread(new Runnable() {
+ postOnCameraThread(new Runnable() {
@Override public void run() {
onOutputFormatRequestOnCameraThread(width, height, framerate);
}
@@ -189,24 +208,22 @@ public class VideoCapturerAndroid implements
// is running.
@Override
public void changeCaptureFormat(final int width, final int height, final int framerate) {
- maybePostOnCameraThread(new Runnable() {
+ postOnCameraThread(new Runnable() {
@Override public void run() {
- startPreviewOnCameraThread(width, height, framerate);
+ requestedWidth = width;
+ requestedHeight = height;
+ requestedFramerate = framerate;
+
+ startPreviewOnCameraThread();
}
});
}
- // Helper function to retrieve the current camera id synchronously. Note that the camera id might
- // change at any point by switchCamera() calls.
- private int getCurrentCameraId() {
- synchronized (cameraIdLock) {
- return id;
- }
- }
-
@Override
public List<CaptureFormat> getSupportedFormats() {
- return Camera1Enumerator.getSupportedFormats(getCurrentCameraId());
+ synchronized (cameraIdLock) {
+ return Camera1Enumerator.getSupportedFormats(id);
+ }
}
// Returns true if this VideoCapturer is setup to capture video frames to a SurfaceTexture.
@@ -216,6 +233,8 @@ public class VideoCapturerAndroid implements
public VideoCapturerAndroid(String cameraName, CameraEventsHandler eventsHandler,
boolean captureToTexture) {
+ cameraState = CameraState.UNINITIALIAZED;
magjed_webrtc 2016/07/20 14:56:08 I prefer if you move this to the declaration.
sakal 2016/07/21 11:17:24 Done.
+
if (android.hardware.Camera.getNumberOfCameras() == 0) {
throw new RuntimeException("No cameras available");
}
@@ -231,49 +250,54 @@ public class VideoCapturerAndroid implements
private void checkIsOnCameraThread() {
if (cameraThreadHandler == null) {
- Logging.e(TAG, "Camera is not initialized - can't check thread.");
+ throw new IllegalStateException("Camera is not initialized - can't check thread.");
} else if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) {
throw new IllegalStateException("Wrong thread");
}
}
- private boolean maybePostOnCameraThread(Runnable runnable) {
- return maybePostDelayedOnCameraThread(0 /* delayMs */, runnable);
+ private void postOnCameraThread(Runnable runnable) {
+ postDelayedOnCameraThread(0 /* delayMs */, runnable);
}
- private boolean maybePostDelayedOnCameraThread(int delayMs, Runnable runnable) {
- return cameraThreadHandler != null && isCameraRunning.get()
- && cameraThreadHandler.postAtTime(
- runnable, this /* token */, SystemClock.uptimeMillis() + delayMs);
+ private void postDelayedOnCameraThread(int delayMs, Runnable runnable) {
+ cameraThreadHandler.postAtTime(
magjed_webrtc 2016/07/20 14:56:07 You have removed the logic for handling failure to
sakal 2016/07/21 11:17:24 Done.
+ runnable, this /* token */, SystemClock.uptimeMillis() + delayMs);
}
@Override
public void dispose() {
Logging.d(TAG, "dispose");
+ stopCapture();
+ // Nothing should be running on the camera thread so should be safe
magjed_webrtc 2016/07/20 14:56:08 nit: dot at end of sentence.
sakal 2016/07/21 11:17:23 Done.
+ cameraState = CameraState.UNINITIALIAZED;
}
private boolean isInitialized() {
- return applicationContext != null && frameObserver != null;
+ return applicationContext != null && capturerObserver != null;
magjed_webrtc 2016/07/20 14:56:08 Maybe this is cleaner: return cameraState != UNINI
sakal 2016/07/21 11:17:24 Done.
}
@Override
public void initialize(SurfaceTextureHelper surfaceTextureHelper, Context applicationContext,
- CapturerObserver frameObserver) {
+ CapturerObserver capturerObserver) {
Logging.d(TAG, "initialize");
if (applicationContext == null) {
throw new IllegalArgumentException("applicationContext not set.");
}
- if (frameObserver == null) {
- throw new IllegalArgumentException("frameObserver not set.");
+ if (capturerObserver == null) {
+ throw new IllegalArgumentException("capturerObserver not set.");
}
if (isInitialized()) {
throw new IllegalStateException("Already initialized");
}
this.applicationContext = applicationContext;
- this.frameObserver = frameObserver;
+ this.capturerObserver = capturerObserver;
this.surfaceHelper = surfaceTextureHelper;
this.cameraThreadHandler =
surfaceTextureHelper == null ? null : surfaceTextureHelper.getHandler();
+
+ // Nothing should be running on the camera thread so should be safe
+ cameraState = CameraState.IDLE;
magjed_webrtc 2016/07/20 14:56:07 nit: dot at end of sentence.
sakal 2016/07/21 11:17:23 Done.
}
// Note that this actually opens the camera, and Camera callbacks run on the
@@ -281,67 +305,60 @@ public class VideoCapturerAndroid implements
@Override
public void startCapture(final int width, final int height, final int framerate) {
Logging.d(TAG, "startCapture requested: " + width + "x" + height + "@" + framerate);
- if (!isInitialized()) {
- throw new IllegalStateException("startCapture called in uninitialized state");
- }
+
+ generateCapturerEvents.set(true);
if (surfaceHelper == null) {
- frameObserver.onCapturerStarted(false /* success */);
+ capturerObserver.onCapturerStarted(false /* success */);
if (eventsHandler != null) {
eventsHandler.onCameraError("No SurfaceTexture created.");
}
return;
}
- if (isCameraRunning.getAndSet(true)) {
- Logging.e(TAG, "Camera has already been started.");
- return;
- }
- final boolean didPost = maybePostOnCameraThread(new Runnable() {
+
+ postOnCameraThread(new Runnable() {
@Override
public void run() {
- openCameraAttempts = 0;
startCaptureOnCameraThread(width, height, framerate);
}
});
- 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) {
checkIsOnCameraThread();
- if (!isCameraRunning.get()) {
- Logging.e(TAG, "startCaptureOnCameraThread: Camera is stopped");
- return;
- }
- if (camera != null) {
- Logging.e(TAG, "startCaptureOnCameraThread: Camera has already been started.");
+
+ openCameraAttempts = 0;
+ firstFrameReported = false;
magjed_webrtc 2016/07/20 14:56:08 Move this line under the state check.
sakal 2016/07/21 11:17:24 Done.
+ if (cameraState != CameraState.IDLE) {
+ Logging.e(TAG, "Camera has already been started.");
return;
}
- this.firstFrameReported = false;
+ setCameraState(CameraState.STARTING);
+
+ requestedWidth = width;
+ requestedHeight = height;
+ requestedFramerate = framerate;
+
+ openCameraOnCameraThread();
+ }
+
+ private void openCameraOnCameraThread() {
try {
+ Logging.d(TAG, "Opening camera " + id);
+ if (eventsHandler != null) {
+ eventsHandler.onCameraOpening(id);
+ }
+
try {
- synchronized (cameraIdLock) {
- Logging.d(TAG, "Opening camera " + id);
- if (eventsHandler != null) {
- eventsHandler.onCameraOpening(id);
- }
- camera = android.hardware.Camera.open(id);
- info = new android.hardware.Camera.CameraInfo();
- android.hardware.Camera.getCameraInfo(id, info);
- }
+ camera = android.hardware.Camera.open(id);
} catch (RuntimeException e) {
openCameraAttempts++;
if (openCameraAttempts < MAX_OPEN_CAMERA_ATTEMPTS) {
Logging.e(TAG, "Camera.open failed, retrying", e);
- maybePostDelayedOnCameraThread(OPEN_CAMERA_DELAY_MS, new Runnable() {
+ postDelayedOnCameraThread(OPEN_CAMERA_DELAY_MS, new Runnable() {
@Override
public void run() {
- startCaptureOnCameraThread(width, height, framerate);
+ openCameraOnCameraThread();
}
});
return;
@@ -349,43 +366,52 @@ public class VideoCapturerAndroid implements
throw e;
}
+ setCameraState(CameraState.RUNNING);
+
+ info = new android.hardware.Camera.CameraInfo();
+ android.hardware.Camera.getCameraInfo(id, info);
+
camera.setPreviewTexture(surfaceHelper.getSurfaceTexture());
Logging.d(TAG, "Camera orientation: " + info.orientation +
" .Device orientation: " + getDeviceOrientation());
camera.setErrorCallback(cameraErrorCallback);
- startPreviewOnCameraThread(width, height, framerate);
- frameObserver.onCapturerStarted(true);
+ startPreviewOnCameraThread();
+ capturerObserver.onCapturerStarted(true);
if (isCapturingToTexture) {
surfaceHelper.startListening(this);
}
- // Start camera observer.
+ // Start camera statistics collector.
cameraStatistics = new CameraStatistics(surfaceHelper, eventsHandler);
} catch (IOException|RuntimeException e) {
Logging.e(TAG, "startCapture failed", e);
// Make sure the camera is released.
- stopCaptureOnCameraThread(true /* stopHandler */);
- frameObserver.onCapturerStarted(false);
+ releaseCameraOnCameraThread();
+ capturerObserver.onCapturerStarted(false);
if (eventsHandler != null) {
eventsHandler.onCameraError("Camera can not be started.");
}
- }
+ }
+
+ synchronized (cameraSwitchLock) {
magjed_webrtc 2016/07/20 14:56:08 This block should be moved inside the success path
sakal 2016/07/21 11:17:24 Done.
+ if (switchEventsHandler != null) {
+ switchEventsHandler.onCameraSwitchDone(
+ info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
+ }
+ switchEventsHandler = null;
+ }
}
// (Re)start preview with the closest supported format to |width| x |height| @ |framerate|.
- private void startPreviewOnCameraThread(int width, int height, int framerate) {
+ private void startPreviewOnCameraThread() {
checkIsOnCameraThread();
- if (!isCameraRunning.get() || camera == null) {
- Logging.e(TAG, "startPreviewOnCameraThread: Camera is stopped");
+ if (cameraState != CameraState.RUNNING) {
+ Logging.e(TAG, "startPreviewOnCameraThread: Camera is not running");
return;
}
- Logging.d(
- TAG, "startPreviewOnCameraThread requested: " + width + "x" + height + "@" + framerate);
-
- requestedWidth = width;
- requestedHeight = height;
- requestedFramerate = framerate;
+ Logging.d(TAG, "startPreviewOnCameraThread requested: "
+ + requestedWidth + "x" + requestedHeight + "@" + requestedFramerate);
// Find closest supported format for |width| x |height| @ |framerate|.
final android.hardware.Camera.Parameters parameters = camera.getParameters();
@@ -394,10 +420,12 @@ public class VideoCapturerAndroid implements
Logging.d(TAG, "Available fps ranges: " + supportedFramerates);
final CaptureFormat.FramerateRange fpsRange =
- CameraEnumerationAndroid.getClosestSupportedFramerateRange(supportedFramerates, framerate);
+ CameraEnumerationAndroid.getClosestSupportedFramerateRange(
+ supportedFramerates, requestedFramerate);
final Size previewSize = CameraEnumerationAndroid.getClosestSupportedSize(
- Camera1Enumerator.convertSizes(parameters.getSupportedPreviewSizes()), width, height);
+ Camera1Enumerator.convertSizes(parameters.getSupportedPreviewSizes()),
+ requestedWidth, requestedHeight);
final CaptureFormat captureFormat =
new CaptureFormat(previewSize.width, previewSize.height, fpsRange);
@@ -426,7 +454,8 @@ public class VideoCapturerAndroid implements
// Picture size is for taking pictures and not for preview/video, but we need to set it anyway
// as a workaround for an aspect ratio problem on Nexus 7.
final Size pictureSize = CameraEnumerationAndroid.getClosestSupportedSize(
- Camera1Enumerator.convertSizes(parameters.getSupportedPictureSizes()), width, height);
+ Camera1Enumerator.convertSizes(parameters.getSupportedPictureSizes()),
+ requestedWidth, requestedHeight);
parameters.setPictureSize(pictureSize.width, pictureSize.height);
// Temporarily stop preview if it's already running.
@@ -464,51 +493,75 @@ public class VideoCapturerAndroid implements
// Blocks until camera is known to be stopped.
@Override
- public void stopCapture() throws InterruptedException {
+ public void stopCapture() {
Logging.d(TAG, "stopCapture");
- final CountDownLatch barrier = new CountDownLatch(1);
- final boolean didPost = maybePostOnCameraThread(new Runnable() {
+
+ postOnCameraThread(new Runnable() {
@Override public void run() {
- stopCaptureOnCameraThread(true /* stopHandler */);
- barrier.countDown();
+ stopCaptureOnCameraThread();
}
});
- if (!didPost) {
- Logging.e(TAG, "Calling stopCapture() for already stopped camera.");
- return;
- }
- if (!barrier.await(CAMERA_STOP_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- Logging.e(TAG, "Camera stop timeout");
- printStackTrace();
- if (eventsHandler != null) {
- eventsHandler.onCameraError("Camera stop timeout");
+
+ synchronized (generateCapturerEvents) {
+ while (generateCapturerEvents.get()) {
+ try {
+ generateCapturerEvents.wait();
+ } catch (InterruptedException e) {
+ Logging.w(TAG, "Interrupt while waiting capturer to stop: "
+ + e.getMessage());
+ }
}
}
- frameObserver.onCapturerStopped();
+
Logging.d(TAG, "stopCapture done");
}
- private void stopCaptureOnCameraThread(boolean stopHandler) {
+ private void stopCaptureOnCameraThread() {
checkIsOnCameraThread();
Logging.d(TAG, "stopCaptureOnCameraThread");
- // Note that the camera might still not be started here if startCaptureOnCameraThread failed
- // and we posted a retry.
- // Make sure onTextureFrameAvailable() is not called anymore.
- if (surfaceHelper != null) {
- surfaceHelper.stopListening();
- }
- if (stopHandler) {
- // 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 (cameraState == CameraState.IDLE) {
+ Logging.d(TAG, "Calling stopCapture() for already stopped camera.");
magjed_webrtc 2016/07/20 14:56:08 You need to notify generateCapturerEvents here.
sakal 2016/07/21 11:17:24 I modified code to use the state instead.
+ return;
}
+
+ final CameraState oldState = cameraState;
+
+ // 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|.
+ cameraThreadHandler.removeCallbacksAndMessages(this /* token */);
+ setCameraState(CameraState.IDLE); // No more frames will be delivered
+ synchronized (generateCapturerEvents) {
+ generateCapturerEvents.set(false);
+ generateCapturerEvents.notifyAll();
+ }
+
+ if (oldState == CameraState.STARTING) {
+ Logging.d(TAG, "Camera starting while calling stopCapture, cancelling.");
+ setCameraState(CameraState.IDLE);
+ return;
+ }
+
+ capturerObserver.onCapturerStopped();
magjed_webrtc 2016/07/20 14:56:07 I think you should notify capturerObserver and eve
sakal 2016/07/21 11:17:24 Done.
+
+ releaseCameraOnCameraThread();
+ if (eventsHandler != null) {
+ eventsHandler.onCameraClosed();
+ }
+
+ Logging.d(TAG, "stopCaptureOnCameraThread done");
+ }
+
+ private void releaseCameraOnCameraThread() {
+ checkIsOnCameraThread();
+
+ // Make sure onTextureFrameAvailable() is not called anymore.
+ surfaceHelper.stopListening();
if (cameraStatistics != null) {
cameraStatistics.release();
cameraStatistics = null;
@@ -520,30 +573,30 @@ public class VideoCapturerAndroid implements
}
queuedBuffers.clear();
captureFormat = null;
-
Logging.d(TAG, "Release camera.");
if (camera != null) {
camera.release();
camera = null;
}
- if (eventsHandler != null) {
- eventsHandler.onCameraClosed();
- }
- Logging.d(TAG, "stopCaptureOnCameraThread done");
}
private void switchCameraOnCameraThread() {
checkIsOnCameraThread();
- if (!isCameraRunning.get()) {
+ Logging.d(TAG, "switchCameraOnCameraThread");
+
+ if (cameraState == CameraState.IDLE) {
magjed_webrtc 2016/07/20 14:56:07 Check for UNINITIALIZED as well? Or make the oppos
sakal 2016/07/21 11:17:24 I made every public function to check if camera is
Logging.e(TAG, "switchCameraOnCameraThread: Camera is stopped");
+ switchEventsHandler.onCameraSwitchError("Camera is stopped.");
return;
}
- Logging.d(TAG, "switchCameraOnCameraThread");
- stopCaptureOnCameraThread(false /* stopHandler */);
+
+ stopCaptureOnCameraThread();
synchronized (cameraIdLock) {
id = (id + 1) % android.hardware.Camera.getNumberOfCameras();
}
- startCaptureOnCameraThread(requestedWidth, requestedHeight, requestedFramerate);
+ startCaptureOnCameraThread(requestedWidth, requestedHeight,
+ requestedFramerate);
+
Logging.d(TAG, "switchCameraOnCameraThread done");
}
@@ -551,7 +604,7 @@ public class VideoCapturerAndroid implements
checkIsOnCameraThread();
Logging.d(TAG, "onOutputFormatRequestOnCameraThread: " + width + "x" + height +
"@" + framerate);
- frameObserver.onOutputFormatRequest(width, height, framerate);
+ capturerObserver.onOutputFormatRequest(width, height, framerate);
}
private int getDeviceOrientation() {
@@ -589,8 +642,9 @@ public class VideoCapturerAndroid implements
@Override
public void onPreviewFrame(byte[] data, android.hardware.Camera callbackCamera) {
checkIsOnCameraThread();
- if (!isCameraRunning.get()) {
- Logging.e(TAG, "onPreviewFrame: Camera is stopped");
+
+ if (cameraState != CameraState.RUNNING) {
+ Logging.d(TAG, "onPreviewFrame: Camera is stopped");
return;
}
if (!queuedBuffers.contains(data)) {
@@ -610,7 +664,7 @@ public class VideoCapturerAndroid implements
}
cameraStatistics.addFrame();
- frameObserver.onByteBufferFrameCaptured(data, captureFormat.width, captureFormat.height,
+ capturerObserver.onByteBufferFrameCaptured(data, captureFormat.width, captureFormat.height,
getFrameOrientation(), captureTimeNs);
camera.addCallbackBuffer(data);
}
@@ -619,8 +673,9 @@ public class VideoCapturerAndroid implements
public void onTextureFrameAvailable(
int oesTextureId, float[] transformMatrix, long timestampNs) {
checkIsOnCameraThread();
- if (!isCameraRunning.get()) {
- Logging.e(TAG, "onTextureFrameAvailable: Camera is stopped");
+
+ if (cameraState != CameraState.RUNNING) {
+ Logging.d(TAG, "onTextureFrameAvailable: Camera is stopped");
surfaceHelper.returnTextureFrame();
return;
}
@@ -637,7 +692,7 @@ public class VideoCapturerAndroid implements
RendererCommon.multiplyMatrices(transformMatrix, RendererCommon.horizontalFlipMatrix());
}
cameraStatistics.addFrame();
- frameObserver.onTextureFrameCaptured(captureFormat.width, captureFormat.height, oesTextureId,
+ capturerObserver.onTextureFrameCaptured(captureFormat.width, captureFormat.height, oesTextureId,
transformMatrix, rotation, timestampNs);
}
}

Powered by Google App Engine
This is Rietveld 408576698