VideoCaptureAndroid: quit & join the camera thread on stopCapture.

Also fix latent bug where setPreviewRotation() wouldn't hold
the lock while its delegate setPreviewRotationOnCameraThread()
was running, allowing the camera to be freed between the
null-check and the use.

BUG=3389
R=wu@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/17619007

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6266 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
fischman@webrtc.org 2014-05-28 18:37:07 +00:00
parent 43a1395370
commit d6a0efdc86

View File

@ -66,10 +66,6 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
this.native_capturer = native_capturer;
this.info = new Camera.CameraInfo();
Camera.getCameraInfo(id, info);
Exchanger<Handler> handlerExchanger = new Exchanger<Handler>();
cameraThread = new CameraThread(handlerExchanger);
cameraThread.start();
cameraThreadHandler = exchange(handlerExchanger, null);
}
private class CameraThread extends Thread {
@ -93,6 +89,14 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
private synchronized boolean startCapture(
final int width, final int height,
final int min_mfps, final int max_mfps) {
if (cameraThread != null || cameraThreadHandler != null) {
throw new RuntimeException("Camera thread already started!");
}
Exchanger<Handler> handlerExchanger = new Exchanger<Handler>();
cameraThread = new CameraThread(handlerExchanger);
cameraThread.start();
cameraThreadHandler = exchange(handlerExchanger, null);
final Exchanger<Boolean> result = new Exchanger<Boolean>();
cameraThreadHandler.post(new Runnable() {
@Override public void run() {
@ -174,12 +178,21 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
stopCaptureOnCameraThread(result);
}
});
return exchange(result, false); // |false| is a dummy value here.
boolean status = exchange(result, false); // |false| is a dummy value here.
try {
cameraThread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
cameraThreadHandler = null;
cameraThread = null;
return status;
}
private void stopCaptureOnCameraThread(
Exchanger<Boolean> result) {
Log.d(TAG, "stopCapture");
Looper.myLooper().quit();
if (camera == null) {
throw new RuntimeException("Camera is already stopped!");
}
@ -225,19 +238,24 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
// Does not affect the captured video image.
// Called by native code.
private synchronized void setPreviewRotation(final int rotation) {
cameraThreadHandler.post(new Runnable() {
@Override public void run() {
setPreviewRotationOnCameraThread(rotation);
}
});
}
private void setPreviewRotationOnCameraThread(int rotation) {
Log.v(TAG, "setPreviewRotation:" + rotation);
if (camera == null) {
if (camera == null || cameraThreadHandler == null) {
return;
}
final Exchanger<IOException> result = new Exchanger<IOException>();
cameraThreadHandler.post(new Runnable() {
@Override public void run() {
setPreviewRotationOnCameraThread(rotation, result);
}
});
// Use the exchanger below to block this function until
// setPreviewRotationOnCameraThread() completes, holding the synchronized
// lock for the duration. The exchanged value itself is ignored.
exchange(result, null);
}
private void setPreviewRotationOnCameraThread(
int rotation, Exchanger<IOException> result) {
Log.v(TAG, "setPreviewRotation:" + rotation);
int resultRotation = 0;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
@ -249,6 +267,7 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
resultRotation = rotation;
}
camera.setDisplayOrientation(resultRotation);
exchange(result, null);
}
public synchronized void surfaceChanged(
@ -259,7 +278,7 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
public synchronized void surfaceCreated(final SurfaceHolder holder) {
Log.d(TAG, "VideoCaptureAndroid::surfaceCreated");
if (camera == null) {
if (camera == null || cameraThreadHandler == null) {
return;
}
final Exchanger<IOException> result = new Exchanger<IOException>();
@ -276,7 +295,7 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
public synchronized void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "VideoCaptureAndroid::surfaceDestroyed");
if (camera == null) {
if (camera == null || cameraThreadHandler == null) {
return;
}
final Exchanger<IOException> result = new Exchanger<IOException>();