Skip to content

Commit 15bc49d

Browse files
committed
[camera] Adds support for video stabilization
- Implements getSupportedVideoStabilizationModes() and setVideoStabilizationMode() methods in CameraController.
1 parent 9fa0fdc commit 15bc49d

File tree

8 files changed

+2276
-4
lines changed

8 files changed

+2276
-4
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 <sanekyy@gmail.com>
6464
Anton Borries <mail@antonborri.es>
6565
Alex Li <google@alexv525.com>
6666
Rahul Raj <64.rahulraj@gmail.com>
67+
Rui Craveiro <ruicraveiro@squarealfa.com>

packages/camera/camera/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.12.0
2+
3+
* Adds support for video stabilization.
4+
15
## 0.11.4
26

37
* Updates minimum supported SDK version to Flutter 3.35/Dart 3.9.

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: 97 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 current video stabilization mode.
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,
@@ -198,6 +204,8 @@ class CameraValue {
198204
previewPauseOrientation: previewPauseOrientation == null
199205
? this.previewPauseOrientation
200206
: previewPauseOrientation.orNull,
207+
videoStabilizationMode:
208+
videoStabilizationMode ?? this.videoStabilizationMode,
201209
);
202210
}
203211

@@ -219,6 +227,7 @@ class CameraValue {
219227
'recordingOrientation: $recordingOrientation, '
220228
'isPreviewPaused: $isPreviewPaused, '
221229
'previewPausedOrientation: $previewPauseOrientation, '
230+
'videoStabilizationMode: $videoStabilizationMode, '
222231
'description: $description)';
223232
}
224233
}
@@ -720,6 +729,94 @@ class CameraController extends ValueNotifier<CameraValue> {
720729
}
721730
}
722731

732+
/// Set the video stabilization mode for the selected camera.
733+
///
734+
/// When [allowFallback] is true (default) the camera will be set to the best
735+
/// video stabilization mode up to, and including, [mode].
736+
///
737+
/// When [allowFallback] is false and if [mode] is not one of the supported
738+
/// modes (see [getSupportedVideoStabilizationModes]), then it throws an
739+
/// [ArgumentError].
740+
///
741+
/// This feature is only available if [getSupportedVideoStabilizationModes]
742+
/// returns at least one value other than [VideoStabilizationMode.off].
743+
Future<void> setVideoStabilizationMode(
744+
VideoStabilizationMode mode, {
745+
bool allowFallback = true,
746+
}) async {
747+
_throwIfNotInitialized('setVideoStabilizationMode');
748+
try {
749+
final VideoStabilizationMode? modeToSet =
750+
await _getVideoStabilizationModeToSet(mode, allowFallback);
751+
752+
// When _getVideoStabilizationModeToSet returns null
753+
// it means that the device doesn't support any
754+
// video stabilization mode and that doing nothing
755+
// is valid because allowFallback is true or [mode]
756+
// is [VideoStabilizationMode.off], so this results
757+
// in a no-op.
758+
if (modeToSet == null) {
759+
return;
760+
}
761+
await CameraPlatform.instance.setVideoStabilizationMode(
762+
_cameraId,
763+
modeToSet,
764+
);
765+
value = value.copyWith(videoStabilizationMode: modeToSet);
766+
} on PlatformException catch (e) {
767+
throw CameraException(e.code, e.message);
768+
}
769+
}
770+
771+
Future<VideoStabilizationMode?> _getVideoStabilizationModeToSet(
772+
VideoStabilizationMode requestedMode,
773+
bool allowFallback,
774+
) async {
775+
final Iterable<VideoStabilizationMode> supportedModes = await CameraPlatform
776+
.instance
777+
.getSupportedVideoStabilizationModes(_cameraId);
778+
779+
// If it can't fallback and the specific
780+
// requested mode isn't available, then...
781+
if (!allowFallback && !supportedModes.contains(requestedMode)) {
782+
// if the request is off, it is a no-op
783+
if (requestedMode == VideoStabilizationMode.off) {
784+
return null;
785+
}
786+
// otherwise, it throws.
787+
throw ArgumentError('Unavailable video stabilization mode.', 'mode');
788+
}
789+
790+
VideoStabilizationMode? fallbackMode = requestedMode;
791+
while (fallbackMode != null && !supportedModes.contains(fallbackMode)) {
792+
fallbackMode = CameraPlatform.getFallbackVideoStabilizationMode(
793+
fallbackMode,
794+
);
795+
}
796+
797+
return fallbackMode;
798+
}
799+
800+
/// Gets a list of video stabilization modes that are supported
801+
/// for the selected camera.
802+
///
803+
/// [VideoStabilizationMode.off] will always be listed.
804+
Future<Iterable<VideoStabilizationMode>>
805+
getSupportedVideoStabilizationModes() async {
806+
_throwIfNotInitialized('getSupportedVideoStabilizationModes');
807+
try {
808+
final modes = <VideoStabilizationMode>{
809+
VideoStabilizationMode.off,
810+
...await CameraPlatform.instance.getSupportedVideoStabilizationModes(
811+
_cameraId,
812+
),
813+
};
814+
return modes;
815+
} on PlatformException catch (e) {
816+
throw CameraException(e.code, e.message);
817+
}
818+
}
819+
723820
/// Sets the flash mode for taking pictures.
724821
Future<void> setFlashMode(FlashMode mode) async {
725822
try {

packages/camera/camera/pubspec.yaml

Lines changed: 4 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.4
7+
version: 0.12.0
88

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

2323
dependencies:
24-
camera_android_camerax: ^0.6.22
25-
camera_avfoundation: ^0.9.18
26-
camera_platform_interface: ^2.11.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

packages/camera/camera/test/camera_preview_test.dart

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

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

0 commit comments

Comments
 (0)