Skip to content

Commit c976917

Browse files
[camera_android] Don't override default fps range when not recording (#8891)
In production I have an app using the `camera_android` plugin that just uses the frame streaming feature. I've been pinning version `0.10.8+18` for a while because we found an issue after updating to `0.10.9`. Some users reported a dark camera preview. After some investigation, I believe the issue is because of the call to `this.cameraFeatures.setFpsRange` in the `Camera` constructor. That is the only difference in behavior that .9 and .8+18 have. Fixes flutter/flutter#165491 From the linked issue I went with the second possible fix. Would that be a good approach? Or should the fps setting also apply to the camera streaming and preview? cc @camsim99 ## Pre-Review Checklist [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent 01f9771 commit c976917

File tree

4 files changed

+43
-30
lines changed

4 files changed

+43
-30
lines changed

packages/camera/camera_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.10.10+2
2+
3+
* 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.
4+
15
## 0.10.10+1
26

37
* Updates compileSdk 34 to flutter.compileSdkVersion.

packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -225,30 +225,6 @@ public Camera(
225225
dartMessenger,
226226
videoCaptureSettings.resolutionPreset);
227227

228-
Integer recordingFps = null;
229-
230-
if (videoCaptureSettings.fps != null && videoCaptureSettings.fps.intValue() > 0) {
231-
recordingFps = videoCaptureSettings.fps;
232-
} else {
233-
234-
if (SdkCapabilityChecker.supportsEncoderProfiles()) {
235-
EncoderProfiles encoderProfiles = getRecordingProfile();
236-
if (encoderProfiles != null && encoderProfiles.getVideoProfiles().size() > 0) {
237-
recordingFps = encoderProfiles.getVideoProfiles().get(0).getFrameRate();
238-
}
239-
} else {
240-
CamcorderProfile camcorderProfile = getRecordingProfileLegacy();
241-
recordingFps = null != camcorderProfile ? camcorderProfile.videoFrameRate : null;
242-
}
243-
}
244-
245-
if (recordingFps != null && recordingFps.intValue() > 0) {
246-
247-
final FpsRangeFeature fpsRange = new FpsRangeFeature(cameraProperties);
248-
fpsRange.setValue(new Range<Integer>(recordingFps, recordingFps));
249-
this.cameraFeatures.setFpsRange(fpsRange);
250-
}
251-
252228
// Create capture callback.
253229
captureTimeouts = new CaptureTimeoutsWrapper(3000, 3000);
254230
captureProps = new CameraCaptureProperties();
@@ -326,6 +302,36 @@ private void prepareMediaRecorder(String outputFilePath) throws IOException {
326302
.build();
327303
}
328304

305+
/**
306+
* Updates the FpsRange camera features with the appropriate FPS range. It sets the minimum and
307+
* maximum fps range to the same value, as that's what is recommended for video recording.
308+
*/
309+
private void setFpsCameraFeatureForRecording(CameraProperties cameraProperties) {
310+
Integer recordingFps = null;
311+
312+
if (videoCaptureSettings.fps != null && videoCaptureSettings.fps.intValue() > 0) {
313+
recordingFps = videoCaptureSettings.fps;
314+
} else {
315+
316+
if (SdkCapabilityChecker.supportsEncoderProfiles()) {
317+
EncoderProfiles encoderProfiles = getRecordingProfile();
318+
if (encoderProfiles != null && encoderProfiles.getVideoProfiles().size() > 0) {
319+
recordingFps = encoderProfiles.getVideoProfiles().get(0).getFrameRate();
320+
}
321+
} else {
322+
CamcorderProfile camcorderProfile = getRecordingProfileLegacy();
323+
recordingFps = null != camcorderProfile ? camcorderProfile.videoFrameRate : null;
324+
}
325+
}
326+
327+
if (recordingFps != null && recordingFps.intValue() > 0) {
328+
329+
final FpsRangeFeature fpsRange = new FpsRangeFeature(cameraProperties);
330+
fpsRange.setValue(new Range<Integer>(recordingFps, recordingFps));
331+
this.cameraFeatures.setFpsRange(fpsRange);
332+
}
333+
}
334+
329335
@SuppressLint("MissingPermission")
330336
public void open(Integer imageFormatGroup) throws CameraAccessException {
331337
this.imageFormatGroup = imageFormatGroup;
@@ -851,6 +857,9 @@ public String stopVideoRecording() {
851857
// Re-create autofocus feature so it's using continuous capture focus mode now.
852858
cameraFeatures.setAutoFocus(
853859
cameraFeatureFactory.createAutoFocusFeature(cameraProperties, false));
860+
// Reset to non recording fps range (the default)
861+
cameraFeatures.setFpsRange(cameraFeatureFactory.createFpsRangeFeature(cameraProperties));
862+
854863
recordingVideo = false;
855864
try {
856865
closeRenderer();
@@ -1252,6 +1261,8 @@ void prepareRecording() {
12521261
// Re-create autofocus feature so it's using video focus mode now.
12531262
cameraFeatures.setAutoFocus(
12541263
cameraFeatureFactory.createAutoFocusFeature(cameraProperties, true));
1264+
// Update camera features with the desired fps range
1265+
setFpsCameraFeatureForRecording(cameraProperties);
12551266
}
12561267

12571268
private void setStreamHandler(EventChannel imageStreamChannel) {
@@ -1375,6 +1386,7 @@ public void setDescriptionWhileRecording(CameraProperties properties) {
13751386
videoCaptureSettings.resolutionPreset);
13761387
cameraFeatures.setAutoFocus(
13771388
cameraFeatureFactory.createAutoFocusFeature(cameraProperties, true));
1389+
setFpsCameraFeatureForRecording(cameraProperties);
13781390
try {
13791391
open(imageFormatGroup);
13801392
} catch (CameraAccessException e) {

packages/camera/camera_android/android/src/test/java/io/flutter/plugins/camera/CameraTest_getRecordingProfileTest.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,7 @@ public void getRecordingProfileLegacy() {
8686

8787
CamcorderProfile actualRecordingProfile = camera.getRecordingProfileLegacy();
8888

89-
// First time: getRecordingProfileLegacy() is called in `before()` when
90-
// camera constructor tries to determine default recording Fps.
91-
// Second time: in this test case.
92-
verify(mockResolutionFeature, times(2)).getRecordingProfileLegacy();
89+
verify(mockResolutionFeature, times(1)).getRecordingProfileLegacy();
9390
assertEquals(mockCamcorderProfile, actualRecordingProfile);
9491
}
9592

@@ -104,7 +101,7 @@ public void getRecordingProfile() {
104101

105102
EncoderProfiles actualRecordingProfile = camera.getRecordingProfile();
106103

107-
verify(mockResolutionFeature, times(2)).getRecordingProfile();
104+
verify(mockResolutionFeature, times(1)).getRecordingProfile();
108105
assertEquals(mockRecordingProfile, actualRecordingProfile);
109106
}
110107

packages/camera/camera_android/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Android implementation of the camera plugin.
33
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
55

6-
version: 0.10.10+1
6+
version: 0.10.10+2
77

88
environment:
99
sdk: ^3.6.0

0 commit comments

Comments
 (0)