Fix NPE when accessing Android camera focus modes
Looks like getSupportedFocusModes() may return null, despite the documentation stating otherwise. Bug: webrtc:13032 Change-Id: I0119b8a97be9ef4340c3e93f16e2dcaa899f2f3c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/227288 Reviewed-by: Xavier Lepaul <xalep@webrtc.org> Commit-Queue: Xavier Lepaul <xalep@webrtc.org> Cr-Commit-Position: refs/heads/main@{#34873}
This commit is contained in:
committed by
WebRTC LUCI CQ
parent
1460e15a45
commit
424b420a22
@ -11,6 +11,7 @@
|
||||
package org.webrtc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.Camera;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemClock;
|
||||
import java.io.IOException;
|
||||
@ -39,8 +40,8 @@ class Camera1Session implements CameraSession {
|
||||
private final Context applicationContext;
|
||||
private final SurfaceTextureHelper surfaceTextureHelper;
|
||||
private final int cameraId;
|
||||
private final android.hardware.Camera camera;
|
||||
private final android.hardware.Camera.CameraInfo info;
|
||||
private final Camera camera;
|
||||
private final Camera.CameraInfo info;
|
||||
private final CaptureFormat captureFormat;
|
||||
// Used only for stats. Only used on the camera thread.
|
||||
private final long constructionTimeNs; // Construction time of this class.
|
||||
@ -66,17 +67,17 @@ class Camera1Session implements CameraSession {
|
||||
return;
|
||||
}
|
||||
|
||||
final android.hardware.Camera camera;
|
||||
final Camera camera;
|
||||
try {
|
||||
camera = android.hardware.Camera.open(cameraId);
|
||||
camera = Camera.open(cameraId);
|
||||
} catch (RuntimeException e) {
|
||||
callback.onFailure(FailureType.ERROR, e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if (camera == null) {
|
||||
callback.onFailure(FailureType.ERROR,
|
||||
"android.hardware.Camera.open returned null for camera id = " + cameraId);
|
||||
callback.onFailure(
|
||||
FailureType.ERROR, "Camera.open returned null for camera id = " + cameraId);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -88,12 +89,12 @@ class Camera1Session implements CameraSession {
|
||||
return;
|
||||
}
|
||||
|
||||
final android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
|
||||
android.hardware.Camera.getCameraInfo(cameraId, info);
|
||||
final Camera.CameraInfo info = new Camera.CameraInfo();
|
||||
Camera.getCameraInfo(cameraId, info);
|
||||
|
||||
final CaptureFormat captureFormat;
|
||||
try {
|
||||
final android.hardware.Camera.Parameters parameters = camera.getParameters();
|
||||
final Camera.Parameters parameters = camera.getParameters();
|
||||
captureFormat = findClosestCaptureFormat(parameters, width, height, framerate);
|
||||
final Size pictureSize = findClosestPictureSize(parameters, width, height);
|
||||
updateCameraParameters(camera, parameters, captureFormat, pictureSize, captureToTexture);
|
||||
@ -111,7 +112,7 @@ class Camera1Session implements CameraSession {
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate orientation manually and send it as CVO insted.
|
||||
// Calculate orientation manually and send it as CVO instead.
|
||||
try {
|
||||
camera.setDisplayOrientation(0 /* degrees */);
|
||||
} catch (RuntimeException e) {
|
||||
@ -124,9 +125,8 @@ class Camera1Session implements CameraSession {
|
||||
surfaceTextureHelper, cameraId, camera, info, captureFormat, constructionTimeNs));
|
||||
}
|
||||
|
||||
private static void updateCameraParameters(android.hardware.Camera camera,
|
||||
android.hardware.Camera.Parameters parameters, CaptureFormat captureFormat, Size pictureSize,
|
||||
boolean captureToTexture) {
|
||||
private static void updateCameraParameters(Camera camera, Camera.Parameters parameters,
|
||||
CaptureFormat captureFormat, Size pictureSize, boolean captureToTexture) {
|
||||
final List<String> focusModes = parameters.getSupportedFocusModes();
|
||||
|
||||
parameters.setPreviewFpsRange(captureFormat.framerate.min, captureFormat.framerate.max);
|
||||
@ -139,14 +139,14 @@ class Camera1Session implements CameraSession {
|
||||
if (parameters.isVideoStabilizationSupported()) {
|
||||
parameters.setVideoStabilization(true);
|
||||
}
|
||||
if (focusModes.contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
|
||||
parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
|
||||
if (focusModes != null && focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
|
||||
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
|
||||
}
|
||||
camera.setParameters(parameters);
|
||||
}
|
||||
|
||||
private static CaptureFormat findClosestCaptureFormat(
|
||||
android.hardware.Camera.Parameters parameters, int width, int height, int framerate) {
|
||||
Camera.Parameters parameters, int width, int height, int framerate) {
|
||||
// Find closest supported format for `width` x `height` @ `framerate`.
|
||||
final List<CaptureFormat.FramerateRange> supportedFramerates =
|
||||
Camera1Enumerator.convertFramerates(parameters.getSupportedPreviewFpsRange());
|
||||
@ -162,16 +162,14 @@ class Camera1Session implements CameraSession {
|
||||
return new CaptureFormat(previewSize.width, previewSize.height, fpsRange);
|
||||
}
|
||||
|
||||
private static Size findClosestPictureSize(
|
||||
android.hardware.Camera.Parameters parameters, int width, int height) {
|
||||
private static Size findClosestPictureSize(Camera.Parameters parameters, int width, int height) {
|
||||
return CameraEnumerationAndroid.getClosestSupportedSize(
|
||||
Camera1Enumerator.convertSizes(parameters.getSupportedPictureSizes()), width, height);
|
||||
}
|
||||
|
||||
private Camera1Session(Events events, boolean captureToTexture, Context applicationContext,
|
||||
SurfaceTextureHelper surfaceTextureHelper, int cameraId, android.hardware.Camera camera,
|
||||
android.hardware.Camera.CameraInfo info, CaptureFormat captureFormat,
|
||||
long constructionTimeNs) {
|
||||
SurfaceTextureHelper surfaceTextureHelper, int cameraId, Camera camera,
|
||||
Camera.CameraInfo info, CaptureFormat captureFormat, long constructionTimeNs) {
|
||||
Logging.d(TAG, "Create new camera1 session on camera " + cameraId);
|
||||
|
||||
this.cameraThreadHandler = new Handler();
|
||||
@ -208,18 +206,18 @@ class Camera1Session implements CameraSession {
|
||||
|
||||
state = SessionState.RUNNING;
|
||||
|
||||
camera.setErrorCallback(new android.hardware.Camera.ErrorCallback() {
|
||||
camera.setErrorCallback(new Camera.ErrorCallback() {
|
||||
@Override
|
||||
public void onError(int error, android.hardware.Camera camera) {
|
||||
public void onError(int error, Camera camera) {
|
||||
String errorMessage;
|
||||
if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) {
|
||||
if (error == Camera.CAMERA_ERROR_SERVER_DIED) {
|
||||
errorMessage = "Camera server died!";
|
||||
} else {
|
||||
errorMessage = "Camera error: " + error;
|
||||
}
|
||||
Logging.e(TAG, errorMessage);
|
||||
stopInternal();
|
||||
if (error == android.hardware.Camera.CAMERA_ERROR_EVICTED) {
|
||||
if (error == Camera.CAMERA_ERROR_EVICTED) {
|
||||
events.onCameraDisconnected(Camera1Session.this);
|
||||
} else {
|
||||
events.onCameraError(Camera1Session.this, errorMessage);
|
||||
@ -251,7 +249,7 @@ class Camera1Session implements CameraSession {
|
||||
state = SessionState.STOPPED;
|
||||
surfaceTextureHelper.stopListening();
|
||||
// Note: stopPreview or other driver code might deadlock. Deadlock in
|
||||
// android.hardware.Camera._stopPreview(Native Method) has been observed on
|
||||
// Camera._stopPreview(Native Method) has been observed on
|
||||
// Nexus 5 (hammerhead), OS version LMY48I.
|
||||
camera.stopPreview();
|
||||
camera.release();
|
||||
@ -277,21 +275,21 @@ class Camera1Session implements CameraSession {
|
||||
|
||||
// Undo the mirror that the OS "helps" us with.
|
||||
// http://developer.android.com/reference/android/hardware/Camera.html#setDisplayOrientation(int)
|
||||
final VideoFrame modifiedFrame = new VideoFrame(
|
||||
CameraSession.createTextureBufferWithModifiedTransformMatrix(
|
||||
(TextureBufferImpl) frame.getBuffer(),
|
||||
/* mirror= */ info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT,
|
||||
/* rotation= */ 0),
|
||||
/* rotation= */ getFrameOrientation(), frame.getTimestampNs());
|
||||
final VideoFrame modifiedFrame =
|
||||
new VideoFrame(CameraSession.createTextureBufferWithModifiedTransformMatrix(
|
||||
(TextureBufferImpl) frame.getBuffer(),
|
||||
/* mirror= */ info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT,
|
||||
/* rotation= */ 0),
|
||||
/* rotation= */ getFrameOrientation(), frame.getTimestampNs());
|
||||
events.onFrameCaptured(Camera1Session.this, modifiedFrame);
|
||||
modifiedFrame.release();
|
||||
});
|
||||
}
|
||||
|
||||
private void listenForBytebufferFrames() {
|
||||
camera.setPreviewCallbackWithBuffer(new android.hardware.Camera.PreviewCallback() {
|
||||
camera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
|
||||
@Override
|
||||
public void onPreviewFrame(final byte[] data, android.hardware.Camera callbackCamera) {
|
||||
public void onPreviewFrame(final byte[] data, Camera callbackCamera) {
|
||||
checkIsOnCameraThread();
|
||||
|
||||
if (callbackCamera != camera) {
|
||||
@ -328,7 +326,7 @@ class Camera1Session implements CameraSession {
|
||||
|
||||
private int getFrameOrientation() {
|
||||
int rotation = CameraSession.getDeviceOrientation(applicationContext);
|
||||
if (info.facing == android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK) {
|
||||
if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
|
||||
rotation = 360 - rotation;
|
||||
}
|
||||
return (info.orientation + rotation) % 360;
|
||||
|
||||
Reference in New Issue
Block a user