Skip to content

Commit 722b2a5

Browse files
committed
Adds video stabilization to camera
- Adds support for video stabilization to camera: Adds getSupportedVideoStabilizationModes() and setVideoStabilizationMode() methods to CameraController. - Adds support for video stabilization to camera_avfoundation - Adds support for video stabilization to camera_android_camerax - Adds support for video stabilization to camera_platform_interface: - Adds getSupportedVideoStabilizationModes() and setVideoStabilizationMode() methods to CameraPlatform. - Adds VideoStabilizationMode enum to represent an abstraction of the available video stabilization modes, meant for Android and iOS, mapped as follows: /// Video stabilization is disabled. off, /// Least stabilized video stabilization mode with the least latency. level1, /// More stabilized video with more latency. level2, /// Most stabilized video with the most latency. level3;
1 parent 287739d commit 722b2a5

File tree

58 files changed

+3866
-47
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3866
-47
lines changed

packages/camera/camera/AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,4 @@ Aleksandr Yurkovskiy <[email protected]>
6464
Anton Borries <[email protected]>
6565
6666
Rahul Raj <[email protected]>
67+
Rui Craveiro <[email protected]>

packages/camera/camera/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
* Updates minimum supported SDK version to Flutter 3.29/Dart 3.7.
44
* Updates README to reflect that only Android API 24+ is supported.
55

6+
## 0.12.0
7+
8+
* Adds support for video stabilization.
9+
610
## 0.11.2
711

812
* Fixes overflowed toggles in the camera example.

packages/camera/camera/example/pubspec.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,8 @@ dev_dependencies:
3131

3232
flutter:
3333
uses-material-design: true
34+
35+
# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
36+
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
37+
dependency_overrides:
38+
{camera: {path: ../../../camera/camera}, camera_android_camerax: {path: ../../../camera/camera_android_camerax}, camera_avfoundation: {path: ../../../camera/camera_avfoundation}, camera_platform_interface: {path: ../../../camera/camera_platform_interface}, camera_web: {path: ../../../camera/camera_web}}

packages/camera/camera/lib/camera.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export 'package:camera_platform_interface/camera_platform_interface.dart'
1313
FocusMode,
1414
ImageFormatGroup,
1515
ResolutionPreset,
16+
VideoStabilizationMode,
1617
XFile;
1718

1819
export 'src/camera_controller.dart';

packages/camera/camera/lib/src/camera_controller.dart

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class CameraValue {
5454
this.recordingOrientation,
5555
this.isPreviewPaused = false,
5656
this.previewPauseOrientation,
57+
this.videoStabilizationMode = VideoStabilizationMode.off,
5758
}) : _isRecordingPaused = isRecordingPaused;
5859

5960
/// Creates a new camera controller state for an uninitialized controller.
@@ -72,6 +73,7 @@ class CameraValue {
7273
deviceOrientation: DeviceOrientation.portraitUp,
7374
isPreviewPaused: false,
7475
description: description,
76+
videoStabilizationMode: VideoStabilizationMode.off,
7577
);
7678

7779
/// True after [CameraController.initialize] has completed successfully.
@@ -148,6 +150,9 @@ class CameraValue {
148150
/// The properties of the camera device controlled by this controller.
149151
final CameraDescription description;
150152

153+
/// The video stabilization mode in
154+
final VideoStabilizationMode videoStabilizationMode;
155+
151156
/// Creates a modified copy of the object.
152157
///
153158
/// Explicitly specified fields get the specified value, all other fields get
@@ -171,6 +176,7 @@ class CameraValue {
171176
bool? isPreviewPaused,
172177
CameraDescription? description,
173178
Optional<DeviceOrientation>? previewPauseOrientation,
179+
VideoStabilizationMode? videoStabilizationMode,
174180
}) {
175181
return CameraValue(
176182
isInitialized: isInitialized ?? this.isInitialized,
@@ -201,6 +207,8 @@ class CameraValue {
201207
previewPauseOrientation == null
202208
? this.previewPauseOrientation
203209
: previewPauseOrientation.orNull,
210+
videoStabilizationMode:
211+
videoStabilizationMode ?? this.videoStabilizationMode,
204212
);
205213
}
206214

@@ -222,6 +230,7 @@ class CameraValue {
222230
'recordingOrientation: $recordingOrientation, '
223231
'isPreviewPaused: $isPreviewPaused, '
224232
'previewPausedOrientation: $previewPauseOrientation, '
233+
'videoStabilizationMode: $videoStabilizationMode, '
225234
'description: $description)';
226235
}
227236
}
@@ -701,6 +710,111 @@ class CameraController extends ValueNotifier<CameraValue> {
701710
}
702711
}
703712

713+
/// Set the video stabilization mode for the selected camera.
714+
///
715+
/// When [allowFallback] is true (default) the camera will
716+
/// be set to the best video stabilization mode up to,
717+
/// and including, [mode].
718+
///
719+
/// When [allowFallback] is false and if
720+
/// [mode] is not one of the supported modes
721+
/// (see [getSupportedVideoStabilizationModes]),
722+
/// then it throws an [ArgumentError].
723+
///
724+
/// This feature is only available on Android
725+
/// (when using camera_android_camerax package)
726+
/// and iOS. It is a no-op on all other platforms.
727+
Future<void> setVideoStabilizationMode(
728+
VideoStabilizationMode mode, {
729+
bool allowFallback = true,
730+
}) async {
731+
_throwIfNotInitialized('setVideoStabilizationMode');
732+
try {
733+
final VideoStabilizationMode? modeToSet =
734+
await _getVideoStabilizationModeToSet(mode, allowFallback);
735+
736+
// When _getVideoStabilizationModeToSet returns null
737+
// it means that the device doesn't support any
738+
// video stabilization mode and that doing nothing
739+
// is valid because allowFallback is true or [mode]
740+
// is [VideoStabilizationMode.off], so this results
741+
// in a no-op.
742+
if (modeToSet == null) {
743+
return;
744+
}
745+
await CameraPlatform.instance.setVideoStabilizationMode(
746+
_cameraId,
747+
modeToSet,
748+
);
749+
value = value.copyWith(videoStabilizationMode: modeToSet);
750+
} on PlatformException catch (e) {
751+
throw CameraException(e.code, e.message);
752+
}
753+
}
754+
755+
Future<VideoStabilizationMode?> _getVideoStabilizationModeToSet(
756+
VideoStabilizationMode requestedMode,
757+
bool allowFallback,
758+
) async {
759+
final Iterable<VideoStabilizationMode> supportedModes = await CameraPlatform
760+
.instance
761+
.getSupportedVideoStabilizationModes(_cameraId);
762+
763+
// In this case the device doesn't report any
764+
// available stabilization mode available and
765+
// if either it can fallback or if the requested mode
766+
// is off, then this returns null to signal that
767+
// there is nothing to be done.
768+
if (supportedModes.isEmpty &&
769+
(allowFallback || requestedMode == VideoStabilizationMode.off)) {
770+
return null;
771+
}
772+
773+
// If it can't fallback and the specific
774+
// requested mode isn't available, then it throws.
775+
if (!allowFallback && !supportedModes.contains(requestedMode)) {
776+
throw ArgumentError('Unavailable video stabilization mode.', 'mode');
777+
}
778+
779+
// The following assumes that [VideoStabilizationMode.off] will
780+
// always be present if any other level is reported by the device.
781+
// It iterates through all the modes returned by the device,
782+
// looking for the highest mode, up to [mode].
783+
VideoStabilizationMode requestMode = VideoStabilizationMode.off;
784+
for (final VideoStabilizationMode supportedMode in supportedModes) {
785+
if (supportedMode.index <= requestedMode.index &&
786+
supportedMode.index >= requestMode.index) {
787+
requestMode = supportedMode;
788+
}
789+
}
790+
791+
return requestMode;
792+
}
793+
794+
/// Gets a list of video stabilization modes that are supported
795+
/// for the selected camera.
796+
///
797+
/// Will return the list of supported video stabilization modes
798+
/// on Android (when using camera_android_camerax package) and
799+
/// on iOS.
800+
///
801+
/// [VideoStabilizationMode.off] will always be listed.
802+
Future<Iterable<VideoStabilizationMode>>
803+
getSupportedVideoStabilizationModes() async {
804+
_throwIfNotInitialized('isVideoStabilizationModeSupported');
805+
try {
806+
final Set<VideoStabilizationMode> modes = <VideoStabilizationMode>{
807+
VideoStabilizationMode.off,
808+
...await CameraPlatform.instance.getSupportedVideoStabilizationModes(
809+
_cameraId,
810+
),
811+
};
812+
return modes;
813+
} on PlatformException catch (e) {
814+
throw CameraException(e.code, e.message);
815+
}
816+
}
817+
704818
/// Sets the flash mode for taking pictures.
705819
Future<void> setFlashMode(FlashMode mode) async {
706820
try {

packages/camera/camera/pubspec.yaml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing
44
Dart.
55
repository: https://github.com/flutter/packages/tree/main/packages/camera/camera
66
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22
7-
version: 0.11.2
7+
version: 0.12.0
88

99
environment:
1010
sdk: ^3.7.0
@@ -21,9 +21,9 @@ flutter:
2121
default_package: camera_web
2222

2323
dependencies:
24-
camera_android_camerax: ^0.6.13
25-
camera_avfoundation: ^0.9.18
26-
camera_platform_interface: ^2.10.0
24+
camera_android_camerax: ^0.7.0
25+
camera_avfoundation: ^0.10.0
26+
camera_platform_interface: ^2.12.0
2727
camera_web: ^0.3.3
2828
flutter:
2929
sdk: flutter
@@ -38,3 +38,8 @@ dev_dependencies:
3838

3939
topics:
4040
- camera
41+
42+
# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE.
43+
# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins
44+
dependency_overrides:
45+
{camera_android_camerax: {path: ../../camera/camera_android_camerax}, camera_avfoundation: {path: ../../camera/camera_avfoundation}, camera_platform_interface: {path: ../../camera/camera_platform_interface}, camera_web: {path: ../../camera/camera_web}}

packages/camera/camera/test/camera_preview_test.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,16 @@ class FakeController extends ValueNotifier<CameraValue>
137137
@override
138138
CameraDescription get description => value.description;
139139

140+
@override
141+
Future<void> setVideoStabilizationMode(
142+
VideoStabilizationMode mode, {
143+
bool allowFallback = true,
144+
}) async {}
145+
146+
@override
147+
Future<Iterable<VideoStabilizationMode>>
148+
getSupportedVideoStabilizationModes() async => <VideoStabilizationMode>[];
149+
140150
@override
141151
bool supportsImageStreaming() => true;
142152
}

0 commit comments

Comments
 (0)