Skip to content

Commit

Permalink
[camera] Revert Android part of flutter#3272 (flutter#3405)
Browse files Browse the repository at this point in the history
Reverts the Android part of flutter#3272 (commit d311478), which introduced significant crash flake in the tests.
  • Loading branch information
stuartmorgan committed Mar 7, 2023
1 parent 5eefd07 commit 036cb1e
Show file tree
Hide file tree
Showing 12 changed files with 47 additions and 780 deletions.
4 changes: 0 additions & 4 deletions packages/camera/camera_android/CHANGELOG.md
@@ -1,7 +1,3 @@
## 0.10.5

* Allows camera to be switched while video recording.

## 0.10.4+2

* Aligns Dart and Flutter SDK constraints.
Expand Down
Expand Up @@ -96,28 +96,13 @@ class Camera
* Holds all of the camera features/settings and will be used to update the request builder when
* one changes.
*/
private CameraFeatures cameraFeatures;

private String imageFormatGroup;

/**
* Takes an input/output surface and orients the recording correctly. This is needed because
* switching cameras while recording causes the wrong orientation.
*/
private VideoRenderer videoRenderer;

/**
* Whether or not the camera aligns with the initial way the camera was facing if the camera was
* flipped.
*/
private int initialCameraFacing;
private final CameraFeatures cameraFeatures;

private final SurfaceTextureEntry flutterTexture;
private final ResolutionPreset resolutionPreset;
private final boolean enableAudio;
private final Context applicationContext;
private final DartMessenger dartMessenger;
private CameraProperties cameraProperties;
private final CameraProperties cameraProperties;
private final CameraFeatureFactory cameraFeatureFactory;
private final Activity activity;
/** A {@link CameraCaptureSession.CaptureCallback} that handles events related to JPEG capture. */
Expand Down Expand Up @@ -207,7 +192,6 @@ public Camera(
this.applicationContext = activity.getApplicationContext();
this.cameraProperties = cameraProperties;
this.cameraFeatureFactory = cameraFeatureFactory;
this.resolutionPreset = resolutionPreset;
this.cameraFeatures =
CameraFeatures.init(
cameraFeatureFactory, cameraProperties, activity, dartMessenger, resolutionPreset);
Expand Down Expand Up @@ -248,7 +232,6 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException {
if (mediaRecorder != null) {
mediaRecorder.release();
}
closeRenderer();

final PlatformChannel.DeviceOrientation lockedOrientation =
cameraFeatures.getSensorOrientation().getLockedCaptureOrientation();
Expand Down Expand Up @@ -276,7 +259,6 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException {

@SuppressLint("MissingPermission")
public void open(String imageFormatGroup) throws CameraAccessException {
this.imageFormatGroup = imageFormatGroup;
final ResolutionFeature resolutionFeature = cameraFeatures.getResolution();

if (!resolutionFeature.checkIsSupported()) {
Expand Down Expand Up @@ -321,16 +303,14 @@ public void onOpened(@NonNull CameraDevice device) {
cameraDevice = new DefaultCameraDeviceWrapper(device);
try {
startPreview();
if (!recordingVideo) // only send initialization if we werent already recording and switching cameras
dartMessenger.sendCameraInitializedEvent(
resolutionFeature.getPreviewSize().getWidth(),
resolutionFeature.getPreviewSize().getHeight(),
cameraFeatures.getExposureLock().getValue(),
cameraFeatures.getAutoFocus().getValue(),
cameraFeatures.getExposurePoint().checkIsSupported(),
cameraFeatures.getFocusPoint().checkIsSupported());

} catch (CameraAccessException | InterruptedException e) {
resolutionFeature.getPreviewSize().getWidth(),
resolutionFeature.getPreviewSize().getHeight(),
cameraFeatures.getExposureLock().getValue(),
cameraFeatures.getAutoFocus().getValue(),
cameraFeatures.getExposurePoint().checkIsSupported(),
cameraFeatures.getFocusPoint().checkIsSupported());
} catch (CameraAccessException e) {
dartMessenger.sendCameraErrorEvent(e.getMessage());
close();
}
Expand All @@ -340,8 +320,7 @@ public void onOpened(@NonNull CameraDevice device) {
public void onClosed(@NonNull CameraDevice camera) {
Log.i(TAG, "open | onClosed");

// Prevents calls to methods that would otherwise result in IllegalStateException
// exceptions.
// Prevents calls to methods that would otherwise result in IllegalStateException exceptions.
cameraDevice = null;
closeCaptureSession();
dartMessenger.sendCameraClosingEvent();
Expand Down Expand Up @@ -756,7 +735,7 @@ public void startVideoRecording(
if (imageStreamChannel != null) {
setStreamHandler(imageStreamChannel);
}
initialCameraFacing = cameraProperties.getLensFacing();

recordingVideo = true;
try {
startCapture(true, imageStreamChannel != null);
Expand All @@ -768,13 +747,6 @@ public void startVideoRecording(
}
}

private void closeRenderer() {
if (videoRenderer != null) {
videoRenderer.close();
videoRenderer = null;
}
}

public void stopVideoRecording(@NonNull final Result result) {
if (!recordingVideo) {
result.success(null);
Expand All @@ -785,7 +757,6 @@ public void stopVideoRecording(@NonNull final Result result) {
cameraFeatureFactory.createAutoFocusFeature(cameraProperties, false));
recordingVideo = false;
try {
closeRenderer();
captureSession.abortCaptures();
mediaRecorder.stop();
} catch (CameraAccessException | IllegalStateException e) {
Expand All @@ -794,7 +765,7 @@ public void stopVideoRecording(@NonNull final Result result) {
mediaRecorder.reset();
try {
startPreview();
} catch (CameraAccessException | IllegalStateException | InterruptedException e) {
} catch (CameraAccessException | IllegalStateException e) {
result.error("videoRecordingFailed", e.getMessage(), null);
return;
}
Expand Down Expand Up @@ -1078,48 +1049,11 @@ public void resumePreview() {
null, (code, message) -> dartMessenger.sendCameraErrorEvent(message));
}

public void startPreview() throws CameraAccessException, InterruptedException {
// If recording is already in progress, the camera is being flipped, so send it through the VideoRenderer to keep the correct orientation.
if (recordingVideo) {
startPreviewWithVideoRendererStream();
} else {
startRegularPreview();
}
}

private void startRegularPreview() throws CameraAccessException {
public void startPreview() throws CameraAccessException {
if (pictureImageReader == null || pictureImageReader.getSurface() == null) return;
Log.i(TAG, "startPreview");
createCaptureSession(CameraDevice.TEMPLATE_PREVIEW, pictureImageReader.getSurface());
}

private void startPreviewWithVideoRendererStream()
throws CameraAccessException, InterruptedException {
if (videoRenderer == null) return;

// get rotation for rendered video
final PlatformChannel.DeviceOrientation lockedOrientation =
cameraFeatures.getSensorOrientation().getLockedCaptureOrientation();
DeviceOrientationManager orientationManager =
cameraFeatures.getSensorOrientation().getDeviceOrientationManager();

int rotation = 0;
if (orientationManager != null) {
rotation =
lockedOrientation == null
? orientationManager.getVideoOrientation()
: orientationManager.getVideoOrientation(lockedOrientation);
}

if (cameraProperties.getLensFacing() != initialCameraFacing) {

// If the new camera is facing the opposite way than the initial recording,
// the rotation should be flipped 180 degrees.
rotation = (rotation + 180) % 360;
}
videoRenderer.setRotation(rotation);

createCaptureSession(CameraDevice.TEMPLATE_RECORD, videoRenderer.getInputSurface());
createCaptureSession(CameraDevice.TEMPLATE_PREVIEW, pictureImageReader.getSurface());
}

public void startPreviewWithImageStream(EventChannel imageStreamChannel)
Expand Down Expand Up @@ -1245,7 +1179,17 @@ private void closeCaptureSession() {
public void close() {
Log.i(TAG, "close");

stopAndReleaseCamera();
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;

// Closing the CameraDevice without closing the CameraCaptureSession is recommended
// for quickly closing the camera:
// https://developer.android.com/reference/android/hardware/camera2/CameraCaptureSession#close()
captureSession = null;
} else {
closeCaptureSession();
}

if (pictureImageReader != null) {
pictureImageReader.close();
Expand All @@ -1264,75 +1208,6 @@ public void close() {
stopBackgroundThread();
}

private void stopAndReleaseCamera() {
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;

// Closing the CameraDevice without closing the CameraCaptureSession is recommended
// for quickly closing the camera:
// https://developer.android.com/reference/android/hardware/camera2/CameraCaptureSession#close()
captureSession = null;
} else {
closeCaptureSession();
}
}

private void prepareVideoRenderer() {
if (videoRenderer != null) return;
final ResolutionFeature resolutionFeature = cameraFeatures.getResolution();

// handle videoRenderer errors
Thread.UncaughtExceptionHandler videoRendererUncaughtExceptionHandler =
new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
dartMessenger.sendCameraErrorEvent(
"Failed to process frames after camera was flipped.");
}
};

videoRenderer =
new VideoRenderer(
mediaRecorder.getSurface(),
resolutionFeature.getCaptureSize().getWidth(),
resolutionFeature.getCaptureSize().getHeight(),
videoRendererUncaughtExceptionHandler);
}

public void setDescriptionWhileRecording(
@NonNull final Result result, CameraProperties properties) {

if (!recordingVideo) {
result.error("setDescriptionWhileRecordingFailed", "Device was not recording", null);
return;
}

// See VideoRenderer.java requires API 26 to switch camera while recording
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O) {
result.error(
"setDescriptionWhileRecordingFailed",
"Device does not support switching the camera while recording",
null);
return;
}

stopAndReleaseCamera();
prepareVideoRenderer();
cameraProperties = properties;
cameraFeatures =
CameraFeatures.init(
cameraFeatureFactory, cameraProperties, activity, dartMessenger, resolutionPreset);
cameraFeatures.setAutoFocus(
cameraFeatureFactory.createAutoFocusFeature(cameraProperties, true));
try {
open(imageFormatGroup);
} catch (CameraAccessException e) {
result.error("setDescriptionWhileRecordingFailed", e.getMessage(), null);
}
result.success(null);
}

public void dispose() {
Log.i(TAG, "dispose");

Expand Down
Expand Up @@ -354,18 +354,6 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result)
result.success(null);
break;
}
case "setDescriptionWhileRecording":
{
try {
String cameraName = call.argument("cameraName");
CameraProperties cameraProperties =
new CameraPropertiesImpl(cameraName, CameraUtils.getCameraManager(activity));
camera.setDescriptionWhileRecording(result, cameraProperties);
} catch (Exception e) {
handleException(e, result);
}
break;
}
case "dispose":
{
if (camera != null) {
Expand Down

0 comments on commit 036cb1e

Please sign in to comment.