| Index: webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java
|
| diff --git a/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java b/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java
|
| index 6352bf799f7be0a74364197a6c1756091dc736e6..78d042df50c850bf468739907953deee2bb6eab0 100644
|
| --- a/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java
|
| +++ b/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java
|
| @@ -38,13 +38,14 @@
|
| // arbitrary Java threads. All public entry points are thread safe, and delegate the work to the
|
| // camera thread. The internal *OnCameraThread() methods must check |camera| for null to check if
|
| // the camera has been stopped.
|
| -// TODO(magjed): This class name is now confusing - rename to Camera1VideoCapturer.
|
| @SuppressWarnings("deprecation")
|
| public class VideoCapturerAndroid implements
|
| - CameraVideoCapturer,
|
| + VideoCapturer,
|
| android.hardware.Camera.PreviewCallback,
|
| SurfaceTextureHelper.OnTextureFrameAvailableListener {
|
| private final static String TAG = "VideoCapturerAndroid";
|
| + private final static int CAMERA_OBSERVER_PERIOD_MS = 2000;
|
| + private final static int CAMERA_FREEZE_REPORT_TIMOUT_MS = 4000;
|
| private static final int CAMERA_STOP_TIMEOUT_MS = 7000;
|
|
|
| private boolean isDisposed = false;
|
| @@ -59,7 +60,7 @@
|
| private final Object cameraIdLock = new Object();
|
| private int id;
|
| private android.hardware.Camera.CameraInfo info;
|
| - private CameraStatistics cameraStatistics;
|
| + private final CameraStatistics cameraStatistics;
|
| // Remember the requested format in case we want to switch cameras.
|
| private int requestedWidth;
|
| private int requestedHeight;
|
| @@ -103,6 +104,84 @@
|
| }
|
| };
|
|
|
| + // Camera observer - monitors camera framerate. Observer is executed on camera thread.
|
| + private final Runnable cameraObserver = new Runnable() {
|
| + private int freezePeriodCount;
|
| + @Override
|
| + public void run() {
|
| + int cameraFramesCount = cameraStatistics.getAndResetFrameCount();
|
| + int cameraFps = (cameraFramesCount * 1000 + CAMERA_OBSERVER_PERIOD_MS / 2)
|
| + / CAMERA_OBSERVER_PERIOD_MS;
|
| +
|
| + Logging.d(TAG, "Camera fps: " + cameraFps +".");
|
| + if (cameraFramesCount == 0) {
|
| + ++freezePeriodCount;
|
| + if (CAMERA_OBSERVER_PERIOD_MS * freezePeriodCount >= CAMERA_FREEZE_REPORT_TIMOUT_MS
|
| + && eventsHandler != null) {
|
| + Logging.e(TAG, "Camera freezed.");
|
| + if (surfaceHelper.isTextureInUse()) {
|
| + // This can only happen if we are capturing to textures.
|
| + eventsHandler.onCameraFreezed("Camera failure. Client must return video buffers.");
|
| + } else {
|
| + eventsHandler.onCameraFreezed("Camera failure.");
|
| + }
|
| + return;
|
| + }
|
| + } else {
|
| + freezePeriodCount = 0;
|
| + }
|
| + maybePostDelayedOnCameraThread(CAMERA_OBSERVER_PERIOD_MS, this);
|
| + }
|
| + };
|
| +
|
| + private static class CameraStatistics {
|
| + private int frameCount = 0;
|
| + private final ThreadUtils.ThreadChecker threadChecker = new ThreadUtils.ThreadChecker();
|
| +
|
| + CameraStatistics() {
|
| + threadChecker.detachThread();
|
| + }
|
| +
|
| + public void addFrame() {
|
| + threadChecker.checkIsOnValidThread();
|
| + ++frameCount;
|
| + }
|
| +
|
| + public int getAndResetFrameCount() {
|
| + threadChecker.checkIsOnValidThread();
|
| + int count = frameCount;
|
| + frameCount = 0;
|
| + return count;
|
| + }
|
| + }
|
| +
|
| + public static interface CameraEventsHandler {
|
| + // Camera error handler - invoked when camera can not be opened
|
| + // or any camera exception happens on camera thread.
|
| + void onCameraError(String errorDescription);
|
| +
|
| + // Invoked when camera stops receiving frames
|
| + void onCameraFreezed(String errorDescription);
|
| +
|
| + // Callback invoked when camera is opening.
|
| + void onCameraOpening(int cameraId);
|
| +
|
| + // Callback invoked when first camera frame is available after camera is opened.
|
| + void onFirstFrameAvailable();
|
| +
|
| + // Callback invoked when camera closed.
|
| + void onCameraClosed();
|
| + }
|
| +
|
| + // Camera switch handler - one of these functions are invoked with the result of switchCamera().
|
| + // The callback may be called on an arbitrary thread.
|
| + public interface CameraSwitchHandler {
|
| + // Invoked on success. |isFrontCamera| is true if the new camera is front facing.
|
| + void onCameraSwitchDone(boolean isFrontCamera);
|
| + // Invoked on failure, e.g. camera is stopped or only one camera available.
|
| + void onCameraSwitchError(String errorDescription);
|
| + }
|
| +
|
| public static VideoCapturerAndroid create(String name,
|
| CameraEventsHandler eventsHandler) {
|
| return VideoCapturerAndroid.create(name, eventsHandler, false /* captureToTexture */);
|
| @@ -137,7 +216,6 @@
|
|
|
| // Switch camera to the next valid camera id. This can only be called while
|
| // the camera is running.
|
| - @Override
|
| public void switchCamera(final CameraSwitchHandler switchEventsHandler) {
|
| if (android.hardware.Camera.getNumberOfCameras() < 2) {
|
| if (switchEventsHandler != null) {
|
| @@ -221,6 +299,7 @@
|
| this.id = cameraId;
|
| this.eventsHandler = eventsHandler;
|
| isCapturingToTexture = captureToTexture;
|
| + cameraStatistics = new CameraStatistics();
|
| Logging.d(TAG, "VideoCapturerAndroid isCapturingToTexture : " + isCapturingToTexture);
|
| }
|
|
|
| @@ -381,7 +460,7 @@
|
| }
|
|
|
| // Start camera observer.
|
| - cameraStatistics = new CameraStatistics(surfaceHelper, eventsHandler);
|
| + maybePostDelayedOnCameraThread(CAMERA_OBSERVER_PERIOD_MS, cameraObserver);
|
| return;
|
| } catch (RuntimeException e) {
|
| error = e;
|
| @@ -534,10 +613,8 @@
|
| if (surfaceHelper != null) {
|
| surfaceHelper.stopListening();
|
| }
|
| - if (cameraStatistics != null) {
|
| - cameraStatistics.release();
|
| - cameraStatistics = null;
|
| - }
|
| + cameraThreadHandler.removeCallbacks(cameraObserver);
|
| + cameraStatistics.getAndResetFrameCount();
|
| Logging.d(TAG, "Stop preview.");
|
| if (camera != null) {
|
| camera.stopPreview();
|
|
|