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}
This commit is contained in:
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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
|
// 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
|
// camera thread. The internal *OnCameraThread() methods must check |camera| for null to check if
|
||||||
// the camera has been stopped.
|
// the camera has been stopped.
|
||||||
// TODO(magjed): This class name is now confusing - rename to Camera1VideoCapturer.
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class VideoCapturerAndroid implements
|
public class VideoCapturerAndroid implements
|
||||||
CameraVideoCapturer,
|
VideoCapturer,
|
||||||
android.hardware.Camera.PreviewCallback,
|
android.hardware.Camera.PreviewCallback,
|
||||||
SurfaceTextureHelper.OnTextureFrameAvailableListener {
|
SurfaceTextureHelper.OnTextureFrameAvailableListener {
|
||||||
private final static String TAG = "VideoCapturerAndroid";
|
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 static final int CAMERA_STOP_TIMEOUT_MS = 7000;
|
||||||
|
|
||||||
private boolean isDisposed = false;
|
private boolean isDisposed = false;
|
||||||
@ -59,7 +60,7 @@ public class VideoCapturerAndroid implements
|
|||||||
private final Object cameraIdLock = new Object();
|
private final Object cameraIdLock = new Object();
|
||||||
private int id;
|
private int id;
|
||||||
private android.hardware.Camera.CameraInfo info;
|
private android.hardware.Camera.CameraInfo info;
|
||||||
private CameraStatistics cameraStatistics;
|
private final CameraStatistics cameraStatistics;
|
||||||
// Remember the requested format in case we want to switch cameras.
|
// Remember the requested format in case we want to switch cameras.
|
||||||
private int requestedWidth;
|
private int requestedWidth;
|
||||||
private int requestedHeight;
|
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,
|
public static VideoCapturerAndroid create(String name,
|
||||||
CameraEventsHandler eventsHandler) {
|
CameraEventsHandler eventsHandler) {
|
||||||
return VideoCapturerAndroid.create(name, eventsHandler, false /* captureToTexture */);
|
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
|
// Switch camera to the next valid camera id. This can only be called while
|
||||||
// the camera is running.
|
// the camera is running.
|
||||||
@Override
|
|
||||||
public void switchCamera(final CameraSwitchHandler switchEventsHandler) {
|
public void switchCamera(final CameraSwitchHandler switchEventsHandler) {
|
||||||
if (android.hardware.Camera.getNumberOfCameras() < 2) {
|
if (android.hardware.Camera.getNumberOfCameras() < 2) {
|
||||||
if (switchEventsHandler != null) {
|
if (switchEventsHandler != null) {
|
||||||
@ -221,6 +299,7 @@ public class VideoCapturerAndroid implements
|
|||||||
this.id = cameraId;
|
this.id = cameraId;
|
||||||
this.eventsHandler = eventsHandler;
|
this.eventsHandler = eventsHandler;
|
||||||
isCapturingToTexture = captureToTexture;
|
isCapturingToTexture = captureToTexture;
|
||||||
|
cameraStatistics = new CameraStatistics();
|
||||||
Logging.d(TAG, "VideoCapturerAndroid isCapturingToTexture : " + isCapturingToTexture);
|
Logging.d(TAG, "VideoCapturerAndroid isCapturingToTexture : " + isCapturingToTexture);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +460,7 @@ public class VideoCapturerAndroid implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start camera observer.
|
// Start camera observer.
|
||||||
cameraStatistics = new CameraStatistics(surfaceHelper, eventsHandler);
|
maybePostDelayedOnCameraThread(CAMERA_OBSERVER_PERIOD_MS, cameraObserver);
|
||||||
return;
|
return;
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
error = e;
|
error = e;
|
||||||
@ -534,10 +613,8 @@ public class VideoCapturerAndroid implements
|
|||||||
if (surfaceHelper != null) {
|
if (surfaceHelper != null) {
|
||||||
surfaceHelper.stopListening();
|
surfaceHelper.stopListening();
|
||||||
}
|
}
|
||||||
if (cameraStatistics != null) {
|
cameraThreadHandler.removeCallbacks(cameraObserver);
|
||||||
cameraStatistics.release();
|
cameraStatistics.getAndResetFrameCount();
|
||||||
cameraStatistics = null;
|
|
||||||
}
|
|
||||||
Logging.d(TAG, "Stop preview.");
|
Logging.d(TAG, "Stop preview.");
|
||||||
if (camera != null) {
|
if (camera != null) {
|
||||||
camera.stopPreview();
|
camera.stopPreview();
|
||||||
|
|||||||
Reference in New Issue
Block a user