Skip to content

Commit 6707def

Browse files
committed
add targetFps
1 parent 53d6138 commit 6707def

File tree

15 files changed

+1091
-529
lines changed

15 files changed

+1091
-529
lines changed

packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CameraXLibrary.g.kt

Lines changed: 924 additions & 503 deletions
Large diffs are not rendered by default.

packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/ImageAnalysisProxyApi.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@
44

55
package io.flutter.plugins.camerax;
66

7+
import android.hardware.camera2.CaptureRequest;
8+
import android.util.Range;
79
import androidx.annotation.NonNull;
810
import androidx.annotation.Nullable;
11+
import androidx.annotation.OptIn;
12+
import androidx.camera.camera2.interop.Camera2Interop;
13+
import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
914
import androidx.camera.core.ImageAnalysis;
1015
import androidx.camera.core.resolutionselector.ResolutionSelector;
1116
import androidx.core.content.ContextCompat;
@@ -18,11 +23,13 @@
1823
class ImageAnalysisProxyApi extends PigeonApiImageAnalysis {
1924
static final long CLEAR_FINALIZED_WEAK_REFERENCES_INTERVAL_FOR_IMAGE_ANALYSIS = 1000;
2025

26+
@OptIn(markerClass = ExperimentalCamera2Interop.class)
2127
@NonNull
2228
@Override
2329
public ImageAnalysis pigeon_defaultConstructor(
2430
@Nullable ResolutionSelector resolutionSelector,
2531
@Nullable Long targetRotation,
32+
@Nullable Long targetFps,
2633
@Nullable Long outputImageFormat) {
2734
final ImageAnalysis.Builder builder = new ImageAnalysis.Builder();
2835
if (resolutionSelector != null) {
@@ -36,6 +43,14 @@ public ImageAnalysis pigeon_defaultConstructor(
3643
builder.setOutputImageFormat(outputImageFormat.intValue());
3744
}
3845

46+
if (targetFps != null) {
47+
Range<Integer> targetFpsRange = new Range<>(targetFps.intValue(), targetFps.intValue());
48+
Camera2Interop.Extender<ImageAnalysis> extender = new Camera2Interop.Extender<>(builder);
49+
extender.setCaptureRequestOption(
50+
CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, targetFpsRange
51+
);
52+
}
53+
3954
return builder.build();
4055
}
4156

packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/PreviewProxyApi.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@
44

55
package io.flutter.plugins.camerax;
66

7+
import android.hardware.camera2.CaptureRequest;
8+
import android.util.Range;
79
import android.view.Surface;
810
import androidx.annotation.NonNull;
911
import androidx.annotation.Nullable;
12+
import androidx.annotation.OptIn;
13+
import androidx.camera.camera2.interop.Camera2Interop;
14+
import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
1015
import androidx.camera.core.Preview;
1116
import androidx.camera.core.ResolutionInfo;
1217
import androidx.camera.core.SurfaceRequest;
@@ -35,17 +40,29 @@ public ProxyApiRegistrar getPigeonRegistrar() {
3540
return (ProxyApiRegistrar) super.getPigeonRegistrar();
3641
}
3742

43+
@OptIn(markerClass = ExperimentalCamera2Interop.class)
3844
@NonNull
3945
@Override
4046
public Preview pigeon_defaultConstructor(
41-
@Nullable ResolutionSelector resolutionSelector, @Nullable Long targetRotation) {
47+
@Nullable ResolutionSelector resolutionSelector,
48+
@Nullable Long targetRotation,
49+
@Nullable Long targetFps) {
4250
final Preview.Builder builder = new Preview.Builder();
4351
if (targetRotation != null) {
4452
builder.setTargetRotation(targetRotation.intValue());
4553
}
4654
if (resolutionSelector != null) {
4755
builder.setResolutionSelector(resolutionSelector);
4856
}
57+
58+
if (targetFps != null) {
59+
Range<Integer> targetFpsRange = new Range<>(targetFps.intValue(), targetFps.intValue());
60+
Camera2Interop.Extender<Preview> extender = new Camera2Interop.Extender<>(builder);
61+
extender.setCaptureRequestOption(
62+
CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, targetFpsRange
63+
);
64+
}
65+
4966
return builder.build();
5067
}
5168

packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/VideoCaptureProxyApi.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@
44

55
package io.flutter.plugins.camerax;
66

7+
import android.hardware.camera2.CaptureRequest;
8+
import android.util.Range;
9+
710
import androidx.annotation.NonNull;
11+
import androidx.annotation.Nullable;
12+
import androidx.annotation.OptIn;
13+
import androidx.camera.camera2.interop.Camera2Interop;
14+
import androidx.camera.camera2.interop.ExperimentalCamera2Interop;
815
import androidx.camera.video.VideoCapture;
916
import androidx.camera.video.VideoOutput;
1017

@@ -18,10 +25,21 @@ class VideoCaptureProxyApi extends PigeonApiVideoCapture {
1825
super(pigeonRegistrar);
1926
}
2027

28+
@OptIn(markerClass = ExperimentalCamera2Interop.class)
2129
@NonNull
2230
@Override
23-
public VideoCapture<?> withOutput(@NonNull VideoOutput videoOutput) {
24-
return VideoCapture.withOutput(videoOutput);
31+
public VideoCapture<?> withOutput(@NonNull VideoOutput videoOutput, @Nullable Long targetFps) {
32+
VideoCapture.Builder<VideoOutput> builder = new VideoCapture.Builder<>(videoOutput);
33+
34+
if (targetFps != null) {
35+
Range<Integer> targetFpsRange = new Range<>(targetFps.intValue(), targetFps.intValue());
36+
Camera2Interop.Extender<VideoCapture<VideoOutput>> extender = new Camera2Interop.Extender<>(builder);
37+
extender.setCaptureRequestOption(
38+
CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, targetFpsRange
39+
);
40+
}
41+
42+
return builder.build();
2543
}
2644

2745
@NonNull

packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/ImageAnalysisTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ public void pigeon_defaultConstructor_createsExpectedImageAnalysisInstance() {
3232

3333
final ResolutionSelector mockResolutionSelector = new ResolutionSelector.Builder().build();
3434
final long targetResolution = Surface.ROTATION_0;
35+
final long targetFps = 30;
3536
final long outputImageFormat = ImageAnalysis.OUTPUT_IMAGE_FORMAT_NV21;
3637
final ImageAnalysis imageAnalysis =
37-
api.pigeon_defaultConstructor(mockResolutionSelector, targetResolution, outputImageFormat);
38+
api.pigeon_defaultConstructor(mockResolutionSelector, targetResolution, targetFps, outputImageFormat);
3839

3940
assertEquals(imageAnalysis.getResolutionSelector(), mockResolutionSelector);
4041
assertEquals(imageAnalysis.getTargetRotation(), Surface.ROTATION_0);

packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/PreviewTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ public void pigeon_defaultConstructor_createsPreviewWithCorrectConfiguration() {
3636

3737
final ResolutionSelector mockResolutionSelector = new ResolutionSelector.Builder().build();
3838
final long targetResolution = Surface.ROTATION_0;
39+
final long targetFps = 30;
3940
final Preview instance =
40-
api.pigeon_defaultConstructor(mockResolutionSelector, targetResolution);
41+
api.pigeon_defaultConstructor(mockResolutionSelector, targetResolution, targetFps);
4142

4243
assertEquals(instance.getResolutionSelector(), mockResolutionSelector);
4344
assertEquals(instance.getTargetRotation(), Surface.ROTATION_0);

packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/VideoCaptureTest.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@
1313
import androidx.camera.video.VideoOutput;
1414
import org.junit.Test;
1515
import org.junit.runner.RunWith;
16-
import org.mockito.MockedStatic;
17-
import org.mockito.Mockito;
18-
import org.mockito.stubbing.Answer;
1916
import org.robolectric.RobolectricTestRunner;
2017

2118
@RunWith(RobolectricTestRunner.class)
@@ -25,17 +22,11 @@ public class VideoCaptureTest {
2522
public void withOutput_createsVideoCaptureWithVideoOutput() {
2623
final PigeonApiVideoCapture api = new TestProxyApiRegistrar().getPigeonApiVideoCapture();
2724

28-
final VideoCapture<VideoOutput> instance = mock(VideoCapture.class);
2925
final VideoOutput videoOutput = mock(VideoOutput.class);
26+
final long targetFps = 30;
3027

31-
try (MockedStatic<VideoCapture> mockedCamera2CameraInfo =
32-
Mockito.mockStatic(VideoCapture.class)) {
33-
mockedCamera2CameraInfo
34-
.when(() -> VideoCapture.withOutput(videoOutput))
35-
.thenAnswer((Answer<VideoCapture>) invocation -> instance);
36-
37-
assertEquals(api.withOutput(videoOutput), instance);
38-
}
28+
final VideoCapture videoCapture = api.withOutput(videoOutput, targetFps);
29+
assertEquals(videoCapture.getOutput(), videoOutput);
3930
}
4031

4132
@SuppressWarnings("unchecked")

packages/camera/camera_android_camerax/example/lib/camera_controller.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,8 @@ class CameraController extends ValueNotifier<CameraValue> {
337337
(CameraInitializedEvent event) => event.focusPointSupported,
338338
),
339339
);
340-
} on PlatformException catch (e) {
340+
} on PlatformException catch (e, stacktrace) {
341+
print(stacktrace);
341342
throw CameraException(e.code, e.message);
342343
}
343344

packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,8 @@ class AndroidCameraCameraX extends CameraPlatform {
288288
/// The preset resolution selector for the camera.
289289
ResolutionSelector? _presetResolutionSelector;
290290

291+
int? _targetFps;
292+
291293
/// The ID of the surface texture that the camera preview is drawn to.
292294
late int _flutterSurfaceTextureId;
293295

@@ -408,6 +410,9 @@ class AndroidCameraCameraX extends CameraPlatform {
408410
_presetResolutionSelector = _getResolutionSelectorFromPreset(
409411
mediaSettings?.resolutionPreset,
410412
);
413+
414+
_targetFps = mediaSettings?.fps;
415+
411416
final QualitySelector? presetQualitySelector =
412417
_getQualitySelectorFromPreset(mediaSettings?.resolutionPreset);
413418

@@ -418,6 +423,7 @@ class AndroidCameraCameraX extends CameraPlatform {
418423
// Configure Preview instance.
419424
preview = proxy.newPreview(
420425
resolutionSelector: _presetResolutionSelector,
426+
targetFps: _targetFps,
421427
/* use CameraX default target rotation */ targetRotation: null,
422428
);
423429
_flutterSurfaceTextureId = await preview!.setSurfaceProvider(
@@ -433,7 +439,10 @@ class AndroidCameraCameraX extends CameraPlatform {
433439

434440
// Configure VideoCapture and Recorder instances.
435441
recorder = proxy.newRecorder(qualitySelector: presetQualitySelector);
436-
videoCapture = proxy.withOutputVideoCapture(videoOutput: recorder!);
442+
videoCapture = proxy.withOutputVideoCapture(
443+
videoOutput: recorder!,
444+
targetFps: _targetFps,
445+
);
437446

438447
// Retrieve info required for correcting the rotation of the camera preview
439448
// if necessary.
@@ -480,6 +489,7 @@ class AndroidCameraCameraX extends CameraPlatform {
480489
_imageAnalysisOutputFormatFromImageFormatGroup(imageFormatGroup);
481490
imageAnalysis = proxy.newImageAnalysis(
482491
resolutionSelector: _presetResolutionSelector,
492+
targetFps: _targetFps,
483493
outputImageFormat: _imageAnalysisOutputImageFormat,
484494
/* use CameraX default target rotation */ targetRotation: null,
485495
);

packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3314,6 +3314,7 @@ class Preview extends UseCase {
33143314
super.pigeon_instanceManager,
33153315
this.resolutionSelector,
33163316
int? targetRotation,
3317+
int? targetFps,
33173318
}) : super.pigeon_detached() {
33183319
final int pigeonVar_instanceIdentifier = pigeon_instanceManager
33193320
.addDartCreatedInstance(this);
@@ -3333,6 +3334,7 @@ class Preview extends UseCase {
33333334
pigeonVar_instanceIdentifier,
33343335
resolutionSelector,
33353336
targetRotation,
3337+
targetFps,
33363338
],
33373339
);
33383340
() async {
@@ -3622,6 +3624,7 @@ class VideoCapture extends UseCase {
36223624
super.pigeon_binaryMessenger,
36233625
super.pigeon_instanceManager,
36243626
required VideoOutput videoOutput,
3627+
int? targetFps,
36253628
}) : super.pigeon_detached() {
36263629
final int pigeonVar_instanceIdentifier = pigeon_instanceManager
36273630
.addDartCreatedInstance(this);
@@ -3637,7 +3640,7 @@ class VideoCapture extends UseCase {
36373640
binaryMessenger: pigeonVar_binaryMessenger,
36383641
);
36393642
final Future<Object?> pigeonVar_sendFuture = pigeonVar_channel.send(
3640-
<Object?>[pigeonVar_instanceIdentifier, videoOutput],
3643+
<Object?>[pigeonVar_instanceIdentifier, videoOutput, targetFps],
36413644
);
36423645
() async {
36433646
final List<Object?>? pigeonVar_replyList =
@@ -5967,6 +5970,7 @@ class ImageAnalysis extends UseCase {
59675970
super.pigeon_instanceManager,
59685971
this.resolutionSelector,
59695972
int? targetRotation,
5973+
int? targetFps,
59705974
int? outputImageFormat,
59715975
}) : super.pigeon_detached() {
59725976
final int pigeonVar_instanceIdentifier = pigeon_instanceManager
@@ -5987,6 +5991,7 @@ class ImageAnalysis extends UseCase {
59875991
pigeonVar_instanceIdentifier,
59885992
resolutionSelector,
59895993
targetRotation,
5994+
targetFps,
59905995
outputImageFormat,
59915996
]);
59925997
() async {
@@ -6793,7 +6798,7 @@ class ImageProxy extends PigeonInternalProxyApiBaseClass {
67936798
}
67946799
}
67956800

6796-
/// Utils for working with [ImageProxy]s.
6801+
/// Utilities for working with [ImageProxy]s.
67976802
class ImageProxyUtils extends PigeonInternalProxyApiBaseClass {
67986803
/// Constructs [ImageProxyUtils] without creating the associated native object.
67996804
///
@@ -6863,8 +6868,7 @@ class ImageProxyUtils extends PigeonInternalProxyApiBaseClass {
68636868
}
68646869
}
68656870

6866-
/// Returns a single Byte Buffer that is representative of the [planes]
6867-
/// that are NV21 compatible.
6871+
/// Returns a single buffer that is representative of three NV21-compatible [planes].
68686872
static Future<Uint8List> getNv21Buffer(
68696873
int imageWidth,
68706874
int imageHeight,

0 commit comments

Comments
 (0)