From bd76607abb712f98c01709f240f147e4bd49df6d Mon Sep 17 00:00:00 2001 From: magjed Date: Thu, 19 May 2016 04:22:58 -0700 Subject: [PATCH] Revert of Android: Make base interface for camera1 and camera2 (patchset #1 id:1 of https://codereview.webrtc.org/1994893002/ ) Reason for revert: Still breaks downstream import. Original issue's description: > Reland of Android: Make base interface for camera1 and camera2 (patchset #1 id:1 of https://codereview.webrtc.org/1979583002/ ) > > Reason for revert: > Downstream code has been updated. > > Original issue's description: > > Revert of Android: Make base interface for camera1 and camera2 (patchset #3 id:80001 of https://codereview.webrtc.org/1895483002/ ) > > > > Reason for revert: > > Breaks downstream import. > > > > Original issue's description: > > > Android: Make base interface for camera1 and camera2 > > > > > > This CL adds a new interface CameraVideoCapturer that extends VideoCapturer with a switchCamera() function. It also moves moves CameraEventsHandler, CameraStatistics, and CameraSwitchHandler from VideoCapturerAndroid to this new interface. The purpose is to prepare for a camera2 implementation that will use the same interfaces and helper class. > > > > > > BUG=webrtc:5519 > > > > > > Committed: https://crrev.com/6bdacaddfb18edef1f0cdd778209f6b05a8f9210 > > > Cr-Commit-Position: refs/heads/master@{#12723} > > > > TBR=perkj@webrtc.org > > # Skipping CQ checks because original CL landed less than 1 days ago. > > NOPRESUBMIT=true > > NOTREECHECKS=true > > NOTRY=true > > BUG=webrtc:5519 > > > > Committed: https://crrev.com/181b5ffdf036427d92929667d9d43bbcff560435 > > Cr-Commit-Position: refs/heads/master@{#12727} > > TBR=perkj@webrtc.org > # Not skipping CQ checks because original CL landed more than 1 days ago. > BUG=webrtc:5519 > > Committed: https://crrev.com/d269b023bfe1c321798fe9c8dbd631a562914fe1 > Cr-Commit-Position: refs/heads/master@{#12807} TBR=perkj@webrtc.org # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=webrtc:5519 Review-Url: https://codereview.webrtc.org/1994013004 Cr-Commit-Position: refs/heads/master@{#12809} --- .../org/webrtc/CameraVideoCapturer.java | 128 ------------------ .../org/webrtc/VideoCapturerAndroid.java | 95 +++++++++++-- 2 files changed, 86 insertions(+), 137 deletions(-) delete mode 100644 webrtc/api/java/android/org/webrtc/CameraVideoCapturer.java diff --git a/webrtc/api/java/android/org/webrtc/CameraVideoCapturer.java b/webrtc/api/java/android/org/webrtc/CameraVideoCapturer.java deleted file mode 100644 index 46432d4619..0000000000 --- a/webrtc/api/java/android/org/webrtc/CameraVideoCapturer.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -package org.webrtc; - -/** - * Base interface for camera1 and camera2 implementations. Extends VideoCapturer with a - * switchCamera() function. Also provides subinterfaces for handling camera events, and a helper - * class for detecting camera freezes. - */ -public interface CameraVideoCapturer extends VideoCapturer { - /** - * Camera events handler - can be used to be notifed about camera events. The callbacks are - * executed from an arbitrary thread. - */ - public 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 started. - void onFirstFrameAvailable(); - - // Callback invoked when camera is 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); - } - - /** - * Switch camera to the next valid camera id. This can only be called while the camera is running. - * This function can be called from any thread. - */ - void switchCamera(CameraSwitchHandler switchEventsHandler); - - /** - * Helper class to log framerate and detect if the camera freezes. It will run periodic callbacks - * on the SurfaceTextureHelper thread passed in the ctor, and should only be operated from that - * thread. - */ - public static class CameraStatistics { - private final static String TAG = "CameraStatistics"; - private final static int CAMERA_OBSERVER_PERIOD_MS = 2000; - private final static int CAMERA_FREEZE_REPORT_TIMOUT_MS = 4000; - - private final SurfaceTextureHelper surfaceTextureHelper; - private final CameraEventsHandler eventsHandler; - private int frameCount; - private int freezePeriodCount; - // Camera observer - monitors camera framerate. Observer is executed on camera thread. - private final Runnable cameraObserver = new Runnable() { - @Override - public void run() { - final int cameraFps = Math.round(frameCount * 1000.0f / CAMERA_OBSERVER_PERIOD_MS); - Logging.d(TAG, "Camera fps: " + cameraFps +"."); - if (frameCount == 0) { - ++freezePeriodCount; - if (CAMERA_OBSERVER_PERIOD_MS * freezePeriodCount >= CAMERA_FREEZE_REPORT_TIMOUT_MS - && eventsHandler != null) { - Logging.e(TAG, "Camera freezed."); - if (surfaceTextureHelper.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; - } - frameCount = 0; - surfaceTextureHelper.getHandler().postDelayed(this, CAMERA_OBSERVER_PERIOD_MS); - } - }; - - public CameraStatistics( - SurfaceTextureHelper surfaceTextureHelper, CameraEventsHandler eventsHandler) { - if (surfaceTextureHelper == null) { - throw new IllegalArgumentException("SurfaceTextureHelper is null"); - } - this.surfaceTextureHelper = surfaceTextureHelper; - this.eventsHandler = eventsHandler; - this.frameCount = 0; - this.freezePeriodCount = 0; - surfaceTextureHelper.getHandler().postDelayed(cameraObserver, CAMERA_OBSERVER_PERIOD_MS); - } - - private void checkThread() { - if (Thread.currentThread() != surfaceTextureHelper.getHandler().getLooper().getThread()) { - throw new IllegalStateException("Wrong thread"); - } - } - - public void addFrame() { - checkThread(); - ++frameCount; - } - - public void release() { - checkThread(); - surfaceTextureHelper.getHandler().removeCallbacks(cameraObserver); - } - } -} diff --git a/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java b/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java index 6352bf799f..78d042df50 100644 --- a/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java +++ b/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java @@ -38,13 +38,14 @@ import java.util.concurrent.TimeUnit; // 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 @@ public class VideoCapturerAndroid implements 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 @@ public class VideoCapturerAndroid implements } }; + // 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 @@ public class VideoCapturerAndroid implements // 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 @@ public class VideoCapturerAndroid implements this.id = cameraId; this.eventsHandler = eventsHandler; isCapturingToTexture = captureToTexture; + cameraStatistics = new CameraStatistics(); Logging.d(TAG, "VideoCapturerAndroid isCapturingToTexture : " + isCapturingToTexture); } @@ -381,7 +460,7 @@ public class VideoCapturerAndroid implements } // Start camera observer. - cameraStatistics = new CameraStatistics(surfaceHelper, eventsHandler); + maybePostDelayedOnCameraThread(CAMERA_OBSERVER_PERIOD_MS, cameraObserver); return; } catch (RuntimeException e) { error = e; @@ -534,10 +613,8 @@ public class VideoCapturerAndroid implements 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();