From d6a0efdc86f61b198b800dba301f53f847eb9ba0 Mon Sep 17 00:00:00 2001 From: "fischman@webrtc.org" Date: Wed, 28 May 2014 18:37:07 +0000 Subject: [PATCH] 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 --- .../videoengine/VideoCaptureAndroid.java | 55 +++++++++++++------ 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java b/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java index 80f6f63233..0e555f9083 100644 --- a/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java +++ b/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/VideoCaptureAndroid.java @@ -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 handlerExchanger = new Exchanger(); - 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 handlerExchanger = new Exchanger(); + cameraThread = new CameraThread(handlerExchanger); + cameraThread.start(); + cameraThreadHandler = exchange(handlerExchanger, null); + final Exchanger result = new Exchanger(); 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 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 result = new Exchanger(); + 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 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 result = new Exchanger(); @@ -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 result = new Exchanger();