Skip to content

Commit 4bf5114

Browse files
authored
[camera] CameraPlatform.createCameraWithSettings (#3615)
## Platform interface of federated plugin This is the `platform-interface` part of `camera` PR #3586. ## App-facing change Previously, CameraController was unable to setup fps and bitrates, allowing only resolution settings like this: ```dart controller = CameraController(_cameras[0], ResolutionPreset.max); ``` This PR gives additional functionality to set `fps` and `bitrates` via `withSettings`: ```dart controller = CameraController.withSettings( _cameras[0], mediaSettings: const MediaSettings( resolutionPreset: ResolutionPreset.low, fps: 15, videoBitrate: 200000, audioBitrate: 32000, enableAudio: true, ), ); ``` ## Android, iOS, etc. All platforms must implement `CameraPlatform.createCameraWithSettings` in addition to `CameraPlatform.createCamera`, providing platform specific code for `fps` and `bitrate' platform: ```dart Future<int> createCamera( CameraDescription cameraDescription, CameraDescription cameraDescription, ResolutionPreset? resolutionPreset, { ResolutionPreset? resolutionPreset, { bool enableAudio = false, bool enableAudio = false, }) { }) => throw UnimplementedError('createCamera() is not implemented.'); createCameraWithSettings( cameraDescription, MediaSettings( resolutionPreset: resolutionPreset, enableAudio: enableAudio, ), ); /// Creates an uninitialized camera instance and returns the cameraId. Future<int> createCameraWithSettings( CameraDescription cameraDescription, MediaSettings? mediaSettings, ) { throw UnimplementedError('createCameraWithSettings() is not implemented.'); } } ```
1 parent a2d8672 commit 4bf5114

File tree

10 files changed

+471
-20
lines changed

10 files changed

+471
-20
lines changed

packages/camera/camera_platform_interface/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.6.0
2+
3+
* Adds support to control video fps and bitrate. See `CameraPlatform.createCameraWithSettings`.
4+
15
## 2.5.2
26

37
* Adds pub topics to package metadata.

packages/camera/camera_platform_interface/lib/camera_platform_interface.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export 'package:cross_file/cross_file.dart';
88
export 'src/events/camera_event.dart';
99
export 'src/events/device_event.dart';
1010
export 'src/platform_interface/camera_platform.dart';
11+
export 'src/types/media_settings.dart';
1112
export 'src/types/types.dart';

packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,29 @@ class MethodChannelCamera extends CameraPlatform {
8888
CameraDescription cameraDescription,
8989
ResolutionPreset? resolutionPreset, {
9090
bool enableAudio = false,
91-
}) async {
91+
}) async =>
92+
createCameraWithSettings(
93+
cameraDescription,
94+
MediaSettings(
95+
resolutionPreset: resolutionPreset, enableAudio: enableAudio));
96+
97+
@override
98+
Future<int> createCameraWithSettings(
99+
CameraDescription cameraDescription,
100+
MediaSettings mediaSettings,
101+
) async {
92102
try {
103+
final ResolutionPreset? resolutionPreset = mediaSettings.resolutionPreset;
93104
final Map<String, dynamic>? reply = await _channel
94105
.invokeMapMethod<String, dynamic>('create', <String, dynamic>{
95106
'cameraName': cameraDescription.name,
96107
'resolutionPreset': resolutionPreset != null
97-
? _serializeResolutionPreset(resolutionPreset)
108+
? _serializeResolutionPreset(mediaSettings.resolutionPreset!)
98109
: null,
99-
'enableAudio': enableAudio,
110+
'fps': mediaSettings.fps,
111+
'videoBitrate': mediaSettings.videoBitrate,
112+
'audioBitrate': mediaSettings.audioBitrate,
113+
'enableAudio': mediaSettings.enableAudio,
100114
});
101115

102116
return reply!['cameraId']! as int;

packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ abstract class CameraPlatform extends PlatformInterface {
5555
throw UnimplementedError('createCamera() is not implemented.');
5656
}
5757

58+
/// Creates an uninitialized camera instance and returns the cameraId.
59+
///
60+
/// Pass MediaSettings() for defaults
61+
Future<int> createCameraWithSettings(
62+
CameraDescription cameraDescription,
63+
MediaSettings mediaSettings,
64+
) {
65+
return createCamera(
66+
cameraDescription,
67+
mediaSettings.resolutionPreset,
68+
enableAudio: mediaSettings.enableAudio,
69+
);
70+
}
71+
5872
/// Initializes the camera on the device.
5973
///
6074
/// [imageFormatGroup] is used to specify the image formatting used.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
// ignore_for_file: avoid_equals_and_hash_code_on_mutable_classes
6+
7+
import 'resolution_preset.dart';
8+
9+
/// Recording media settings.
10+
///
11+
/// Used in [CameraPlatform.createCameraWithSettings].
12+
/// Allows to tune recorded video parameters, such as resolution, frame rate, bitrate.
13+
/// If [fps], [videoBitrate] or [audioBitrate] are passed, they must be greater than zero.
14+
class MediaSettings {
15+
/// Creates a [MediaSettings].
16+
const MediaSettings({
17+
this.resolutionPreset,
18+
this.fps,
19+
this.videoBitrate,
20+
this.audioBitrate,
21+
this.enableAudio = false,
22+
}) : assert(fps == null || fps > 0, 'fps must be null or greater than zero'),
23+
assert(videoBitrate == null || videoBitrate > 0,
24+
'videoBitrate must be null or greater than zero'),
25+
assert(audioBitrate == null || audioBitrate > 0,
26+
'audioBitrate must be null or greater than zero');
27+
28+
/// [ResolutionPreset] affect the quality of video recording and image capture.
29+
final ResolutionPreset? resolutionPreset;
30+
31+
/// Rate at which frames should be captured by the camera in frames per second.
32+
final int? fps;
33+
34+
/// The video encoding bit rate for recording.
35+
final int? videoBitrate;
36+
37+
/// The audio encoding bit rate for recording.
38+
final int? audioBitrate;
39+
40+
/// Controls audio presence in recorded video.
41+
final bool enableAudio;
42+
43+
@override
44+
bool operator ==(Object other) {
45+
if (identical(other, this)) {
46+
return true;
47+
}
48+
if (other.runtimeType != runtimeType) {
49+
return false;
50+
}
51+
return other is MediaSettings &&
52+
resolutionPreset == other.resolutionPreset &&
53+
fps == other.fps &&
54+
videoBitrate == other.videoBitrate &&
55+
audioBitrate == other.audioBitrate &&
56+
enableAudio == other.enableAudio;
57+
}
58+
59+
@override
60+
int get hashCode => Object.hash(
61+
resolutionPreset,
62+
fps,
63+
videoBitrate,
64+
audioBitrate,
65+
enableAudio,
66+
);
67+
68+
@override
69+
String toString() {
70+
return 'MediaSettings{'
71+
'resolutionPreset: $resolutionPreset, '
72+
'fps: $fps, '
73+
'videoBitrate: $videoBitrate, '
74+
'audioBitrate: $audioBitrate, '
75+
'enableAudio: $enableAudio}';
76+
}
77+
}

packages/camera/camera_platform_interface/lib/src/types/types.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ export 'exposure_mode.dart';
99
export 'flash_mode.dart';
1010
export 'focus_mode.dart';
1111
export 'image_format_group.dart';
12+
export 'media_settings.dart';
1213
export 'resolution_preset.dart';
1314
export 'video_capture_options.dart';

packages/camera/camera_platform_interface/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/camera/camera
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
55
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
66
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
7-
version: 2.5.2
7+
version: 2.6.0
88

99
environment:
1010
sdk: ">=2.19.0 <4.0.0"

packages/camera/camera_platform_interface/test/camera_platform_interface_test.dart

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,67 @@ void main() {
163163
lensDirection: CameraLensDirection.back,
164164
sensorOrientation: 0,
165165
),
166-
ResolutionPreset.high,
166+
ResolutionPreset.low,
167167
),
168168
throwsUnimplementedError,
169169
);
170170
});
171171

172+
test(
173+
'Default implementation of createCameraWithSettings() should call createCamera() passing parameters',
174+
() {
175+
// Arrange
176+
const CameraDescription cameraDescription = CameraDescription(
177+
name: 'back',
178+
lensDirection: CameraLensDirection.back,
179+
sensorOrientation: 0,
180+
);
181+
182+
const MediaSettings mediaSettings = MediaSettings(
183+
resolutionPreset: ResolutionPreset.low,
184+
fps: 15,
185+
videoBitrate: 200000,
186+
audioBitrate: 32000,
187+
enableAudio: true,
188+
);
189+
190+
bool createCameraCalled = false;
191+
192+
final OverriddenCameraPlatform cameraPlatform = OverriddenCameraPlatform((
193+
CameraDescription cameraDescriptionArg,
194+
ResolutionPreset? resolutionPresetArg,
195+
bool enableAudioArg,
196+
) {
197+
expect(
198+
cameraDescriptionArg,
199+
cameraDescription,
200+
reason: 'should pass camera description',
201+
);
202+
expect(
203+
resolutionPresetArg,
204+
mediaSettings.resolutionPreset,
205+
reason: 'should pass resolution preset',
206+
);
207+
expect(
208+
enableAudioArg,
209+
mediaSettings.enableAudio,
210+
reason: 'should pass enableAudio',
211+
);
212+
213+
createCameraCalled = true;
214+
});
215+
216+
// Act & Assert
217+
cameraPlatform.createCameraWithSettings(
218+
cameraDescription,
219+
mediaSettings,
220+
);
221+
222+
expect(createCameraCalled, isTrue,
223+
reason:
224+
'default implementation of createCameraWithSettings should call createCamera passing parameters');
225+
});
226+
172227
test(
173228
'Default implementation of initializeCamera() should throw unimplemented error',
174229
() {
@@ -496,3 +551,21 @@ class ImplementsCameraPlatform implements CameraPlatform {
496551
}
497552

498553
class ExtendsCameraPlatform extends CameraPlatform {}
554+
555+
class OverriddenCameraPlatform extends CameraPlatform {
556+
OverriddenCameraPlatform(this._onCreateCameraCalled);
557+
558+
final void Function(
559+
CameraDescription cameraDescription,
560+
ResolutionPreset? resolutionPreset,
561+
bool enableAudio,
562+
) _onCreateCameraCalled;
563+
564+
@override
565+
Future<int> createCamera(
566+
CameraDescription cameraDescription, ResolutionPreset? resolutionPreset,
567+
{bool enableAudio = false}) {
568+
_onCreateCameraCalled(cameraDescription, resolutionPreset, enableAudio);
569+
return Future<int>.value(0);
570+
}
571+
}

0 commit comments

Comments
 (0)