| Index: webrtc/api/android/java/src/org/webrtc/Camera2Session.java
|
| diff --git a/webrtc/api/android/java/src/org/webrtc/Camera2Session.java b/webrtc/api/android/java/src/org/webrtc/Camera2Session.java
|
| deleted file mode 100644
|
| index 2552b2413e373263baf3e2039ed3617607f82726..0000000000000000000000000000000000000000
|
| --- a/webrtc/api/android/java/src/org/webrtc/Camera2Session.java
|
| +++ /dev/null
|
| @@ -1,450 +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;
|
| -
|
| -import android.annotation.TargetApi;
|
| -import android.content.Context;
|
| -import android.graphics.SurfaceTexture;
|
| -import android.hardware.camera2.CameraAccessException;
|
| -import android.hardware.camera2.CameraCaptureSession;
|
| -import android.hardware.camera2.CameraCharacteristics;
|
| -import android.hardware.camera2.CameraDevice;
|
| -import android.hardware.camera2.CameraManager;
|
| -import android.hardware.camera2.CameraMetadata;
|
| -import android.hardware.camera2.CaptureFailure;
|
| -import android.hardware.camera2.CaptureRequest;
|
| -import android.os.Handler;
|
| -import android.util.Range;
|
| -import android.view.Surface;
|
| -import android.view.WindowManager;
|
| -import java.util.Arrays;
|
| -import java.util.List;
|
| -import java.util.concurrent.TimeUnit;
|
| -import org.webrtc.CameraEnumerationAndroid.CaptureFormat;
|
| -
|
| -@TargetApi(21)
|
| -public class Camera2Session implements CameraSession {
|
| - private static final String TAG = "Camera2Session";
|
| -
|
| - private static final Histogram camera2StartTimeMsHistogram =
|
| - Histogram.createCounts("WebRTC.Android.Camera2.StartTimeMs", 1, 10000, 50);
|
| - private static final Histogram camera2StopTimeMsHistogram =
|
| - Histogram.createCounts("WebRTC.Android.Camera2.StopTimeMs", 1, 10000, 50);
|
| - private static final Histogram camera2ResolutionHistogram = Histogram.createEnumeration(
|
| - "WebRTC.Android.Camera2.Resolution", CameraEnumerationAndroid.COMMON_RESOLUTIONS.size());
|
| -
|
| - private static enum SessionState { RUNNING, STOPPED }
|
| -
|
| - private final Handler cameraThreadHandler;
|
| - private final CreateSessionCallback callback;
|
| - private final Events events;
|
| - private final Context applicationContext;
|
| - private final CameraManager cameraManager;
|
| - private final SurfaceTextureHelper surfaceTextureHelper;
|
| - private final String cameraId;
|
| - private final int width;
|
| - private final int height;
|
| - private final int framerate;
|
| -
|
| - // Initialized at start
|
| - private CameraCharacteristics cameraCharacteristics;
|
| - private int cameraOrientation;
|
| - private boolean isCameraFrontFacing;
|
| - private int fpsUnitFactor;
|
| - private CaptureFormat captureFormat;
|
| -
|
| - // Initialized when camera opens
|
| - private CameraDevice cameraDevice;
|
| - private Surface surface;
|
| -
|
| - // Initialized when capture session is created
|
| - private CameraCaptureSession captureSession;
|
| -
|
| - // State
|
| - private SessionState state = SessionState.RUNNING;
|
| - private boolean firstFrameReported = false;
|
| -
|
| - // Used only for stats. Only used on the camera thread.
|
| - private final long constructionTimeNs; // Construction time of this class.
|
| -
|
| - private class CameraStateCallback extends CameraDevice.StateCallback {
|
| - private String getErrorDescription(int errorCode) {
|
| - switch (errorCode) {
|
| - case CameraDevice.StateCallback.ERROR_CAMERA_DEVICE:
|
| - return "Camera device has encountered a fatal error.";
|
| - case CameraDevice.StateCallback.ERROR_CAMERA_DISABLED:
|
| - return "Camera device could not be opened due to a device policy.";
|
| - case CameraDevice.StateCallback.ERROR_CAMERA_IN_USE:
|
| - return "Camera device is in use already.";
|
| - case CameraDevice.StateCallback.ERROR_CAMERA_SERVICE:
|
| - return "Camera service has encountered a fatal error.";
|
| - case CameraDevice.StateCallback.ERROR_MAX_CAMERAS_IN_USE:
|
| - return "Camera device could not be opened because"
|
| - + " there are too many other open camera devices.";
|
| - default:
|
| - return "Unknown camera error: " + errorCode;
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void onDisconnected(CameraDevice camera) {
|
| - checkIsOnCameraThread();
|
| - final boolean startFailure = (captureSession == null);
|
| - state = SessionState.STOPPED;
|
| - stopInternal();
|
| - if (startFailure) {
|
| - callback.onFailure("Camera disconnected / evicted.");
|
| - } else {
|
| - events.onCameraDisconnected(Camera2Session.this);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void onError(CameraDevice camera, int errorCode) {
|
| - checkIsOnCameraThread();
|
| - reportError(getErrorDescription(errorCode));
|
| - }
|
| -
|
| - @Override
|
| - public void onOpened(CameraDevice camera) {
|
| - checkIsOnCameraThread();
|
| -
|
| - Logging.d(TAG, "Camera opened.");
|
| - cameraDevice = camera;
|
| -
|
| - final SurfaceTexture surfaceTexture = surfaceTextureHelper.getSurfaceTexture();
|
| - surfaceTexture.setDefaultBufferSize(captureFormat.width, captureFormat.height);
|
| - surface = new Surface(surfaceTexture);
|
| - try {
|
| - camera.createCaptureSession(
|
| - Arrays.asList(surface), new CaptureSessionCallback(), cameraThreadHandler);
|
| - } catch (CameraAccessException e) {
|
| - reportError("Failed to create capture session. " + e);
|
| - return;
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void onClosed(CameraDevice camera) {
|
| - checkIsOnCameraThread();
|
| -
|
| - Logging.d(TAG, "Camera device closed.");
|
| - events.onCameraClosed(Camera2Session.this);
|
| - }
|
| - }
|
| -
|
| - private class CaptureSessionCallback extends CameraCaptureSession.StateCallback {
|
| - @Override
|
| - public void onConfigureFailed(CameraCaptureSession session) {
|
| - checkIsOnCameraThread();
|
| - session.close();
|
| - reportError("Failed to configure capture session.");
|
| - }
|
| -
|
| - @Override
|
| - public void onConfigured(CameraCaptureSession session) {
|
| - checkIsOnCameraThread();
|
| - Logging.d(TAG, "Camera capture session configured.");
|
| - captureSession = session;
|
| - try {
|
| - /*
|
| - * The viable options for video capture requests are:
|
| - * TEMPLATE_PREVIEW: High frame rate is given priority over the highest-quality
|
| - * post-processing.
|
| - * TEMPLATE_RECORD: Stable frame rate is used, and post-processing is set for recording
|
| - * quality.
|
| - */
|
| - final CaptureRequest.Builder captureRequestBuilder =
|
| - cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
|
| - // Set auto exposure fps range.
|
| - captureRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
|
| - new Range<Integer>(captureFormat.framerate.min / fpsUnitFactor,
|
| - captureFormat.framerate.max / fpsUnitFactor));
|
| - captureRequestBuilder.set(
|
| - CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
|
| - captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
|
| - chooseStabilizationMode(captureRequestBuilder);
|
| - chooseFocusMode(captureRequestBuilder);
|
| -
|
| - captureRequestBuilder.addTarget(surface);
|
| - session.setRepeatingRequest(
|
| - captureRequestBuilder.build(), new CameraCaptureCallback(), cameraThreadHandler);
|
| - } catch (CameraAccessException e) {
|
| - reportError("Failed to start capture request. " + e);
|
| - return;
|
| - }
|
| -
|
| - surfaceTextureHelper.startListening(
|
| - new SurfaceTextureHelper.OnTextureFrameAvailableListener() {
|
| - @Override
|
| - public void onTextureFrameAvailable(
|
| - int oesTextureId, float[] transformMatrix, long timestampNs) {
|
| - checkIsOnCameraThread();
|
| -
|
| - if (state != SessionState.RUNNING) {
|
| - Logging.d(TAG, "Texture frame captured but camera is no longer running.");
|
| - surfaceTextureHelper.returnTextureFrame();
|
| - return;
|
| - }
|
| -
|
| - if (!firstFrameReported) {
|
| - firstFrameReported = true;
|
| - final int startTimeMs =
|
| - (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - constructionTimeNs);
|
| - camera2StartTimeMsHistogram.addSample(startTimeMs);
|
| - }
|
| -
|
| - int rotation = getFrameOrientation();
|
| - if (isCameraFrontFacing) {
|
| - // Undo the mirror that the OS "helps" us with.
|
| - // http://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation(int)
|
| - transformMatrix = RendererCommon.multiplyMatrices(
|
| - transformMatrix, RendererCommon.horizontalFlipMatrix());
|
| - }
|
| -
|
| - // Undo camera orientation - we report it as rotation instead.
|
| - transformMatrix =
|
| - RendererCommon.rotateTextureMatrix(transformMatrix, -cameraOrientation);
|
| -
|
| - events.onTextureFrameCaptured(Camera2Session.this, captureFormat.width,
|
| - captureFormat.height, oesTextureId, transformMatrix, rotation, timestampNs);
|
| - }
|
| - });
|
| - Logging.d(TAG, "Camera device successfully started.");
|
| - callback.onDone(Camera2Session.this);
|
| - }
|
| -
|
| - // Prefers optical stabilization over software stabilization if available. Only enables one of
|
| - // the stabilization modes at a time because having both enabled can cause strange results.
|
| - private void chooseStabilizationMode(CaptureRequest.Builder captureRequestBuilder) {
|
| - final int[] availableOpticalStabilization = cameraCharacteristics.get(
|
| - CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION);
|
| - if (availableOpticalStabilization != null) {
|
| - for (int mode : availableOpticalStabilization) {
|
| - if (mode == CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON) {
|
| - captureRequestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE,
|
| - CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_ON);
|
| - captureRequestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE,
|
| - CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_OFF);
|
| - Logging.d(TAG, "Using optical stabilization.");
|
| - return;
|
| - }
|
| - }
|
| - }
|
| - // If no optical mode is available, try software.
|
| - final int[] availableVideoStabilization = cameraCharacteristics.get(
|
| - CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES);
|
| - for (int mode : availableVideoStabilization) {
|
| - if (mode == CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON) {
|
| - captureRequestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE,
|
| - CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON);
|
| - captureRequestBuilder.set(CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE,
|
| - CaptureRequest.LENS_OPTICAL_STABILIZATION_MODE_OFF);
|
| - Logging.d(TAG, "Using video stabilization.");
|
| - return;
|
| - }
|
| - }
|
| - Logging.d(TAG, "Stabilization not available.");
|
| - }
|
| -
|
| - private void chooseFocusMode(CaptureRequest.Builder captureRequestBuilder) {
|
| - final int[] availableFocusModes =
|
| - cameraCharacteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
|
| - for (int mode : availableFocusModes) {
|
| - if (mode == CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO) {
|
| - captureRequestBuilder.set(
|
| - CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO);
|
| - Logging.d(TAG, "Using continuous video auto-focus.");
|
| - return;
|
| - }
|
| - }
|
| - Logging.d(TAG, "Auto-focus is not available.");
|
| - }
|
| - }
|
| -
|
| - private class CameraCaptureCallback extends CameraCaptureSession.CaptureCallback {
|
| - @Override
|
| - public void onCaptureFailed(
|
| - CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
|
| - Logging.d(TAG, "Capture failed: " + failure);
|
| - }
|
| - }
|
| -
|
| - public static void create(CreateSessionCallback callback, Events events,
|
| - Context applicationContext, CameraManager cameraManager,
|
| - SurfaceTextureHelper surfaceTextureHelper, String cameraId, int width, int height,
|
| - int framerate) {
|
| - new Camera2Session(callback, events, applicationContext, cameraManager, surfaceTextureHelper,
|
| - cameraId, width, height, framerate);
|
| - }
|
| -
|
| - private Camera2Session(CreateSessionCallback callback, Events events, Context applicationContext,
|
| - CameraManager cameraManager, SurfaceTextureHelper surfaceTextureHelper, String cameraId,
|
| - int width, int height, int framerate) {
|
| - Logging.d(TAG, "Create new camera2 session on camera " + cameraId);
|
| -
|
| - constructionTimeNs = System.nanoTime();
|
| -
|
| - this.cameraThreadHandler = new Handler();
|
| - this.callback = callback;
|
| - this.events = events;
|
| - this.applicationContext = applicationContext;
|
| - this.cameraManager = cameraManager;
|
| - this.surfaceTextureHelper = surfaceTextureHelper;
|
| - this.cameraId = cameraId;
|
| - this.width = width;
|
| - this.height = height;
|
| - this.framerate = framerate;
|
| -
|
| - start();
|
| - }
|
| -
|
| - private void start() {
|
| - checkIsOnCameraThread();
|
| - Logging.d(TAG, "start");
|
| -
|
| - try {
|
| - cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
|
| - } catch (final CameraAccessException e) {
|
| - reportError("getCameraCharacteristics(): " + e.getMessage());
|
| - }
|
| - cameraOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
|
| - isCameraFrontFacing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING)
|
| - == CameraMetadata.LENS_FACING_FRONT;
|
| -
|
| - findCaptureFormat();
|
| - openCamera();
|
| - }
|
| -
|
| - private void findCaptureFormat() {
|
| - checkIsOnCameraThread();
|
| -
|
| - Range<Integer>[] fpsRanges =
|
| - cameraCharacteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
|
| - fpsUnitFactor = Camera2Enumerator.getFpsUnitFactor(fpsRanges);
|
| - List<CaptureFormat.FramerateRange> framerateRanges =
|
| - Camera2Enumerator.convertFramerates(fpsRanges, fpsUnitFactor);
|
| - List<Size> sizes = Camera2Enumerator.getSupportedSizes(cameraCharacteristics);
|
| - Logging.d(TAG, "Available preview sizes: " + sizes);
|
| - Logging.d(TAG, "Available fps ranges: " + framerateRanges);
|
| -
|
| - if (framerateRanges.isEmpty() || sizes.isEmpty()) {
|
| - reportError("No supported capture formats.");
|
| - }
|
| -
|
| - final CaptureFormat.FramerateRange bestFpsRange =
|
| - CameraEnumerationAndroid.getClosestSupportedFramerateRange(framerateRanges, framerate);
|
| -
|
| - final Size bestSize = CameraEnumerationAndroid.getClosestSupportedSize(sizes, width, height);
|
| - CameraEnumerationAndroid.reportCameraResolution(camera2ResolutionHistogram, bestSize);
|
| -
|
| - captureFormat = new CaptureFormat(bestSize.width, bestSize.height, bestFpsRange);
|
| - Logging.d(TAG, "Using capture format: " + captureFormat);
|
| - }
|
| -
|
| - private void openCamera() {
|
| - checkIsOnCameraThread();
|
| -
|
| - Logging.d(TAG, "Opening camera " + cameraId);
|
| - events.onCameraOpening();
|
| -
|
| - try {
|
| - cameraManager.openCamera(cameraId, new CameraStateCallback(), cameraThreadHandler);
|
| - } catch (CameraAccessException e) {
|
| - reportError("Failed to open camera: " + e);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void stop() {
|
| - Logging.d(TAG, "Stop camera2 session on camera " + cameraId);
|
| - checkIsOnCameraThread();
|
| - if (state != SessionState.STOPPED) {
|
| - final long stopStartTime = System.nanoTime();
|
| - state = SessionState.STOPPED;
|
| - stopInternal();
|
| - final int stopTimeMs = (int) TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - stopStartTime);
|
| - camera2StopTimeMsHistogram.addSample(stopTimeMs);
|
| - }
|
| - }
|
| -
|
| - private void stopInternal() {
|
| - Logging.d(TAG, "Stop internal");
|
| - checkIsOnCameraThread();
|
| -
|
| - surfaceTextureHelper.stopListening();
|
| -
|
| - if (captureSession != null) {
|
| - captureSession.close();
|
| - captureSession = null;
|
| - }
|
| - if (surface != null) {
|
| - surface.release();
|
| - surface = null;
|
| - }
|
| - if (cameraDevice != null) {
|
| - cameraDevice.close();
|
| - cameraDevice = null;
|
| - }
|
| -
|
| - Logging.d(TAG, "Stop done");
|
| - }
|
| -
|
| - private void reportError(String error) {
|
| - checkIsOnCameraThread();
|
| - Logging.e(TAG, "Error: " + error);
|
| -
|
| - final boolean startFailure = (captureSession == null);
|
| - state = SessionState.STOPPED;
|
| - stopInternal();
|
| - if (startFailure) {
|
| - callback.onFailure(error);
|
| - } else {
|
| - events.onCameraError(this, error);
|
| - }
|
| - }
|
| -
|
| - private int getDeviceOrientation() {
|
| - int orientation = 0;
|
| -
|
| - WindowManager wm = (WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE);
|
| - switch (wm.getDefaultDisplay().getRotation()) {
|
| - case Surface.ROTATION_90:
|
| - orientation = 90;
|
| - break;
|
| - case Surface.ROTATION_180:
|
| - orientation = 180;
|
| - break;
|
| - case Surface.ROTATION_270:
|
| - orientation = 270;
|
| - break;
|
| - case Surface.ROTATION_0:
|
| - default:
|
| - orientation = 0;
|
| - break;
|
| - }
|
| - return orientation;
|
| - }
|
| -
|
| - private int getFrameOrientation() {
|
| - int rotation = getDeviceOrientation();
|
| - if (!isCameraFrontFacing) {
|
| - rotation = 360 - rotation;
|
| - }
|
| - return (cameraOrientation + rotation) % 360;
|
| - }
|
| -
|
| - private void checkIsOnCameraThread() {
|
| - if (Thread.currentThread() != cameraThreadHandler.getLooper().getThread()) {
|
| - throw new IllegalStateException("Wrong thread");
|
| - }
|
| - }
|
| -}
|
|
|