diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index 60b8e6cd0a40..e5e99ce82838 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.10+2 + +* Don't set the FPS range unless video recording. It can cause dark image previews on some devices becuse the auto exposure algorithm is more constrained after fixing the min/max FPS range to the same value. This change has the side effect that providing the `fps` parameter will not affect the camera preview when not video recording. And if you need a lower frame rate in your image streaming handler, you can skip frames by checking the time it passed since the last frame. + ## 0.10.10+1 * Updates compileSdk 34 to flutter.compileSdkVersion. diff --git a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java index cfddf2d3bc34..9b5aa049b445 100644 --- a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -225,30 +225,6 @@ public Camera( dartMessenger, videoCaptureSettings.resolutionPreset); - Integer recordingFps = null; - - if (videoCaptureSettings.fps != null && videoCaptureSettings.fps.intValue() > 0) { - recordingFps = videoCaptureSettings.fps; - } else { - - if (SdkCapabilityChecker.supportsEncoderProfiles()) { - EncoderProfiles encoderProfiles = getRecordingProfile(); - if (encoderProfiles != null && encoderProfiles.getVideoProfiles().size() > 0) { - recordingFps = encoderProfiles.getVideoProfiles().get(0).getFrameRate(); - } - } else { - CamcorderProfile camcorderProfile = getRecordingProfileLegacy(); - recordingFps = null != camcorderProfile ? camcorderProfile.videoFrameRate : null; - } - } - - if (recordingFps != null && recordingFps.intValue() > 0) { - - final FpsRangeFeature fpsRange = new FpsRangeFeature(cameraProperties); - fpsRange.setValue(new Range(recordingFps, recordingFps)); - this.cameraFeatures.setFpsRange(fpsRange); - } - // Create capture callback. captureTimeouts = new CaptureTimeoutsWrapper(3000, 3000); captureProps = new CameraCaptureProperties(); @@ -326,6 +302,36 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException { .build(); } + /** + * Updates the FpsRange camera features with the appropriate FPS range. It sets the minimum and + * maximum fps range to the same value, as that's what is recommended for video recording. + */ + private void setFpsCameraFeatureForRecording(CameraProperties cameraProperties) { + Integer recordingFps = null; + + if (videoCaptureSettings.fps != null && videoCaptureSettings.fps.intValue() > 0) { + recordingFps = videoCaptureSettings.fps; + } else { + + if (SdkCapabilityChecker.supportsEncoderProfiles()) { + EncoderProfiles encoderProfiles = getRecordingProfile(); + if (encoderProfiles != null && encoderProfiles.getVideoProfiles().size() > 0) { + recordingFps = encoderProfiles.getVideoProfiles().get(0).getFrameRate(); + } + } else { + CamcorderProfile camcorderProfile = getRecordingProfileLegacy(); + recordingFps = null != camcorderProfile ? camcorderProfile.videoFrameRate : null; + } + } + + if (recordingFps != null && recordingFps.intValue() > 0) { + + final FpsRangeFeature fpsRange = new FpsRangeFeature(cameraProperties); + fpsRange.setValue(new Range(recordingFps, recordingFps)); + this.cameraFeatures.setFpsRange(fpsRange); + } + } + @SuppressLint("MissingPermission") public void open(Integer imageFormatGroup) throws CameraAccessException { this.imageFormatGroup = imageFormatGroup; @@ -851,6 +857,9 @@ public String stopVideoRecording() { // Re-create autofocus feature so it's using continuous capture focus mode now. cameraFeatures.setAutoFocus( cameraFeatureFactory.createAutoFocusFeature(cameraProperties, false)); + // Reset to non recording fps range (the default) + cameraFeatures.setFpsRange(cameraFeatureFactory.createFpsRangeFeature(cameraProperties)); + recordingVideo = false; try { closeRenderer(); @@ -1252,6 +1261,8 @@ void prepareRecording() { // Re-create autofocus feature so it's using video focus mode now. cameraFeatures.setAutoFocus( cameraFeatureFactory.createAutoFocusFeature(cameraProperties, true)); + // Update camera features with the desired fps range + setFpsCameraFeatureForRecording(cameraProperties); } private void setStreamHandler(EventChannel imageStreamChannel) { @@ -1375,6 +1386,7 @@ public void setDescriptionWhileRecording(CameraProperties properties) { videoCaptureSettings.resolutionPreset); cameraFeatures.setAutoFocus( cameraFeatureFactory.createAutoFocusFeature(cameraProperties, true)); + setFpsCameraFeatureForRecording(cameraProperties); try { open(imageFormatGroup); } catch (CameraAccessException e) { diff --git a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java index c5a97a19aca7..c67b0f3346cd 100644 --- a/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java +++ b/packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java @@ -86,10 +86,7 @@ public void getRecordingProfileLegacy() { CamcorderProfile actualRecordingProfile = camera.getRecordingProfileLegacy(); - // First time: getRecordingProfileLegacy() is called in `before()` when - // camera constructor tries to determine default recording Fps. - // Second time: in this test case. - verify(mockResolutionFeature, times(2)).getRecordingProfileLegacy(); + verify(mockResolutionFeature, times(1)).getRecordingProfileLegacy(); assertEquals(mockCamcorderProfile, actualRecordingProfile); } @@ -104,7 +101,7 @@ public void getRecordingProfile() { EncoderProfiles actualRecordingProfile = camera.getRecordingProfile(); - verify(mockResolutionFeature, times(2)).getRecordingProfile(); + verify(mockResolutionFeature, times(1)).getRecordingProfile(); assertEquals(mockRecordingProfile, actualRecordingProfile); } diff --git a/packages/camera/camera_android/pubspec.yaml b/packages/camera/camera_android/pubspec.yaml index 33163076f680..f813858fd620 100644 --- a/packages/camera/camera_android/pubspec.yaml +++ b/packages/camera/camera_android/pubspec.yaml @@ -3,7 +3,7 @@ description: Android implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.10.10+1 +version: 0.10.10+2 environment: sdk: ^3.6.0