diff --git a/packages/camera/camera/AUTHORS b/packages/camera/camera/AUTHORS index 493a0b4ef9c..605414ab7dc 100644 --- a/packages/camera/camera/AUTHORS +++ b/packages/camera/camera/AUTHORS @@ -64,3 +64,4 @@ Aleksandr Yurkovskiy Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> +Rui Craveiro diff --git a/packages/camera/camera/CHANGELOG.md b/packages/camera/camera/CHANGELOG.md index d0d58be6ca9..bc4d4cccdbf 100644 --- a/packages/camera/camera/CHANGELOG.md +++ b/packages/camera/camera/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.12.0 + +* Adds support for video stabilization. + ## 0.11.1 * Adds API support query for image streaming. diff --git a/packages/camera/camera/example/pubspec.yaml b/packages/camera/camera/example/pubspec.yaml index aff0afef21f..8aa6161057a 100644 --- a/packages/camera/camera/example/pubspec.yaml +++ b/packages/camera/camera/example/pubspec.yaml @@ -31,3 +31,8 @@ dev_dependencies: flutter: uses-material-design: true + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {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}} diff --git a/packages/camera/camera/lib/camera.dart b/packages/camera/camera/lib/camera.dart index 507d6c7cded..3778c870071 100644 --- a/packages/camera/camera/lib/camera.dart +++ b/packages/camera/camera/lib/camera.dart @@ -12,6 +12,7 @@ export 'package:camera_platform_interface/camera_platform_interface.dart' FocusMode, ImageFormatGroup, ResolutionPreset, + VideoStabilizationMode, XFile; export 'src/camera_controller.dart'; diff --git a/packages/camera/camera/lib/src/camera_controller.dart b/packages/camera/camera/lib/src/camera_controller.dart index 3f39d3202b8..5331199681e 100644 --- a/packages/camera/camera/lib/src/camera_controller.dart +++ b/packages/camera/camera/lib/src/camera_controller.dart @@ -54,6 +54,7 @@ class CameraValue { this.recordingOrientation, this.isPreviewPaused = false, this.previewPauseOrientation, + this.videoStabilizationMode = VideoStabilizationMode.off, }) : _isRecordingPaused = isRecordingPaused; /// Creates a new camera controller state for an uninitialized controller. @@ -72,6 +73,7 @@ class CameraValue { deviceOrientation: DeviceOrientation.portraitUp, isPreviewPaused: false, description: description, + videoStabilizationMode: VideoStabilizationMode.off, ); /// True after [CameraController.initialize] has completed successfully. @@ -148,6 +150,9 @@ class CameraValue { /// The properties of the camera device controlled by this controller. final CameraDescription description; + /// The video stabilization mode in + final VideoStabilizationMode videoStabilizationMode; + /// Creates a modified copy of the object. /// /// Explicitly specified fields get the specified value, all other fields get @@ -171,6 +176,7 @@ class CameraValue { bool? isPreviewPaused, CameraDescription? description, Optional? previewPauseOrientation, + VideoStabilizationMode? videoStabilizationMode, }) { return CameraValue( isInitialized: isInitialized ?? this.isInitialized, @@ -198,6 +204,8 @@ class CameraValue { previewPauseOrientation: previewPauseOrientation == null ? this.previewPauseOrientation : previewPauseOrientation.orNull, + videoStabilizationMode: + videoStabilizationMode ?? this.videoStabilizationMode, ); } @@ -219,6 +227,7 @@ class CameraValue { 'recordingOrientation: $recordingOrientation, ' 'isPreviewPaused: $isPreviewPaused, ' 'previewPausedOrientation: $previewPauseOrientation, ' + 'videoStabilizationMode: $videoStabilizationMode, ' 'description: $description)'; } } @@ -687,6 +696,80 @@ class CameraController extends ValueNotifier { } } + /// Set the video stabilization mode for the selected camera. + /// + /// On Android (when using camera_android_camerax) and on iOS + /// the supplied [mode] value should be a mode in the list returned + /// by [getSupportedVideoStabilizationModes]. + /// + /// When [allowFallback] is true (default) and when + /// the camera supports any video stabilization other than + /// [VideoStabilizationMode.off], then the camera will + /// be set to the best video stabilization mode up to, and including, [mode]. + /// + /// When either [allowFallback] is false or the only + /// supported video stabilization mode is [VideoStabilizationMode.off], + /// and if [mode] is not one of the supported modes, + /// then it throws an [ArgumentError]. + Future setVideoStabilizationMode( + VideoStabilizationMode mode, { + bool allowFallback = true, + }) async { + _throwIfNotInitialized('setVideoStabilizationMode'); + try { + final VideoStabilizationMode requestMode = + allowFallback ? await _getVideoStabilizationFallbackMode(mode) : mode; + + await CameraPlatform.instance + .setVideoStabilizationMode(_cameraId, requestMode); + value = value.copyWith(videoStabilizationMode: mode); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + Future _getVideoStabilizationFallbackMode( + VideoStabilizationMode mode) async { + final Iterable supportedModes = await CameraPlatform + .instance + .getSupportedVideoStabilizationModes(_cameraId); + + // if there are no supported modes or if the only supported mode is Off + // and something else is requested, then we throw an ArgumentError. + if (supportedModes.isEmpty || + (mode != VideoStabilizationMode.off && + supportedModes.every((VideoStabilizationMode sm) => + sm == VideoStabilizationMode.off))) { + throw ArgumentError('Unavailable video stabilization mode.', 'mode'); + } + + VideoStabilizationMode requestMode = VideoStabilizationMode.off; + for (final VideoStabilizationMode supportedMode in supportedModes) { + if (supportedMode.index <= mode.index && + supportedMode.index >= requestMode.index) { + requestMode = supportedMode; + } + } + + return requestMode; + } + + /// Gets a list of video stabilization modes that are supported for the selected camera. + /// + /// Will return the list of supported video stabilization modes + /// on Android (when using camera_android_camerax package) and + /// on iOS. Throws an [UnimplementedError] on all other platforms. + Future> + getSupportedVideoStabilizationModes() { + _throwIfNotInitialized('isVideoStabilizationModeSupported'); + try { + return CameraPlatform.instance + .getSupportedVideoStabilizationModes(_cameraId); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + /// Sets the flash mode for taking pictures. Future setFlashMode(FlashMode mode) async { try { diff --git a/packages/camera/camera/pubspec.yaml b/packages/camera/camera/pubspec.yaml index 09899dfa579..8d65d085e2b 100644 --- a/packages/camera/camera/pubspec.yaml +++ b/packages/camera/camera/pubspec.yaml @@ -4,7 +4,7 @@ description: A Flutter plugin for controlling the camera. Supports previewing Dart. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.11.1 +version: 0.12.0 environment: sdk: ^3.6.0 @@ -21,9 +21,9 @@ flutter: default_package: camera_web dependencies: - camera_android_camerax: ^0.6.13 - camera_avfoundation: ^0.9.18 - camera_platform_interface: ^2.9.0 + camera_android_camerax: ^0.7.0 + camera_avfoundation: ^0.10.0 + camera_platform_interface: ^2.10.0 camera_web: ^0.3.3 flutter: sdk: flutter @@ -38,3 +38,8 @@ dev_dependencies: topics: - camera + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {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}} diff --git a/packages/camera/camera/test/camera_preview_test.dart b/packages/camera/camera/test/camera_preview_test.dart index 73359e455ad..a4cf9d3d01e 100644 --- a/packages/camera/camera/test/camera_preview_test.dart +++ b/packages/camera/camera/test/camera_preview_test.dart @@ -133,6 +133,16 @@ class FakeController extends ValueNotifier @override CameraDescription get description => value.description; + @override + Future setVideoStabilizationMode( + VideoStabilizationMode mode, { + bool allowFallback = true, + }) async {} + + @override + Future> + getSupportedVideoStabilizationModes() async => []; + @override bool supportsImageStreaming() => true; } diff --git a/packages/camera/camera/test/camera_test.dart b/packages/camera/camera/test/camera_test.dart index 0c6a319397e..51a3f065e8e 100644 --- a/packages/camera/camera/test/camera_test.dart +++ b/packages/camera/camera/test/camera_test.dart @@ -1190,6 +1190,532 @@ void main() { .called(4); }); + test('getSupportedVideoStabilizationModes() returns empty list', () async { + // arrange + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => []); + + // act + final Iterable modes = + await cameraController.getSupportedVideoStabilizationModes(); + + // assert + expect(modes, []); + }); + + test('getSupportedVideoStabilizationModes() returns off', () async { + // arrange + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => + [VideoStabilizationMode.off]); + + // act + final Iterable modes = + await cameraController.getSupportedVideoStabilizationModes(); + + // assert + expect(modes, [VideoStabilizationMode.off]); + }); + + test('getSupportedVideoStabilizationModes() returns all modes', () async { + // arrange + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + + await cameraController.initialize(); + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => [ + VideoStabilizationMode.off, + VideoStabilizationMode.level1, + VideoStabilizationMode.level2, + VideoStabilizationMode.level3, + ]); + + // act + final Iterable modes = + await cameraController.getSupportedVideoStabilizationModes(); + + // assert + expect(modes, [ + VideoStabilizationMode.off, + VideoStabilizationMode.level1, + VideoStabilizationMode.level2, + VideoStabilizationMode.level3, + ]); + }); + + test( + 'setVideoStabilizationMode() throws $CameraException on $PlatformException', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => [ + VideoStabilizationMode.off, + VideoStabilizationMode.level1, + ]); + + when(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level1)) + .thenThrow( + PlatformException( + code: 'TEST_ERROR', + message: 'This is a test error message', + ), + ); + + expect( + cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level1), + throwsA(isA().having( + (CameraException error) => error.description, + 'TEST_ERROR', + 'This is a test error message', + ))); + }); + + test( + 'setVideoStabilizationMode() throws $ArgumentError when no supported mode is available', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => []); + + expect( + cameraController + .setVideoStabilizationMode(VideoStabilizationMode.off), + throwsA(isA().having( + (ArgumentError error) => error.name, + 'name', + 'mode', + ))); + expect( + cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level1), + throwsA(isA().having( + (ArgumentError error) => error.name, + 'name', + 'mode', + ))); + expect( + cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level2), + throwsA(isA().having( + (ArgumentError error) => error.name, + 'name', + 'mode', + ))); + expect( + cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level3), + throwsA(isA().having( + (ArgumentError error) => error.name, + 'name', + 'mode', + ))); + }); + + test( + 'setVideoStabilizationMode() throws $ArgumentError when only Off mode is available', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => [ + VideoStabilizationMode.off, + ]); + + expect( + cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level1), + throwsA(isA().having( + (ArgumentError error) => error.name, + 'name', + 'mode', + ))); + expect( + cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level2), + throwsA(isA().having( + (ArgumentError error) => error.name, + 'name', + 'mode', + ))); + expect( + cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level3), + throwsA(isA().having( + (ArgumentError error) => error.name, + 'name', + 'mode', + ))); + }); + + test( + 'setVideoStabilizationMode() calls CameraPlatform with VideoStabilizationMode.off', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => [ + VideoStabilizationMode.off, + ]); + + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.off); + + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.off)) + .called(1); + }); + + test( + 'setVideoStabilizationMode() calls CameraPlatform with fallback level1', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => [ + VideoStabilizationMode.off, + VideoStabilizationMode.level1, + ]); + + when(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level1)) + .thenAnswer((_) async {}); + when(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level2)) + .thenAnswer((_) async {}); + when(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level3)) + .thenAnswer((_) async {}); + + clearInteractions(CameraPlatform.instance); + + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.off); + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level1); + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level2); + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level3); + + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.off)) + .called(1); + + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level1)) + .called(3); + + verifyNever(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level2)); + + verifyNever(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level3)); + }); + + test( + 'setVideoStabilizationMode() calls CameraPlatform with fallback level2', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => [ + VideoStabilizationMode.off, + VideoStabilizationMode.level1, + VideoStabilizationMode.level2, + ]); + + clearInteractions(CameraPlatform.instance); + + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.off); + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level1); + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level2); + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level3); + + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.off)) + .called(1); + + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level1)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level2)) + .called(2); + verifyNever(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level3)); + }); + + test( + 'setVideoStabilizationMode() calls CameraPlatform with fallback level3', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => [ + VideoStabilizationMode.off, + VideoStabilizationMode.level1, + VideoStabilizationMode.level2, + VideoStabilizationMode.level3, + ]); + + clearInteractions(CameraPlatform.instance); + + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.off); + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level1); + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level2); + await cameraController + .setVideoStabilizationMode(VideoStabilizationMode.level3); + + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.off)) + .called(1); + + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level1)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level2)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level3)) + .called(1); + }); + + test( + 'setVideoStabilizationMode() with false allowFallback calls platform with mode as is when no supported mode is available', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => []); + + clearInteractions(CameraPlatform.instance); + + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.off, + allowFallback: false, + ); + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.level1, + allowFallback: false, + ); + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.level2, + allowFallback: false, + ); + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.level3, + allowFallback: false, + ); + + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.off)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level1)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level2)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level3)) + .called(1); + }); + + test( + 'setVideoStabilizationMode() with false allowFallback calls platform with mode as is when only VideoStabilizationMode.off is available', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => [ + VideoStabilizationMode.off, + ]); + + clearInteractions(CameraPlatform.instance); + + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.off, + allowFallback: false, + ); + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.level1, + allowFallback: false, + ); + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.level2, + allowFallback: false, + ); + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.level3, + allowFallback: false, + ); + + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.off)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level1)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level2)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level3)) + .called(1); + }); + + test( + 'setVideoStabilizationMode() with false allowFallback calls platform with mode as is when all modes are available', + () async { + final CameraController cameraController = CameraController( + const CameraDescription( + name: 'cam', + lensDirection: CameraLensDirection.back, + sensorOrientation: 90), + ResolutionPreset.max); + await cameraController.initialize(); + + when(CameraPlatform.instance + .getSupportedVideoStabilizationModes(mockInitializeCamera)) + .thenAnswer((_) async => [ + VideoStabilizationMode.off, + VideoStabilizationMode.level1, + VideoStabilizationMode.level2, + VideoStabilizationMode.level3, + ]); + + clearInteractions(CameraPlatform.instance); + + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.off, + allowFallback: false, + ); + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.level1, + allowFallback: false, + ); + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.level2, + allowFallback: false, + ); + await cameraController.setVideoStabilizationMode( + VideoStabilizationMode.level3, + allowFallback: false, + ); + + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.off)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level1)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level2)) + .called(1); + verify(CameraPlatform.instance.setVideoStabilizationMode( + cameraController.cameraId, VideoStabilizationMode.level3)) + .called(1); + }); + test('pausePreview() calls $CameraPlatform', () async { final CameraController cameraController = CameraController( const CameraDescription( @@ -1602,6 +2128,23 @@ class MockCameraPlatform extends Mock Invocation.method(#setExposureOffset, [cameraId, offset]), returnValue: Future.value(1.0), ) as Future; + + @override + Future> getSupportedVideoStabilizationModes( + int cameraId) { + return super.noSuchMethod( + Invocation.method( + #getSupportedVideoStabilizationModes, [cameraId]), + returnValue: Future>.value( + []), + ) as Future>; + } + + @override + Future setVideoStabilizationMode( + int cameraId, VideoStabilizationMode mode) async => + super.noSuchMethod(Invocation.method( + #setVideoStabilizationMode, [cameraId, mode])); } class MockCameraDescription extends CameraDescription { diff --git a/packages/camera/camera/test/camera_value_test.dart b/packages/camera/camera/test/camera_value_test.dart index dbb1ddcbf78..5cbd83075b1 100644 --- a/packages/camera/camera/test/camera_value_test.dart +++ b/packages/camera/camera/test/camera_value_test.dart @@ -28,6 +28,7 @@ void main() { focusPointSupported: true, previewPauseOrientation: DeviceOrientation.portraitUp, description: FakeController.fakeDescription, + videoStabilizationMode: VideoStabilizationMode.level2, ); expect(cameraValue, isA()); @@ -47,6 +48,7 @@ void main() { expect(cameraValue.recordingOrientation, DeviceOrientation.portraitUp); expect(cameraValue.isPreviewPaused, false); expect(cameraValue.previewPauseOrientation, DeviceOrientation.portraitUp); + expect(cameraValue.videoStabilizationMode, VideoStabilizationMode.level2); }); test('Can be created as uninitialized', () { @@ -70,6 +72,7 @@ void main() { expect(cameraValue.recordingOrientation, null); expect(cameraValue.isPreviewPaused, isFalse); expect(cameraValue.previewPauseOrientation, null); + expect(cameraValue.videoStabilizationMode, VideoStabilizationMode.off); }); test('Can be copied with isInitialized', () { @@ -94,6 +97,7 @@ void main() { expect(cameraValue.recordingOrientation, null); expect(cameraValue.isPreviewPaused, isFalse); expect(cameraValue.previewPauseOrientation, null); + expect(cameraValue.videoStabilizationMode, VideoStabilizationMode.off); }); test('Has aspectRatio after setting size', () { @@ -144,10 +148,11 @@ void main() { isPreviewPaused: true, previewPauseOrientation: DeviceOrientation.portraitUp, description: FakeController.fakeDescription, + videoStabilizationMode: VideoStabilizationMode.level3, ); expect(cameraValue.toString(), - 'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false, flashMode: FlashMode.auto, exposureMode: ExposureMode.auto, focusMode: FocusMode.auto, exposurePointSupported: true, focusPointSupported: true, deviceOrientation: DeviceOrientation.portraitUp, lockedCaptureOrientation: DeviceOrientation.portraitUp, recordingOrientation: DeviceOrientation.portraitUp, isPreviewPaused: true, previewPausedOrientation: DeviceOrientation.portraitUp, description: CameraDescription(, CameraLensDirection.back, 0))'); + 'CameraValue(isRecordingVideo: false, isInitialized: false, errorDescription: null, previewSize: Size(10.0, 10.0), isStreamingImages: false, flashMode: FlashMode.auto, exposureMode: ExposureMode.auto, focusMode: FocusMode.auto, exposurePointSupported: true, focusPointSupported: true, deviceOrientation: DeviceOrientation.portraitUp, lockedCaptureOrientation: DeviceOrientation.portraitUp, recordingOrientation: DeviceOrientation.portraitUp, isPreviewPaused: true, previewPausedOrientation: DeviceOrientation.portraitUp, videoStabilizationMode: VideoStabilizationMode.level3, description: CameraDescription(, CameraLensDirection.back, 0))'); }); }); } diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index 60b8e6cd0a4..5f25cf8c3ab 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -41,6 +41,7 @@ ## 0.10.9+9 +* Updates camera_platform_interface lib to 2.9.0. * Updates lint checks to ignore NewerVersionAvailable. ## 0.10.9+8 diff --git a/packages/camera/camera_android/example/pubspec.yaml b/packages/camera/camera_android/example/pubspec.yaml index 9c8f8476d0b..2ef3b88c1c4 100644 --- a/packages/camera/camera_android/example/pubspec.yaml +++ b/packages/camera/camera_android/example/pubspec.yaml @@ -31,3 +31,8 @@ dev_dependencies: flutter: uses-material-design: true + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {camera_android: {path: ../../../camera/camera_android}, camera_platform_interface: {path: ../../../camera/camera_platform_interface}} diff --git a/packages/camera/camera_android/pubspec.yaml b/packages/camera/camera_android/pubspec.yaml index 33163076f68..ace6675291a 100644 --- a/packages/camera/camera_android/pubspec.yaml +++ b/packages/camera/camera_android/pubspec.yaml @@ -36,3 +36,8 @@ dev_dependencies: topics: - camera + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {camera_platform_interface: {path: ../../camera/camera_platform_interface}} diff --git a/packages/camera/camera_android_camerax/AUTHORS b/packages/camera/camera_android_camerax/AUTHORS index 557dff97933..7fc8bd920ea 100644 --- a/packages/camera/camera_android_camerax/AUTHORS +++ b/packages/camera/camera_android_camerax/AUTHORS @@ -4,3 +4,4 @@ # Name/Organization Google Inc. +Rui Craveiro \ No newline at end of file diff --git a/packages/camera/camera_android_camerax/CHANGELOG.md b/packages/camera/camera_android_camerax/CHANGELOG.md index f678aeef8d3..02edacf8225 100644 --- a/packages/camera/camera_android_camerax/CHANGELOG.md +++ b/packages/camera/camera_android_camerax/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.0 + +* Adds video stabilization. + ## 0.6.14+1 * Updates compileSdk 34 to flutter.compileSdkVersion. diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/Camera2CameraInfoHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/Camera2CameraInfoHostApiImpl.java index 983e9e0c674..e704c027eb8 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/Camera2CameraInfoHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/Camera2CameraInfoHostApiImpl.java @@ -4,7 +4,6 @@ package io.flutter.plugins.camerax; -import android.content.Context; import android.hardware.camera2.CameraCharacteristics; import androidx.annotation.NonNull; import androidx.annotation.OptIn; @@ -14,6 +13,8 @@ import androidx.camera.core.CameraInfo; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugins.camerax.GeneratedCameraXLibrary.Camera2CameraInfoHostApi; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; /** @@ -22,6 +23,7 @@ *

This class handles instantiating and adding native object instances that are attached to a * Dart instance or handle method calls on the associated native class or an instance of the class. */ +@OptIn(markerClass = ExperimentalCamera2Interop.class) public class Camera2CameraInfoHostApiImpl implements Camera2CameraInfoHostApi { private final BinaryMessenger binaryMessenger; private final InstanceManager instanceManager; @@ -29,7 +31,6 @@ public class Camera2CameraInfoHostApiImpl implements Camera2CameraInfoHostApi { /** Proxy for methods of {@link Camera2CameraInfo}. */ @VisibleForTesting - @OptIn(markerClass = ExperimentalCamera2Interop.class) public static class Camera2CameraInfoProxy { @NonNull @@ -53,6 +54,14 @@ public Long getSensorOrientation(@NonNull Camera2CameraInfo camera2CameraInfo) { return Long.valueOf( camera2CameraInfo.getCameraCharacteristic(CameraCharacteristics.SENSOR_ORIENTATION)); } + + @NonNull + public int[] getAvailableVideoStabilizationModes(@NonNull Camera2CameraInfo camera2CameraInfo) { + int[] modes = + camera2CameraInfo.getCameraCharacteristic( + CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES); + return modes == null ? new int[] {} : modes; + } } /** @@ -60,7 +69,6 @@ public Long getSensorOrientation(@NonNull Camera2CameraInfo camera2CameraInfo) { * * @param binaryMessenger used to communicate with Dart over asynchronous messages * @param instanceManager maintains instances stored to communicate with attached Dart objects - * @param context {@link Context} used to retrieve {@code Executor} */ public Camera2CameraInfoHostApiImpl( @NonNull BinaryMessenger binaryMessenger, @NonNull InstanceManager instanceManager) { @@ -116,7 +124,18 @@ public Long getSensorOrientation(@NonNull Long identifier) { return proxy.getSensorOrientation(getCamera2CameraInfoInstance(identifier)); } - @OptIn(markerClass = ExperimentalCamera2Interop.class) + @NonNull + @Override + public List getAvailableVideoStabilizationModes(@NonNull Long identifier) { + + int[] availableModes = proxy.getAvailableVideoStabilizationModes(getCamera2CameraInfoInstance(identifier)); + List ret = new ArrayList(availableModes.length); + for (int i : availableModes) { + ret.add((long) i); + } + return ret; + } + private Camera2CameraInfo getCamera2CameraInfoInstance(@NonNull Long identifier) { return Objects.requireNonNull(instanceManager.getInstance(identifier)); } diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CaptureRequestOptionsHostApiImpl.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CaptureRequestOptionsHostApiImpl.java index f76dd5422e7..af05e045cce 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CaptureRequestOptionsHostApiImpl.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/CaptureRequestOptionsHostApiImpl.java @@ -51,6 +51,10 @@ public static class CaptureRequestOptionsProxy { builder.setCaptureRequestOption( (CaptureRequest.Key) optionKey, (Boolean) optionValue); break; + case CONTROL_VIDEO_STABILIZATION_MODE: + builder.setCaptureRequestOption( + (CaptureRequest.Key) optionKey, (int) optionValue); + break; default: throw new IllegalArgumentException( "The capture request key " @@ -69,6 +73,9 @@ private CaptureRequest.Key getCaptureRequestKey( case CONTROL_AE_LOCK: key = CaptureRequest.CONTROL_AE_LOCK; break; + case CONTROL_VIDEO_STABILIZATION_MODE: + key = CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE; + break; default: throw new IllegalArgumentException( "The capture request key is not currently supported by the plugin."); diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java index 93f65cbc791..e3fd3e507ad 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/GeneratedCameraXLibrary.java @@ -181,7 +181,8 @@ private VideoRecordEvent(final int index) { * Camera2. */ public enum CaptureRequestKeySupportedType { - CONTROL_AE_LOCK(0); + CONTROL_AE_LOCK(0), + CONTROL_VIDEO_STABILIZATION_MODE(1); final int index; @@ -4444,6 +4445,9 @@ public interface Camera2CameraInfoHostApi { @NonNull Long getSensorOrientation(@NonNull Long identifier); + @NonNull + List getAvailableVideoStabilizationModes(@NonNull Long identifier); + /** The codec used by Camera2CameraInfoHostApi. */ static @NonNull MessageCodec getCodec() { return new StandardMessageCodec(); @@ -4563,6 +4567,33 @@ static void setup( channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.Camera2CameraInfoHostApi.getAvailableVideoStabilizationModes", + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + Number identifierArg = (Number) args.get(0); + try { + List output = + api.getAvailableVideoStabilizationModes( + (identifierArg == null) ? null : identifierArg.longValue()); + wrapped.add(0, output); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } } } /** Generated class from Pigeon that represents Flutter messages that can be called from Java. */ diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/Camera2CameraInfoTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/Camera2CameraInfoTest.java index a5ab10ff79b..4d6aac853c3 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/Camera2CameraInfoTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/Camera2CameraInfoTest.java @@ -4,6 +4,10 @@ package io.flutter.plugins.camerax; +import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_OFF; +import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON; +import static android.hardware.camera2.CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -17,6 +21,7 @@ import androidx.camera.camera2.interop.Camera2CameraInfo; import androidx.camera.core.CameraInfo; import io.flutter.plugin.common.BinaryMessenger; +import java.util.List; import java.util.Objects; import org.junit.After; import org.junit.Before; @@ -86,6 +91,52 @@ public void getSupportedHardwareLevel_returnsExpectedLevel() { hostApi.getSupportedHardwareLevel(camera2CameraInfoIdentifier).intValue()); } + @Test + public void getAvailableVideoStabilizationModes_returnsNone() { + final Camera2CameraInfoHostApiImpl hostApi = + new Camera2CameraInfoHostApiImpl(mock(BinaryMessenger.class), testInstanceManager); + final long camera2CameraInfoIdentifier = 3; + + testInstanceManager.addDartCreatedInstance(mockCamera2CameraInfo, camera2CameraInfoIdentifier); + when(mockCamera2CameraInfo.getCameraCharacteristic( + CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES)) + .thenReturn(new int[] {}); + + List returned = hostApi.getAvailableVideoStabilizationModes(camera2CameraInfoIdentifier); + assertEquals(0, returned.size()); + } + + @Test + public void getAvailableVideoStabilizationModes_returnsAll() { + // arrange + final Camera2CameraInfoHostApiImpl hostApi = + new Camera2CameraInfoHostApiImpl(mock(BinaryMessenger.class), testInstanceManager); + final long camera2CameraInfoIdentifier = 3; + + int[] expected = + new int[] { + CONTROL_VIDEO_STABILIZATION_MODE_OFF, + CONTROL_VIDEO_STABILIZATION_MODE_ON, + CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION, + }; + + testInstanceManager.addDartCreatedInstance(mockCamera2CameraInfo, camera2CameraInfoIdentifier); + when(mockCamera2CameraInfo.getCameraCharacteristic( + CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES)) + .thenReturn(expected); + + // act + int[] returned = + hostApi + .getAvailableVideoStabilizationModes(camera2CameraInfoIdentifier) + .stream() + .mapToInt(value -> value.intValue()) + .toArray(); + + // assert + assertArrayEquals(expected, returned); + } + @Test public void getCameraId_returnsExpectedId() { final Camera2CameraInfoHostApiImpl hostApi = diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CaptureRequestOptionsTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CaptureRequestOptionsTest.java index 9c3329978d4..912207470fa 100644 --- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CaptureRequestOptionsTest.java +++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/CaptureRequestOptionsTest.java @@ -55,6 +55,7 @@ public void create_buildsExpectedCaptureKeyRequestOptionsWhenOptionsNonNull() { new HashMap() { { put(0L, false); + put(1L, 1); } }; @@ -71,6 +72,13 @@ public void create_buildsExpectedCaptureKeyRequestOptionsWhenOptionsNonNull() { .setCaptureRequestOption( eq(CaptureRequest.CONTROL_AE_LOCK), eq((Boolean) testValueForSupportedType)); break; + case CONTROL_VIDEO_STABILIZATION_MODE: + verify(mockBuilder) + .setCaptureRequestOption( + eq(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE), + eq((Integer) testValueForSupportedType)); + break; + default: throw new IllegalArgumentException( "The capture request key is not currently supported by the plugin."); diff --git a/packages/camera/camera_android_camerax/example/pubspec.yaml b/packages/camera/camera_android_camerax/example/pubspec.yaml index 62736015336..a0c4bca9f38 100644 --- a/packages/camera/camera_android_camerax/example/pubspec.yaml +++ b/packages/camera/camera_android_camerax/example/pubspec.yaml @@ -29,3 +29,8 @@ dev_dependencies: flutter: uses-material-design: true +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {camera_android_camerax: {path: ../../../camera/camera_android_camerax}, camera_platform_interface: {path: ../../../camera/camera_platform_interface}} + diff --git a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart index 8e61727cc61..7dbd35c235a 100644 --- a/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart +++ b/packages/camera/camera_android_camerax/lib/src/android_camera_camerax.dart @@ -793,6 +793,71 @@ class AndroidCameraCameraX extends CameraPlatform { await cameraControl.setZoomRatio(zoom); } + /// Gets a list of video stabilization modes that are supported for the + /// selected camera. + @override + Future> getSupportedVideoStabilizationModes( + int cameraId) async { + return (await _getSupportedVideoStabilizationModeMap(cameraId)).keys; + } + + /// Set the video stabilization mode for the selected camera. + /// + /// Throws a [ArgumentError] when an unsupported [mode] is + /// supplied. + @override + Future setVideoStabilizationMode( + int cameraId, VideoStabilizationMode mode) async { + final Map availableModes = + await _getSupportedVideoStabilizationModeMap(cameraId); + + final int? controlMode = availableModes[mode]; + if (controlMode == null) { + throw ArgumentError('Unavailable video stabilization mode.', 'mode'); + } + + final CaptureRequestOptions captureRequestOptions = proxy + .createCaptureRequestOptions(<( + CaptureRequestKeySupportedType, + Object? + )>[ + ( + CaptureRequestKeySupportedType.controlVideoStabilizationMode, + controlMode + ) + ]); + + final Camera2CameraControl camera2Control = + proxy.getCamera2CameraControl(cameraControl); + await camera2Control.addCaptureRequestOptions(captureRequestOptions); + } + + /// Gets a map of video stabilization control modes that are supported for the + /// selected camera, indexed by the respective [VideoStabilizationMode]. + Future> + _getSupportedVideoStabilizationModeMap(int cameraId) async { + final CameraInfo? camInfo = cameraInfo; + if (camInfo == null) { + return {}; + } + final Camera2CameraInfo cam2Info = + await proxy.getCamera2CameraInfo(camInfo); + + final List controlModes = + await cam2Info.getAvailableVideoStabilizationModes(); + + final Map modes = + { + for (final int controlMode in controlModes) + if (controlMode == CameraMetadata.controlVideoStabilizationModeOff) + VideoStabilizationMode.off: controlMode + else if (controlMode == CameraMetadata.controlVideoStabilizationModeOn) + VideoStabilizationMode.level1: controlMode + }; + + return modes; + } + /// The ui orientation changed. @override Stream onDeviceOrientationChanged() { diff --git a/packages/camera/camera_android_camerax/lib/src/camera2_camera_info.dart b/packages/camera/camera_android_camerax/lib/src/camera2_camera_info.dart index 88b44238f3b..b1b90b44046 100644 --- a/packages/camera/camera_android_camerax/lib/src/camera2_camera_info.dart +++ b/packages/camera/camera_android_camerax/lib/src/camera2_camera_info.dart @@ -48,6 +48,22 @@ class Camera2CameraInfo extends JavaObject { Future getSupportedHardwareLevel() => _api.getSupportedHardwareLevelFromInstance(this); + /// Retrieves de list of available common platform video stabilization modes + /// the device to which this instance pertains to supports. + /// + /// Works by retrieving the value of `CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES` + /// and mapping each of those values to the corresponding common platform + /// video stabilization mode. + /// + /// See https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES + /// for more information. + Future> getAvailableVideoStabilizationModes() async { + final List modes = + await _api.getAvailableVideoStabilizationModesFromInstance(this); + + return modes; + } + /// Gets the camera ID. /// /// The ID may change based on the internal configuration of the camera to which @@ -91,6 +107,15 @@ class _Camera2CameraInfoHostApiImpl extends Camera2CameraInfoHostApi { return getSupportedHardwareLevel(identifier!); } + Future> getAvailableVideoStabilizationModesFromInstance( + Camera2CameraInfo instance) async { + final int? identifier = instanceManager.getIdentifier(instance); + final List modes = + await getAvailableVideoStabilizationModes(identifier!); + + return modes.where((int? e) => e != null).map((int? e) => e!).toList(); + } + Future getCameraIdFromInstance(Camera2CameraInfo instance) { final int? identifier = instanceManager.getIdentifier(instance); return getCameraId(identifier!); diff --git a/packages/camera/camera_android_camerax/lib/src/camera_metadata.dart b/packages/camera/camera_android_camerax/lib/src/camera_metadata.dart index 65098b747c6..36f3f0dc40a 100644 --- a/packages/camera/camera_android_camerax/lib/src/camera_metadata.dart +++ b/packages/camera/camera_android_camerax/lib/src/camera_metadata.dart @@ -34,9 +34,24 @@ class CameraMetadata { /// See https://developer.android.com/reference/android/hardware/camera2/CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_3. static const int infoSupportedHardwareLevel3 = 3; - /// Constant taht specifies a camera device is backed by an external camera + /// Constant that specifies a camera device is backed by an external camera /// connected to this Android device. /// /// See https://developer.android.com/reference/android/hardware/camera2/CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL. static const int infoSupportedHardwareLevelExternal = 4; + + /// Constant that specifies that video stabilization is disabled. + /// + /// See https://developer.android.com/reference/android/hardware/camera2/CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_OFF. + static const int controlVideoStabilizationModeOff = 0; + + /// Constant that specifies that video stabilization is enabled. + /// + /// See https://developer.android.com/reference/android/hardware/camera2/CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_ON. + static const int controlVideoStabilizationModeOn = 1; + + /// Constant that specifies that video stabilization mode is preview stabilization, + /// + /// See https://developer.android.com/reference/android/hardware/camera2/CameraMetadata#CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION. + static const int controlVideoStabilizationModePreviewStabilization = 2; } diff --git a/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart b/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart index e830a288ce9..6c64f2ed53c 100644 --- a/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart +++ b/packages/camera/camera_android_camerax/lib/src/camerax_library.g.dart @@ -96,6 +96,7 @@ enum VideoRecordEvent { /// interoperability with Camera2. enum CaptureRequestKeySupportedType { controlAeLock, + controlVideoStabilizationMode, } class ResolutionInfo { @@ -3657,6 +3658,35 @@ class Camera2CameraInfoHostApi { return (replyList[0] as int?)!; } } + + Future> getAvailableVideoStabilizationModes( + int arg_identifier) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.Camera2CameraInfoHostApi.getAvailableVideoStabilizationModes', + codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_identifier]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as List?)!.cast(); + } + } } abstract class Camera2CameraInfoFlutterApi { diff --git a/packages/camera/camera_android_camerax/lib/src/capture_request_options.dart b/packages/camera/camera_android_camerax/lib/src/capture_request_options.dart index 8c3de00845e..c5069a116a9 100644 --- a/packages/camera/camera_android_camerax/lib/src/capture_request_options.dart +++ b/packages/camera/camera_android_camerax/lib/src/capture_request_options.dart @@ -112,6 +112,12 @@ class _CaptureRequestOptionsHostApiImpl extends CaptureRequestOptionsHostApi { throw ArgumentError( 'A controlAeLock value must be specified as a bool, but a $valueRuntimeType was specified.'); } + case CaptureRequestKeySupportedType.controlVideoStabilizationMode: + if (valueRuntimeType != int) { + throw ArgumentError( + 'A controlVideoStabilizationMode value must be specified as an int, but a $valueRuntimeType was specified.'); + } + // This ignore statement is safe beause this error will be useful when // a new CaptureRequestKeySupportedType is being added, but the logic in // this method has not yet been updated. diff --git a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart index a6e4eded23a..d293fabb6ff 100644 --- a/packages/camera/camera_android_camerax/pigeons/camerax_library.dart +++ b/packages/camera/camera_android_camerax/pigeons/camerax_library.dart @@ -172,6 +172,7 @@ class MeteringPointInfo { /// interoperability with Camera2. enum CaptureRequestKeySupportedType { controlAeLock, + controlVideoStabilizationMode, } @HostApi(dartHostTestHandler: 'TestInstanceManagerHostApi') @@ -568,6 +569,8 @@ abstract class Camera2CameraInfoHostApi { String getCameraId(int identifier); int getSensorOrientation(int identifier); + + List getAvailableVideoStabilizationModes(int identifier); } @FlutterApi() diff --git a/packages/camera/camera_android_camerax/pubspec.yaml b/packages/camera/camera_android_camerax/pubspec.yaml index c611b2f69b4..fa49c3de16d 100644 --- a/packages/camera/camera_android_camerax/pubspec.yaml +++ b/packages/camera/camera_android_camerax/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_android_camerax description: Android implementation of the camera plugin using the CameraX library. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android_camerax issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.6.14+1 +version: 0.7.0 environment: sdk: ^3.6.0 @@ -19,7 +19,7 @@ flutter: dependencies: async: ^2.5.0 - camera_platform_interface: ^2.9.0 + camera_platform_interface: ^2.10.0 flutter: sdk: flutter meta: ^1.7.0 @@ -35,3 +35,8 @@ dev_dependencies: topics: - camera + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {camera_platform_interface: {path: ../../camera/camera_platform_interface}} diff --git a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart index 2e4a5c83af7..49e84fa341f 100644 --- a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart +++ b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.dart @@ -2158,6 +2158,222 @@ void main() { verify(mockCameraControl.setZoomRatio(zoomRatio)); }); + test('setVideoStabilizationMode sets mode expected', () async { + final AndroidCameraCameraX camera = AndroidCameraCameraX(); + const int cameraId = 78; + + final MockCameraInfo mockCameraInfo = MockCameraInfo(); + final MockCamera2CameraInfo mockCamera2CameraInfo = MockCamera2CameraInfo(); + + final MockCameraControl mockCameraControl = MockCameraControl(); + final MockCamera2CameraControl mockCamera2CameraControl = + MockCamera2CameraControl(); + + // Set directly for test versus calling createCamera. + camera.camera = MockCamera(); + camera.cameraControl = mockCameraControl; + camera.cameraInfo = mockCameraInfo; + + when(mockCamera2CameraInfo.getAvailableVideoStabilizationModes()) + .thenAnswer( + (_) async { + return [0]; + }, + ); + + camera.proxy = CameraXProxy( + getCamera2CameraControl: (CameraControl cameraControl) => + cameraControl == mockCameraControl + ? mockCamera2CameraControl + : Camera2CameraControl.detached(cameraControl: cameraControl), + getCamera2CameraInfo: (CameraInfo cameraInfo) async { + return cameraInfo == mockCameraInfo + ? mockCamera2CameraInfo + : Camera2CameraInfo.detached(); + }, + createCaptureRequestOptions: + (List<(CaptureRequestKeySupportedType, Object?)> options) => + CaptureRequestOptions.detached(requestedOptions: options), + ); + + // Test off. + await camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.off); + + final VerificationResult verificationResult = + verify(mockCamera2CameraControl.addCaptureRequestOptions(captureAny)); + final CaptureRequestOptions capturedCaptureRequestOptions = + verificationResult.captured.single as CaptureRequestOptions; + final List<(CaptureRequestKeySupportedType, Object?)> requestedOptions = + capturedCaptureRequestOptions.requestedOptions; + expect(requestedOptions.length, equals(1)); + expect(requestedOptions.first.$1, + equals(CaptureRequestKeySupportedType.controlVideoStabilizationMode)); + expect(requestedOptions.first.$2, equals(0)); + }); + + test('setVideoStabilizationMode throws ArgumentError when mode not available', + () async { + final AndroidCameraCameraX camera = AndroidCameraCameraX(); + const int cameraId = 78; + + final MockCameraInfo mockCameraInfo = MockCameraInfo(); + final MockCamera2CameraInfo mockCamera2CameraInfo = MockCamera2CameraInfo(); + + final MockCameraControl mockCameraControl = MockCameraControl(); + + // Set directly for test versus calling createCamera. + camera.camera = MockCamera(); + camera.cameraInfo = mockCameraInfo; + + when(mockCamera2CameraInfo.getAvailableVideoStabilizationModes()) + .thenAnswer( + (_) async { + return [0]; + }, + ); + + camera.cameraControl = mockCameraControl; + + camera.proxy = CameraXProxy( + getCamera2CameraInfo: (CameraInfo cameraInfo) async { + return cameraInfo == mockCameraInfo + ? mockCamera2CameraInfo + : Camera2CameraInfo.detached(); + }, + ); + + expect( + () => camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.level2), + throwsA(isA() + .having((ArgumentError e) => e.name, 'name', 'mode'))); + }); + + test('setVideoStabilizationMode throws ArgumentError when mode not mapped', + () async { + final AndroidCameraCameraX camera = AndroidCameraCameraX(); + const int cameraId = 78; + + final MockCameraInfo mockCameraInfo = MockCameraInfo(); + final MockCamera2CameraInfo mockCamera2CameraInfo = MockCamera2CameraInfo(); + + final MockCameraControl mockCameraControl = MockCameraControl(); + + // Set directly for test versus calling createCamera. + camera.camera = MockCamera(); + camera.cameraInfo = mockCameraInfo; + + when(mockCamera2CameraInfo.getAvailableVideoStabilizationModes()) + .thenAnswer( + (_) async { + return [0, 1, 2]; + }, + ); + + camera.cameraControl = mockCameraControl; + + camera.proxy = CameraXProxy( + getCamera2CameraInfo: (CameraInfo cameraInfo) async { + return cameraInfo == mockCameraInfo + ? mockCamera2CameraInfo + : Camera2CameraInfo.detached(); + }, + ); + + expect( + () => camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.level2), + throwsA(isA() + .having((ArgumentError e) => e.name, 'name', 'mode'))); + expect( + () => camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.level3), + throwsA(isA() + .having((ArgumentError e) => e.name, 'name', 'mode'))); + }); + + test('getVideoStabilizationMode returns no available mode', () async { + final AndroidCameraCameraX camera = AndroidCameraCameraX(); + const int cameraId = 78; + + final MockCameraInfo mockCameraInfo = MockCameraInfo(); + final MockCamera2CameraInfo mockCamera2CameraInfo = MockCamera2CameraInfo(); + + final MockCameraControl mockCameraControl = MockCameraControl(); + + // Set directly for test versus calling createCamera. + camera.camera = MockCamera(); + camera.cameraInfo = mockCameraInfo; + + when(mockCamera2CameraInfo.getAvailableVideoStabilizationModes()) + .thenAnswer( + (_) async { + return []; + }, + ); + + camera.cameraControl = mockCameraControl; + + // Tell plugin to create detached Camera2CameraControl and + // CaptureRequestOptions instances for testing. + camera.proxy = CameraXProxy( + getCamera2CameraInfo: (CameraInfo cameraInfo) async { + return cameraInfo == mockCameraInfo + ? mockCamera2CameraInfo + : Camera2CameraInfo.detached(); + }, + ); + + final Iterable modes = + await camera.getSupportedVideoStabilizationModes(cameraId); + + expect(modes, isEmpty); + }); + + test('getVideoStabilizationMode returns all available modes', () async { + final AndroidCameraCameraX camera = AndroidCameraCameraX(); + const int cameraId = 78; + + final MockCameraInfo mockCameraInfo = MockCameraInfo(); + final MockCamera2CameraInfo mockCamera2CameraInfo = MockCamera2CameraInfo(); + + final MockCameraControl mockCameraControl = MockCameraControl(); + + // Set directly for test versus calling createCamera. + camera.camera = MockCamera(); + camera.cameraInfo = mockCameraInfo; + + when(mockCamera2CameraInfo.getAvailableVideoStabilizationModes()) + .thenAnswer( + (_) async { + return [0, 1, 2]; + }, + ); + + camera.cameraControl = mockCameraControl; + + // Tell plugin to create detached Camera2CameraControl and + // CaptureRequestOptions instances for testing. + camera.proxy = CameraXProxy( + getCamera2CameraInfo: (CameraInfo cameraInfo) async { + return cameraInfo == mockCameraInfo + ? mockCamera2CameraInfo + : Camera2CameraInfo.detached(); + }, + ); + + final Iterable modes = + await camera.getSupportedVideoStabilizationModes(cameraId); + + expect( + modes, + orderedEquals([ + VideoStabilizationMode.off, + VideoStabilizationMode.level1, + ])); + }); + test('Should report support for image streaming', () async { final AndroidCameraCameraX camera = AndroidCameraCameraX(); expect(camera.supportsImageStreaming(), true); diff --git a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart index fc838a461bb..d3eccd71028 100644 --- a/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart +++ b/packages/camera/camera_android_camerax/test/android_camera_camerax_test.mocks.dart @@ -707,6 +707,17 @@ class MockCamera2CameraInfo extends _i1.Mock implements _i26.Camera2CameraInfo { returnValueForMissingStub: _i17.Future.value(0), ) as _i17.Future); + @override + _i17.Future> getAvailableVideoStabilizationModes() => + (super.noSuchMethod( + Invocation.method( + #getAvailableVideoStabilizationModes, + [], + ), + returnValue: _i17.Future>.value([]), + returnValueForMissingStub: _i17.Future>.value([]), + ) as _i17.Future>); + @override _i17.Future getCameraId() => (super.noSuchMethod( Invocation.method( diff --git a/packages/camera/camera_android_camerax/test/camera2_camera_info_test.dart b/packages/camera/camera_android_camerax/test/camera2_camera_info_test.dart index 0766eee37e8..0d5c0224a81 100644 --- a/packages/camera/camera_android_camerax/test/camera2_camera_info_test.dart +++ b/packages/camera/camera_android_camerax/test/camera2_camera_info_test.dart @@ -110,6 +110,76 @@ void main() { verify(mockApi.getSupportedHardwareLevel(camera2CameraInfoId)); }); + test( + 'getAvailableVideoStabilizationModes makes call to retrieve no available video stabilization modes', + () async { + // Arrange + final MockTestCamera2CameraInfoHostApi mockApi = + MockTestCamera2CameraInfoHostApi(); + TestCamera2CameraInfoHostApi.setup(mockApi); + + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + final Camera2CameraInfo camera2CameraInfo = Camera2CameraInfo.detached( + instanceManager: instanceManager, + ); + const int camera2CameraInfoId = 9; + + instanceManager.addHostCreatedInstance( + camera2CameraInfo, + camera2CameraInfoId, + onCopy: (_) => Camera2CameraInfo.detached(), + ); + + const List expectedModes = []; + when(mockApi.getAvailableVideoStabilizationModes(camera2CameraInfoId)) + .thenReturn(expectedModes); + + // Act + final List returnedModes = + await camera2CameraInfo.getAvailableVideoStabilizationModes(); + + // Assert + expect(returnedModes, equals(expectedModes)); + verify(mockApi.getAvailableVideoStabilizationModes(camera2CameraInfoId)); + }); + + test( + 'getAvailableVideoStabilizationModes makes call to retrieve all available video stabilization modes', + () async { + // Arrange + final MockTestCamera2CameraInfoHostApi mockApi = + MockTestCamera2CameraInfoHostApi(); + TestCamera2CameraInfoHostApi.setup(mockApi); + + final InstanceManager instanceManager = InstanceManager( + onWeakReferenceRemoved: (_) {}, + ); + final Camera2CameraInfo camera2CameraInfo = Camera2CameraInfo.detached( + instanceManager: instanceManager, + ); + const int camera2CameraInfoId = 9; + + instanceManager.addHostCreatedInstance( + camera2CameraInfo, + camera2CameraInfoId, + onCopy: (_) => Camera2CameraInfo.detached(), + ); + + const List expectedModes = [0, 1, 2]; + when(mockApi.getAvailableVideoStabilizationModes(camera2CameraInfoId)) + .thenReturn(expectedModes); + + // Act + final List returnedModes = + await camera2CameraInfo.getAvailableVideoStabilizationModes(); + + // Assert + expect(returnedModes, equals(expectedModes)); + verify(mockApi.getAvailableVideoStabilizationModes(camera2CameraInfoId)); + }); + test('getCameraId makes call to retrieve camera ID', () async { final MockTestCamera2CameraInfoHostApi mockApi = MockTestCamera2CameraInfoHostApi(); diff --git a/packages/camera/camera_android_camerax/test/camera2_camera_info_test.mocks.dart b/packages/camera/camera_android_camerax/test/camera2_camera_info_test.mocks.dart index 88b219f28cf..97a5140d0f9 100644 --- a/packages/camera/camera_android_camerax/test/camera2_camera_info_test.mocks.dart +++ b/packages/camera/camera_android_camerax/test/camera2_camera_info_test.mocks.dart @@ -99,6 +99,16 @@ class MockTestCamera2CameraInfoHostApi extends _i1.Mock ), returnValue: 0, ) as int); + + @override + List getAvailableVideoStabilizationModes(int? identifier) => + (super.noSuchMethod( + Invocation.method( + #getAvailableVideoStabilizationModes, + [identifier], + ), + returnValue: [], + ) as List); } /// A class which mocks [TestInstanceManagerHostApi]. diff --git a/packages/camera/camera_android_camerax/test/capture_request_options_test.dart b/packages/camera/camera_android_camerax/test/capture_request_options_test.dart index c048aae2297..478e7fe5cbf 100644 --- a/packages/camera/camera_android_camerax/test/capture_request_options_test.dart +++ b/packages/camera/camera_android_camerax/test/capture_request_options_test.dart @@ -101,10 +101,11 @@ void main() { ); final List<(CaptureRequestKeySupportedType key, Object? value)> - supportedOptionsForTesting = <( - CaptureRequestKeySupportedType key, - Object? value - )>[(CaptureRequestKeySupportedType.controlAeLock, false)]; + supportedOptionsForTesting = + <(CaptureRequestKeySupportedType key, Object? value)>[ + (CaptureRequestKeySupportedType.controlAeLock, false), + (CaptureRequestKeySupportedType.controlVideoStabilizationMode, 0), + ]; final CaptureRequestOptions instance = CaptureRequestOptions( requestedOptions: supportedOptionsForTesting, @@ -129,6 +130,10 @@ void main() { case CaptureRequestKeySupportedType.controlAeLock: expect(captureRequestOptions[optionKey.index], equals(optionValue! as bool)); + + case CaptureRequestKeySupportedType.controlVideoStabilizationMode: + expect(captureRequestOptions[optionKey.index], + equals(optionValue! as int)); // This ignore statement is safe beause this will test when // a new CaptureRequestKeySupportedType is being added, but the logic in // in the CaptureRequestOptions class has not yet been updated. diff --git a/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart b/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart index 1007d975ebc..82398d21f67 100644 --- a/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart +++ b/packages/camera/camera_android_camerax/test/test_camerax_library.g.dart @@ -2487,6 +2487,8 @@ abstract class TestCamera2CameraInfoHostApi { int getSensorOrientation(int identifier); + List getAvailableVideoStabilizationModes(int identifier); + static void setup(TestCamera2CameraInfoHostApi? api, {BinaryMessenger? binaryMessenger}) { { @@ -2579,5 +2581,29 @@ abstract class TestCamera2CameraInfoHostApi { }); } } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.Camera2CameraInfoHostApi.getAvailableVideoStabilizationModes', + codec, + binaryMessenger: binaryMessenger); + if (api == null) { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, null); + } else { + _testBinaryMessengerBinding!.defaultBinaryMessenger + .setMockDecodedMessageHandler(channel, + (Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.Camera2CameraInfoHostApi.getAvailableVideoStabilizationModes was null.'); + final List args = (message as List?)!; + final int? arg_identifier = (args[0] as int?); + assert(arg_identifier != null, + 'Argument for dev.flutter.pigeon.Camera2CameraInfoHostApi.getAvailableVideoStabilizationModes was null, expected non-null int.'); + final List output = + api.getAvailableVideoStabilizationModes(arg_identifier!); + return [output]; + }); + } + } } } diff --git a/packages/camera/camera_avfoundation/AUTHORS b/packages/camera/camera_avfoundation/AUTHORS index 493a0b4ef9c..1d9825e2e03 100644 --- a/packages/camera/camera_avfoundation/AUTHORS +++ b/packages/camera/camera_avfoundation/AUTHORS @@ -64,3 +64,4 @@ Aleksandr Yurkovskiy Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> +Rui Craveiro \ No newline at end of file diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 0890c7f7314..08ceeebd7d5 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.0 + +* Adds video stabilization. + ## 0.9.18+9 * Backfills unit tests for `CameraPlugin` class. diff --git a/packages/camera/camera_avfoundation/example/pubspec.yaml b/packages/camera/camera_avfoundation/example/pubspec.yaml index 9f82d7faf62..1e04dcc8818 100644 --- a/packages/camera/camera_avfoundation/example/pubspec.yaml +++ b/packages/camera/camera_avfoundation/example/pubspec.yaml @@ -29,3 +29,8 @@ dev_dependencies: flutter: uses-material-design: true + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {camera_avfoundation: {path: ../../../camera/camera_avfoundation}, camera_platform_interface: {path: ../../../camera/camera_platform_interface}} diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m index b9e1ef1850c..a4f48f050df 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraPlugin.m @@ -452,6 +452,25 @@ - (void)disposeCamera:(NSInteger)cameraId }); } +- (void)setVideoStabilizationMode:(FCPPlatformVideoStabilizationMode)mode + completion:(nonnull void (^)(FlutterError *_Nullable))completion { + __weak typeof(self) weakSelf = self; + dispatch_async(self.captureSessionQueue, ^{ + [weakSelf.camera setVideoStabilizationMode:mode withCompletion:completion]; + }); +} + +- (void)isVideoStabilizationModeSupported:(FCPPlatformVideoStabilizationMode)mode + completion:(nonnull void (^)(NSNumber *_Nullable, + FlutterError *_Nullable))completion { + __weak typeof(self) weakSelf = self; + + dispatch_async(self.captureSessionQueue, ^{ + BOOL isSupported = [weakSelf.camera isVideoStabilizationModeSupported:mode]; + completion(@(isSupported), nil); + }); +} + #pragma mark Private // This must be called on captureSessionQueue. It is extracted from diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraProperties.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraProperties.m index 8ef61b43fc8..9421f35b637 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraProperties.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/CameraProperties.m @@ -55,3 +55,24 @@ OSType FCPGetPixelFormatForPigeonFormat(FCPPlatformImageFormatGroup imageFormat) return kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; } } + +AVCaptureVideoStabilizationMode getAvCaptureVideoStabilizationMode( + FCPPlatformVideoStabilizationMode videoStabilizationMode) { + switch (videoStabilizationMode) { + case FCPPlatformVideoStabilizationModeOff: + return AVCaptureVideoStabilizationModeOff; + case FCPPlatformVideoStabilizationModeStandard: + return AVCaptureVideoStabilizationModeStandard; + case FCPPlatformVideoStabilizationModeCinematic: + return AVCaptureVideoStabilizationModeCinematic; + case FCPPlatformVideoStabilizationModeCinematicExtended: + if (@available(iOS 13.0, *)) { + return AVCaptureVideoStabilizationModeCinematicExtended; + } else { + return AVCaptureVideoStabilizationModeCinematic; + } + + default: + return AVCaptureVideoStabilizationModeOff; + } +} diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m index dc9b45836d8..d8a0c38233f 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/FLTCam.m @@ -1240,6 +1240,29 @@ - (void)setZoomLevel:(CGFloat)zoom withCompletion:(void (^)(FlutterError *_Nulla completion(nil); } +- (void)setVideoStabilizationMode:(FCPPlatformVideoStabilizationMode)mode + withCompletion:(void (^)(FlutterError *_Nullable))completion { + AVCaptureVideoStabilizationMode stabilizationMode = getAvCaptureVideoStabilizationMode(mode); + + if (![_captureDevice.activeFormat isVideoStabilizationModeSupported:stabilizationMode]) { + completion([FlutterError errorWithCode:@"VIDEO_STABILIIZATION_ERROR" + message:@"Unavailable video stabilization mode." + details:nil]); + return; + } + + AVCaptureConnection *connection = [_captureVideoOutput connectionWithMediaType:AVMediaTypeVideo]; + + connection.preferredVideoStabilizationMode = stabilizationMode; + + completion(nil); +} + +- (BOOL)isVideoStabilizationModeSupported:(FCPPlatformVideoStabilizationMode)mode { + AVCaptureVideoStabilizationMode stabilizationMode = getAvCaptureVideoStabilizationMode(mode); + return [_captureDevice.activeFormat isVideoStabilizationModeSupported:stabilizationMode]; +} + - (CGFloat)minimumAvailableZoomFactor { return _captureDevice.minAvailableVideoZoomFactor; } diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraProperties.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraProperties.h index a46e4f04b65..27c582b6d69 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraProperties.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/CameraProperties.h @@ -25,4 +25,6 @@ extern FCPPlatformDeviceOrientation FCPGetPigeonDeviceOrientationForOrientation( /// Gets VideoFormat from its Pigeon representation. extern OSType FCPGetPixelFormatForPigeonFormat(FCPPlatformImageFormatGroup imageFormat); +extern AVCaptureVideoStabilizationMode getAvCaptureVideoStabilizationMode( + FCPPlatformVideoStabilizationMode videoStabilizationMode); NS_ASSUME_NONNULL_END diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h index be3af446e7c..47d4ca92e9f 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/FLTCam.h @@ -109,6 +109,10 @@ NS_ASSUME_NONNULL_BEGIN - (void)startImageStreamWithMessenger:(NSObject *)messenger; - (void)stopImageStream; - (void)setZoomLevel:(CGFloat)zoom withCompletion:(void (^)(FlutterError *_Nullable))completion; +- (void)setVideoStabilizationMode:(FCPPlatformVideoStabilizationMode)mode + withCompletion:(void (^)(FlutterError *_Nullable))completion; +- (bool)isVideoStabilizationModeSupported:(FCPPlatformVideoStabilizationMode)mode; +- (void)setUpCaptureSessionForAudio; - (void)setUpCaptureSessionForAudioIfNeeded; @end diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/messages.g.h b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/messages.g.h index 2f1d8646afa..ed97ffa7960 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/messages.g.h +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/include/camera_avfoundation/messages.g.h @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v22.4.2), do not edit directly. +// Autogenerated from Pigeon (v22.7.2), do not edit directly. // See also: https://pub.dev/packages/pigeon #import @@ -114,6 +114,19 @@ typedef NS_ENUM(NSUInteger, FCPPlatformResolutionPreset) { - (instancetype)initWithValue:(FCPPlatformResolutionPreset)value; @end +typedef NS_ENUM(NSUInteger, FCPPlatformVideoStabilizationMode) { + FCPPlatformVideoStabilizationModeOff = 0, + FCPPlatformVideoStabilizationModeStandard = 1, + FCPPlatformVideoStabilizationModeCinematic = 2, + FCPPlatformVideoStabilizationModeCinematicExtended = 3, +}; + +/// Wrapper for FCPPlatformVideoStabilizationMode to allow for nullability. +@interface FCPPlatformVideoStabilizationModeBox : NSObject +@property(nonatomic, assign) FCPPlatformVideoStabilizationMode value; +- (instancetype)initWithValue:(FCPPlatformVideoStabilizationMode)value; +@end + @class FCPPlatformCameraDescription; @class FCPPlatformCameraState; @class FCPPlatformMediaSettings; @@ -124,9 +137,9 @@ typedef NS_ENUM(NSUInteger, FCPPlatformResolutionPreset) { /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; + (instancetype)makeWithName:(NSString *)name - lensDirection:(FCPPlatformCameraLensDirection)lensDirection; + lensDirection:(FCPPlatformCameraLensDirection)lensDirection; /// The name of the camera device. -@property(nonatomic, copy) NSString *name; +@property(nonatomic, copy) NSString * name; /// The direction the camera is facing. @property(nonatomic, assign) FCPPlatformCameraLensDirection lensDirection; @end @@ -135,51 +148,53 @@ typedef NS_ENUM(NSUInteger, FCPPlatformResolutionPreset) { /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; + (instancetype)makeWithPreviewSize:(FCPPlatformSize *)previewSize - exposureMode:(FCPPlatformExposureMode)exposureMode - focusMode:(FCPPlatformFocusMode)focusMode - exposurePointSupported:(BOOL)exposurePointSupported - focusPointSupported:(BOOL)focusPointSupported; + exposureMode:(FCPPlatformExposureMode)exposureMode + focusMode:(FCPPlatformFocusMode)focusMode + exposurePointSupported:(BOOL )exposurePointSupported + focusPointSupported:(BOOL )focusPointSupported; /// The size of the preview, in pixels. -@property(nonatomic, strong) FCPPlatformSize *previewSize; +@property(nonatomic, strong) FCPPlatformSize * previewSize; /// The default exposure mode @property(nonatomic, assign) FCPPlatformExposureMode exposureMode; /// The default focus mode @property(nonatomic, assign) FCPPlatformFocusMode focusMode; /// Whether setting exposure points is supported. -@property(nonatomic, assign) BOOL exposurePointSupported; +@property(nonatomic, assign) BOOL exposurePointSupported; /// Whether setting focus points is supported. -@property(nonatomic, assign) BOOL focusPointSupported; +@property(nonatomic, assign) BOOL focusPointSupported; @end @interface FCPPlatformMediaSettings : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; + (instancetype)makeWithResolutionPreset:(FCPPlatformResolutionPreset)resolutionPreset - framesPerSecond:(nullable NSNumber *)framesPerSecond - videoBitrate:(nullable NSNumber *)videoBitrate - audioBitrate:(nullable NSNumber *)audioBitrate - enableAudio:(BOOL)enableAudio; + framesPerSecond:(nullable NSNumber *)framesPerSecond + videoBitrate:(nullable NSNumber *)videoBitrate + audioBitrate:(nullable NSNumber *)audioBitrate + enableAudio:(BOOL )enableAudio; @property(nonatomic, assign) FCPPlatformResolutionPreset resolutionPreset; -@property(nonatomic, strong, nullable) NSNumber *framesPerSecond; -@property(nonatomic, strong, nullable) NSNumber *videoBitrate; -@property(nonatomic, strong, nullable) NSNumber *audioBitrate; -@property(nonatomic, assign) BOOL enableAudio; +@property(nonatomic, strong, nullable) NSNumber * framesPerSecond; +@property(nonatomic, strong, nullable) NSNumber * videoBitrate; +@property(nonatomic, strong, nullable) NSNumber * audioBitrate; +@property(nonatomic, assign) BOOL enableAudio; @end @interface FCPPlatformPoint : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithX:(double)x y:(double)y; -@property(nonatomic, assign) double x; -@property(nonatomic, assign) double y; ++ (instancetype)makeWithX:(double )x + y:(double )y; +@property(nonatomic, assign) double x; +@property(nonatomic, assign) double y; @end @interface FCPPlatformSize : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. - (instancetype)init NS_UNAVAILABLE; -+ (instancetype)makeWithWidth:(double)width height:(double)height; -@property(nonatomic, assign) double width; -@property(nonatomic, assign) double height; ++ (instancetype)makeWithWidth:(double )width + height:(double )height; +@property(nonatomic, assign) double width; +@property(nonatomic, assign) double height; @end /// The codec used by all APIs. @@ -187,16 +202,11 @@ NSObject *FCPGetMessagesCodec(void); @protocol FCPCameraApi /// Returns the list of available cameras. -- (void)availableCamerasWithCompletion:(void (^)(NSArray *_Nullable, - FlutterError *_Nullable))completion; +- (void)availableCamerasWithCompletion:(void (^)(NSArray *_Nullable, FlutterError *_Nullable))completion; /// Create a new camera with the given settings, and returns its ID. -- (void)createCameraWithName:(NSString *)cameraName - settings:(FCPPlatformMediaSettings *)settings - completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; +- (void)createCameraWithName:(NSString *)cameraName settings:(FCPPlatformMediaSettings *)settings completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; /// Initializes the camera with the given ID. -- (void)initializeCamera:(NSInteger)cameraId - withImageFormat:(FCPPlatformImageFormatGroup)imageFormat - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)initializeCamera:(NSInteger)cameraId withImageFormat:(FCPPlatformImageFormatGroup)imageFormat completion:(void (^)(FlutterError *_Nullable))completion; /// Begins streaming frames from the camera. - (void)startImageStreamWithCompletion:(void (^)(FlutterError *_Nullable))completion; /// Stops streaming frames from the camera. @@ -210,39 +220,32 @@ NSObject *FCPGetMessagesCodec(void); /// and any associated resources can be cleaned up. - (void)disposeCamera:(NSInteger)cameraId completion:(void (^)(FlutterError *_Nullable))completion; /// Locks the camera capture to the current device orientation. -- (void)lockCaptureOrientation:(FCPPlatformDeviceOrientation)orientation - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)lockCaptureOrientation:(FCPPlatformDeviceOrientation)orientation completion:(void (^)(FlutterError *_Nullable))completion; /// Unlocks camera capture orientation, allowing it to automatically adapt to /// device orientation. - (void)unlockCaptureOrientationWithCompletion:(void (^)(FlutterError *_Nullable))completion; /// Takes a picture with the current settings, and returns the path to the /// resulting file. -- (void)takePictureWithCompletion:(void (^)(NSString *_Nullable, - FlutterError *_Nullable))completion; +- (void)takePictureWithCompletion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; /// Does any preprocessing necessary before beginning to record video. - (void)prepareForVideoRecordingWithCompletion:(void (^)(FlutterError *_Nullable))completion; /// Begins recording video, optionally enabling streaming to Dart at the same /// time. -- (void)startVideoRecordingWithStreaming:(BOOL)enableStream - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)startVideoRecordingWithStreaming:(BOOL)enableStream completion:(void (^)(FlutterError *_Nullable))completion; /// Stops recording video, and results the path to the resulting file. -- (void)stopVideoRecordingWithCompletion:(void (^)(NSString *_Nullable, - FlutterError *_Nullable))completion; +- (void)stopVideoRecordingWithCompletion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; /// Pauses video recording. - (void)pauseVideoRecordingWithCompletion:(void (^)(FlutterError *_Nullable))completion; /// Resumes a previously paused video recording. - (void)resumeVideoRecordingWithCompletion:(void (^)(FlutterError *_Nullable))completion; /// Switches the camera to the given flash mode. -- (void)setFlashMode:(FCPPlatformFlashMode)mode - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)setFlashMode:(FCPPlatformFlashMode)mode completion:(void (^)(FlutterError *_Nullable))completion; /// Switches the camera to the given exposure mode. -- (void)setExposureMode:(FCPPlatformExposureMode)mode - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)setExposureMode:(FCPPlatformExposureMode)mode completion:(void (^)(FlutterError *_Nullable))completion; /// Anchors auto-exposure to the given point in (0,1) coordinate space. /// /// A null value resets to the default exposure point. -- (void)setExposurePoint:(nullable FCPPlatformPoint *)point - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)setExposurePoint:(nullable FCPPlatformPoint *)point completion:(void (^)(FlutterError *_Nullable))completion; /// Returns the minimum exposure offset supported by the camera. - (void)getMinimumExposureOffset:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; /// Returns the maximum exposure offset supported by the camera. @@ -250,60 +253,55 @@ NSObject *FCPGetMessagesCodec(void); /// Sets the exposure offset manually to the given value. - (void)setExposureOffset:(double)offset completion:(void (^)(FlutterError *_Nullable))completion; /// Switches the camera to the given focus mode. -- (void)setFocusMode:(FCPPlatformFocusMode)mode - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)setFocusMode:(FCPPlatformFocusMode)mode completion:(void (^)(FlutterError *_Nullable))completion; /// Anchors auto-focus to the given point in (0,1) coordinate space. /// /// A null value resets to the default focus point. -- (void)setFocusPoint:(nullable FCPPlatformPoint *)point - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)setFocusPoint:(nullable FCPPlatformPoint *)point completion:(void (^)(FlutterError *_Nullable))completion; /// Returns the minimum zoom level supported by the camera. - (void)getMinimumZoomLevel:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; /// Returns the maximum zoom level supported by the camera. - (void)getMaximumZoomLevel:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; /// Sets the zoom factor. - (void)setZoomLevel:(double)zoom completion:(void (^)(FlutterError *_Nullable))completion; +/// Sets the video stabilization mode. +- (void)setVideoStabilizationMode:(FCPPlatformVideoStabilizationMode)mode completion:(void (^)(FlutterError *_Nullable))completion; +/// Sets the video stabilization mode. +- (void)isVideoStabilizationModeSupported:(FCPPlatformVideoStabilizationMode)mode completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion; /// Pauses streaming of preview frames. - (void)pausePreviewWithCompletion:(void (^)(FlutterError *_Nullable))completion; -/// Resumes a previously paused preview stream. +/// Resumes a previously paused preview stream.ƒ - (void)resumePreviewWithCompletion:(void (^)(FlutterError *_Nullable))completion; /// Changes the camera used while recording video. /// /// This should only be called while video recording is active. -- (void)updateDescriptionWhileRecordingCameraName:(NSString *)cameraName - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)updateDescriptionWhileRecordingCameraName:(NSString *)cameraName completion:(void (^)(FlutterError *_Nullable))completion; /// Sets the file format used for taking pictures. -- (void)setImageFileFormat:(FCPPlatformImageFileFormat)format - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)setImageFileFormat:(FCPPlatformImageFileFormat)format completion:(void (^)(FlutterError *_Nullable))completion; @end -extern void SetUpFCPCameraApi(id binaryMessenger, - NSObject *_Nullable api); +extern void SetUpFCPCameraApi(id binaryMessenger, NSObject *_Nullable api); + +extern void SetUpFCPCameraApiWithSuffix(id binaryMessenger, NSObject *_Nullable api, NSString *messageChannelSuffix); -extern void SetUpFCPCameraApiWithSuffix(id binaryMessenger, - NSObject *_Nullable api, - NSString *messageChannelSuffix); /// Handler for native callbacks that are not tied to a specific camera ID. @interface FCPCameraGlobalEventApi : NSObject - (instancetype)initWithBinaryMessenger:(id)binaryMessenger; -- (instancetype)initWithBinaryMessenger:(id)binaryMessenger - messageChannelSuffix:(nullable NSString *)messageChannelSuffix; +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger messageChannelSuffix:(nullable NSString *)messageChannelSuffix; /// Called when the device's physical orientation changes. -- (void)deviceOrientationChangedOrientation:(FCPPlatformDeviceOrientation)orientation - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)deviceOrientationChangedOrientation:(FCPPlatformDeviceOrientation)orientation completion:(void (^)(FlutterError *_Nullable))completion; @end + /// Handler for native callbacks that are tied to a specific camera ID. /// /// This is intended to be initialized with the camera ID as a suffix. @interface FCPCameraEventApi : NSObject - (instancetype)initWithBinaryMessenger:(id)binaryMessenger; -- (instancetype)initWithBinaryMessenger:(id)binaryMessenger - messageChannelSuffix:(nullable NSString *)messageChannelSuffix; +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger messageChannelSuffix:(nullable NSString *)messageChannelSuffix; /// Called when the camera is inialitized for use. -- (void)initializedWithState:(FCPPlatformCameraState *)initialState - completion:(void (^)(FlutterError *_Nullable))completion; +- (void)initializedWithState:(FCPPlatformCameraState *)initialState completion:(void (^)(FlutterError *_Nullable))completion; /// Called when an error occurs in the camera. /// /// This should be used for errors that occur outside of the context of diff --git a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/messages.g.m b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/messages.g.m index 0164b4d6c6c..d283dee357f 100644 --- a/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/messages.g.m +++ b/packages/camera/camera_avfoundation/ios/camera_avfoundation/Sources/camera_avfoundation/messages.g.m @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v22.4.2), do not edit directly. +// Autogenerated from Pigeon (v22.7.2), do not edit directly. // See also: https://pub.dev/packages/pigeon #import "./include/camera_avfoundation/messages.g.h" @@ -26,12 +26,7 @@ } static FlutterError *createConnectionError(NSString *channelName) { - return [FlutterError - errorWithCode:@"channel-error" - message:[NSString stringWithFormat:@"%@/%@/%@", - @"Unable to establish connection on channel: '", - channelName, @"'."] - details:@""]; + return [FlutterError errorWithCode:@"channel-error" message:[NSString stringWithFormat:@"%@/%@/%@", @"Unable to establish connection on channel: '", channelName, @"'."] details:@""]; } static id GetNullableObjectAtIndex(NSArray *array, NSInteger key) { @@ -120,6 +115,16 @@ - (instancetype)initWithValue:(FCPPlatformResolutionPreset)value { } @end +@implementation FCPPlatformVideoStabilizationModeBox +- (instancetype)initWithValue:(FCPPlatformVideoStabilizationMode)value { + self = [super init]; + if (self) { + _value = value; + } + return self; +} +@end + @interface FCPPlatformCameraDescription () + (FCPPlatformCameraDescription *)fromList:(NSArray *)list; + (nullable FCPPlatformCameraDescription *)nullableFromList:(NSArray *)list; @@ -152,8 +157,8 @@ + (nullable FCPPlatformSize *)nullableFromList:(NSArray *)list; @implementation FCPPlatformCameraDescription + (instancetype)makeWithName:(NSString *)name - lensDirection:(FCPPlatformCameraLensDirection)lensDirection { - FCPPlatformCameraDescription *pigeonResult = [[FCPPlatformCameraDescription alloc] init]; + lensDirection:(FCPPlatformCameraLensDirection)lensDirection { + FCPPlatformCameraDescription* pigeonResult = [[FCPPlatformCameraDescription alloc] init]; pigeonResult.name = name; pigeonResult.lensDirection = lensDirection; return pigeonResult; @@ -161,8 +166,7 @@ + (instancetype)makeWithName:(NSString *)name + (FCPPlatformCameraDescription *)fromList:(NSArray *)list { FCPPlatformCameraDescription *pigeonResult = [[FCPPlatformCameraDescription alloc] init]; pigeonResult.name = GetNullableObjectAtIndex(list, 0); - FCPPlatformCameraLensDirectionBox *boxedFCPPlatformCameraLensDirection = - GetNullableObjectAtIndex(list, 1); + FCPPlatformCameraLensDirectionBox *boxedFCPPlatformCameraLensDirection = GetNullableObjectAtIndex(list, 1); pigeonResult.lensDirection = boxedFCPPlatformCameraLensDirection.value; return pigeonResult; } @@ -179,11 +183,11 @@ + (nullable FCPPlatformCameraDescription *)nullableFromList:(NSArray *)list @implementation FCPPlatformCameraState + (instancetype)makeWithPreviewSize:(FCPPlatformSize *)previewSize - exposureMode:(FCPPlatformExposureMode)exposureMode - focusMode:(FCPPlatformFocusMode)focusMode - exposurePointSupported:(BOOL)exposurePointSupported - focusPointSupported:(BOOL)focusPointSupported { - FCPPlatformCameraState *pigeonResult = [[FCPPlatformCameraState alloc] init]; + exposureMode:(FCPPlatformExposureMode)exposureMode + focusMode:(FCPPlatformFocusMode)focusMode + exposurePointSupported:(BOOL )exposurePointSupported + focusPointSupported:(BOOL )focusPointSupported { + FCPPlatformCameraState* pigeonResult = [[FCPPlatformCameraState alloc] init]; pigeonResult.previewSize = previewSize; pigeonResult.exposureMode = exposureMode; pigeonResult.focusMode = focusMode; @@ -218,11 +222,11 @@ + (nullable FCPPlatformCameraState *)nullableFromList:(NSArray *)list { @implementation FCPPlatformMediaSettings + (instancetype)makeWithResolutionPreset:(FCPPlatformResolutionPreset)resolutionPreset - framesPerSecond:(nullable NSNumber *)framesPerSecond - videoBitrate:(nullable NSNumber *)videoBitrate - audioBitrate:(nullable NSNumber *)audioBitrate - enableAudio:(BOOL)enableAudio { - FCPPlatformMediaSettings *pigeonResult = [[FCPPlatformMediaSettings alloc] init]; + framesPerSecond:(nullable NSNumber *)framesPerSecond + videoBitrate:(nullable NSNumber *)videoBitrate + audioBitrate:(nullable NSNumber *)audioBitrate + enableAudio:(BOOL )enableAudio { + FCPPlatformMediaSettings* pigeonResult = [[FCPPlatformMediaSettings alloc] init]; pigeonResult.resolutionPreset = resolutionPreset; pigeonResult.framesPerSecond = framesPerSecond; pigeonResult.videoBitrate = videoBitrate; @@ -232,8 +236,7 @@ + (instancetype)makeWithResolutionPreset:(FCPPlatformResolutionPreset)resolution } + (FCPPlatformMediaSettings *)fromList:(NSArray *)list { FCPPlatformMediaSettings *pigeonResult = [[FCPPlatformMediaSettings alloc] init]; - FCPPlatformResolutionPresetBox *boxedFCPPlatformResolutionPreset = - GetNullableObjectAtIndex(list, 0); + FCPPlatformResolutionPresetBox *boxedFCPPlatformResolutionPreset = GetNullableObjectAtIndex(list, 0); pigeonResult.resolutionPreset = boxedFCPPlatformResolutionPreset.value; pigeonResult.framesPerSecond = GetNullableObjectAtIndex(list, 1); pigeonResult.videoBitrate = GetNullableObjectAtIndex(list, 2); @@ -256,8 +259,9 @@ + (nullable FCPPlatformMediaSettings *)nullableFromList:(NSArray *)list { @end @implementation FCPPlatformPoint -+ (instancetype)makeWithX:(double)x y:(double)y { - FCPPlatformPoint *pigeonResult = [[FCPPlatformPoint alloc] init]; ++ (instancetype)makeWithX:(double )x + y:(double )y { + FCPPlatformPoint* pigeonResult = [[FCPPlatformPoint alloc] init]; pigeonResult.x = x; pigeonResult.y = y; return pigeonResult; @@ -280,8 +284,9 @@ + (nullable FCPPlatformPoint *)nullableFromList:(NSArray *)list { @end @implementation FCPPlatformSize -+ (instancetype)makeWithWidth:(double)width height:(double)height { - FCPPlatformSize *pigeonResult = [[FCPPlatformSize alloc] init]; ++ (instancetype)makeWithWidth:(double )width + height:(double )height { + FCPPlatformSize* pigeonResult = [[FCPPlatformSize alloc] init]; pigeonResult.width = width; pigeonResult.height = height; return pigeonResult; @@ -310,61 +315,49 @@ - (nullable id)readValueOfType:(UInt8)type { switch (type) { case 129: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil ? nil - : [[FCPPlatformCameraLensDirectionBox alloc] - initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[FCPPlatformCameraLensDirectionBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 130: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil ? nil - : [[FCPPlatformDeviceOrientationBox alloc] - initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[FCPPlatformDeviceOrientationBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 131: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[FCPPlatformExposureModeBox alloc] initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[FCPPlatformExposureModeBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 132: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[FCPPlatformFlashModeBox alloc] initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[FCPPlatformFlashModeBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 133: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil - ? nil - : [[FCPPlatformFocusModeBox alloc] initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[FCPPlatformFocusModeBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 134: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil ? nil - : [[FCPPlatformImageFileFormatBox alloc] - initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[FCPPlatformImageFileFormatBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 135: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil ? nil - : [[FCPPlatformImageFormatGroupBox alloc] - initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[FCPPlatformImageFormatGroupBox alloc] initWithValue:[enumAsNumber integerValue]]; } case 136: { NSNumber *enumAsNumber = [self readValue]; - return enumAsNumber == nil ? nil - : [[FCPPlatformResolutionPresetBox alloc] - initWithValue:[enumAsNumber integerValue]]; + return enumAsNumber == nil ? nil : [[FCPPlatformResolutionPresetBox alloc] initWithValue:[enumAsNumber integerValue]]; } - case 137: + case 137: { + NSNumber *enumAsNumber = [self readValue]; + return enumAsNumber == nil ? nil : [[FCPPlatformVideoStabilizationModeBox alloc] initWithValue:[enumAsNumber integerValue]]; + } + case 138: return [FCPPlatformCameraDescription fromList:[self readValue]]; - case 138: + case 139: return [FCPPlatformCameraState fromList:[self readValue]]; - case 139: + case 140: return [FCPPlatformMediaSettings fromList:[self readValue]]; - case 140: + case 141: return [FCPPlatformPoint fromList:[self readValue]]; - case 141: + case 142: return [FCPPlatformSize fromList:[self readValue]]; default: return [super readValueOfType:type]; @@ -408,20 +401,24 @@ - (void)writeValue:(id)value { FCPPlatformResolutionPresetBox *box = (FCPPlatformResolutionPresetBox *)value; [self writeByte:136]; [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; - } else if ([value isKindOfClass:[FCPPlatformCameraDescription class]]) { + } else if ([value isKindOfClass:[FCPPlatformVideoStabilizationModeBox class]]) { + FCPPlatformVideoStabilizationModeBox *box = (FCPPlatformVideoStabilizationModeBox *)value; [self writeByte:137]; + [self writeValue:(value == nil ? [NSNull null] : [NSNumber numberWithInteger:box.value])]; + } else if ([value isKindOfClass:[FCPPlatformCameraDescription class]]) { + [self writeByte:138]; [self writeValue:[value toList]]; } else if ([value isKindOfClass:[FCPPlatformCameraState class]]) { - [self writeByte:138]; + [self writeByte:139]; [self writeValue:[value toList]]; } else if ([value isKindOfClass:[FCPPlatformMediaSettings class]]) { - [self writeByte:139]; + [self writeByte:140]; [self writeValue:[value toList]]; } else if ([value isKindOfClass:[FCPPlatformPoint class]]) { - [self writeByte:140]; + [self writeByte:141]; [self writeValue:[value toList]]; } else if ([value isKindOfClass:[FCPPlatformSize class]]) { - [self writeByte:141]; + [self writeByte:142]; [self writeValue:[value toList]]; } else { [super writeValue:value]; @@ -444,8 +441,7 @@ - (FlutterStandardReader *)readerWithData:(NSData *)data { static FlutterStandardMessageCodec *sSharedObject = nil; static dispatch_once_t sPred = 0; dispatch_once(&sPred, ^{ - FCPMessagesPigeonCodecReaderWriter *readerWriter = - [[FCPMessagesPigeonCodecReaderWriter alloc] init]; + FCPMessagesPigeonCodecReaderWriter *readerWriter = [[FCPMessagesPigeonCodecReaderWriter alloc] init]; sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; }); return sSharedObject; @@ -454,29 +450,19 @@ void SetUpFCPCameraApi(id binaryMessenger, NSObject binaryMessenger, - NSObject *api, NSString *messageChannelSuffix) { - messageChannelSuffix = messageChannelSuffix.length > 0 - ? [NSString stringWithFormat:@".%@", messageChannelSuffix] - : @""; +void SetUpFCPCameraApiWithSuffix(id binaryMessenger, NSObject *api, NSString *messageChannelSuffix) { + messageChannelSuffix = messageChannelSuffix.length > 0 ? [NSString stringWithFormat: @".%@", messageChannelSuffix] : @""; /// Returns the list of available cameras. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.getAvailableCameras", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.getAvailableCameras", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert( - [api respondsToSelector:@selector(availableCamerasWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(availableCamerasWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(availableCamerasWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(availableCamerasWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - [api availableCamerasWithCompletion:^( - NSArray *_Nullable output, - FlutterError *_Nullable error) { + [api availableCamerasWithCompletion:^(NSArray *_Nullable output, FlutterError *_Nullable error) { callback(wrapResult(output, error)); }]; }]; @@ -486,27 +472,20 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Create a new camera with the given settings, and returns its ID. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.create", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.create", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(createCameraWithName:settings:completion:)], - @"FCPCameraApi api (%@) doesn't respond to " - @"@selector(createCameraWithName:settings:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(createCameraWithName:settings:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(createCameraWithName:settings:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; NSString *arg_cameraName = GetNullableObjectAtIndex(args, 0); FCPPlatformMediaSettings *arg_settings = GetNullableObjectAtIndex(args, 1); - [api createCameraWithName:arg_cameraName - settings:arg_settings - completion:^(NSNumber *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; + [api createCameraWithName:arg_cameraName settings:arg_settings completion:^(NSNumber *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -514,30 +493,21 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Initializes the camera with the given ID. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.initialize", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.initialize", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(initializeCamera:withImageFormat:completion:)], - @"FCPCameraApi api (%@) doesn't respond to " - @"@selector(initializeCamera:withImageFormat:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(initializeCamera:withImageFormat:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(initializeCamera:withImageFormat:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; NSInteger arg_cameraId = [GetNullableObjectAtIndex(args, 0) integerValue]; - FCPPlatformImageFormatGroupBox *boxedFCPPlatformImageFormatGroup = - GetNullableObjectAtIndex(args, 1); + FCPPlatformImageFormatGroupBox *boxedFCPPlatformImageFormatGroup = GetNullableObjectAtIndex(args, 1); FCPPlatformImageFormatGroup arg_imageFormat = boxedFCPPlatformImageFormatGroup.value; - [api initializeCamera:arg_cameraId - withImageFormat:arg_imageFormat - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api initializeCamera:arg_cameraId withImageFormat:arg_imageFormat completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -545,18 +515,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Begins streaming frames from the camera. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.startImageStream", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.startImageStream", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert( - [api respondsToSelector:@selector(startImageStreamWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(startImageStreamWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(startImageStreamWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(startImageStreamWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api startImageStreamWithCompletion:^(FlutterError *_Nullable error) { callback(wrapResult(nil, error)); @@ -568,19 +533,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Stops streaming frames from the camera. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.stopImageStream", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.stopImageStream", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert( - [api respondsToSelector:@selector(stopImageStreamWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(stopImageStreamWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(stopImageStreamWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(stopImageStreamWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api stopImageStreamWithCompletion:^(FlutterError *_Nullable error) { callback(wrapResult(nil, error)); @@ -595,18 +554,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, /// /// This is used to throttle sending frames across the channel. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.receivedImageStreamData", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.receivedImageStreamData", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(receivedImageStreamDataWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to " - @"@selector(receivedImageStreamDataWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(receivedImageStreamDataWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(receivedImageStreamDataWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api receivedImageStreamDataWithCompletion:^(FlutterError *_Nullable error) { callback(wrapResult(nil, error)); @@ -619,24 +573,19 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, /// Indicates that the given camera is no longer being used on the Dart side, /// and any associated resources can be cleaned up. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.dispose", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.dispose", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(disposeCamera:completion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(disposeCamera:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(disposeCamera:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(disposeCamera:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; NSInteger arg_cameraId = [GetNullableObjectAtIndex(args, 0) integerValue]; - [api disposeCamera:arg_cameraId - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api disposeCamera:arg_cameraId completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -644,27 +593,20 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Locks the camera capture to the current device orientation. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.lockCaptureOrientation", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.lockCaptureOrientation", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert( - [api respondsToSelector:@selector(lockCaptureOrientation:completion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(lockCaptureOrientation:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(lockCaptureOrientation:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(lockCaptureOrientation:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; - FCPPlatformDeviceOrientationBox *boxedFCPPlatformDeviceOrientation = - GetNullableObjectAtIndex(args, 0); + FCPPlatformDeviceOrientationBox *boxedFCPPlatformDeviceOrientation = GetNullableObjectAtIndex(args, 0); FCPPlatformDeviceOrientation arg_orientation = boxedFCPPlatformDeviceOrientation.value; - [api lockCaptureOrientation:arg_orientation - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api lockCaptureOrientation:arg_orientation completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -673,18 +615,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, /// Unlocks camera capture orientation, allowing it to automatically adapt to /// device orientation. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.unlockCaptureOrientation", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.unlockCaptureOrientation", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(unlockCaptureOrientationWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to " - @"@selector(unlockCaptureOrientationWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(unlockCaptureOrientationWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(unlockCaptureOrientationWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api unlockCaptureOrientationWithCompletion:^(FlutterError *_Nullable error) { callback(wrapResult(nil, error)); @@ -697,23 +634,17 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, /// Takes a picture with the current settings, and returns the path to the /// resulting file. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName: - [NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.takePicture", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.takePicture", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(takePictureWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(takePictureWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(takePictureWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(takePictureWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - [api - takePictureWithCompletion:^(NSString *_Nullable output, FlutterError *_Nullable error) { - callback(wrapResult(output, error)); - }]; + [api takePictureWithCompletion:^(NSString *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -721,18 +652,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Does any preprocessing necessary before beginning to record video. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.prepareForVideoRecording", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.prepareForVideoRecording", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(prepareForVideoRecordingWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to " - @"@selector(prepareForVideoRecordingWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(prepareForVideoRecordingWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(prepareForVideoRecordingWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api prepareForVideoRecordingWithCompletion:^(FlutterError *_Nullable error) { callback(wrapResult(nil, error)); @@ -745,25 +671,19 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, /// Begins recording video, optionally enabling streaming to Dart at the same /// time. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.startVideoRecording", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.startVideoRecording", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(startVideoRecordingWithStreaming:completion:)], - @"FCPCameraApi api (%@) doesn't respond to " - @"@selector(startVideoRecordingWithStreaming:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(startVideoRecordingWithStreaming:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(startVideoRecordingWithStreaming:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; BOOL arg_enableStream = [GetNullableObjectAtIndex(args, 0) boolValue]; - [api startVideoRecordingWithStreaming:arg_enableStream - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api startVideoRecordingWithStreaming:arg_enableStream completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -771,21 +691,15 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Stops recording video, and results the path to the resulting file. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.stopVideoRecording", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.stopVideoRecording", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert( - [api respondsToSelector:@selector(stopVideoRecordingWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(stopVideoRecordingWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(stopVideoRecordingWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(stopVideoRecordingWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { - [api stopVideoRecordingWithCompletion:^(NSString *_Nullable output, - FlutterError *_Nullable error) { + [api stopVideoRecordingWithCompletion:^(NSString *_Nullable output, FlutterError *_Nullable error) { callback(wrapResult(output, error)); }]; }]; @@ -795,18 +709,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Pauses video recording. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.pauseVideoRecording", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.pauseVideoRecording", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert( - [api respondsToSelector:@selector(pauseVideoRecordingWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(pauseVideoRecordingWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(pauseVideoRecordingWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(pauseVideoRecordingWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api pauseVideoRecordingWithCompletion:^(FlutterError *_Nullable error) { callback(wrapResult(nil, error)); @@ -818,18 +727,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Resumes a previously paused video recording. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.resumeVideoRecording", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.resumeVideoRecording", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(resumeVideoRecordingWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to " - @"@selector(resumeVideoRecordingWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(resumeVideoRecordingWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(resumeVideoRecordingWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api resumeVideoRecordingWithCompletion:^(FlutterError *_Nullable error) { callback(wrapResult(nil, error)); @@ -841,26 +745,20 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Switches the camera to the given flash mode. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setFlashMode", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setFlashMode", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(setFlashMode:completion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(setFlashMode:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(setFlashMode:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(setFlashMode:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; FCPPlatformFlashModeBox *boxedFCPPlatformFlashMode = GetNullableObjectAtIndex(args, 0); FCPPlatformFlashMode arg_mode = boxedFCPPlatformFlashMode.value; - [api setFlashMode:arg_mode - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api setFlashMode:arg_mode completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -868,27 +766,20 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Switches the camera to the given exposure mode. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setExposureMode", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setExposureMode", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(setExposureMode:completion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(setExposureMode:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(setExposureMode:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(setExposureMode:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; - FCPPlatformExposureModeBox *boxedFCPPlatformExposureMode = - GetNullableObjectAtIndex(args, 0); + FCPPlatformExposureModeBox *boxedFCPPlatformExposureMode = GetNullableObjectAtIndex(args, 0); FCPPlatformExposureMode arg_mode = boxedFCPPlatformExposureMode.value; - [api setExposureMode:arg_mode - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api setExposureMode:arg_mode completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -898,24 +789,19 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, /// /// A null value resets to the default exposure point. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.setExposurePoint", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setExposurePoint", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(setExposurePoint:completion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(setExposurePoint:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(setExposurePoint:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(setExposurePoint:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; FCPPlatformPoint *arg_point = GetNullableObjectAtIndex(args, 0); - [api setExposurePoint:arg_point - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api setExposurePoint:arg_point completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -923,17 +809,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Returns the minimum exposure offset supported by the camera. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.getMinExposureOffset", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.getMinExposureOffset", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(getMinimumExposureOffset:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(getMinimumExposureOffset:)", - api); + NSCAssert([api respondsToSelector:@selector(getMinimumExposureOffset:)], @"FCPCameraApi api (%@) doesn't respond to @selector(getMinimumExposureOffset:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api getMinimumExposureOffset:^(NSNumber *_Nullable output, FlutterError *_Nullable error) { callback(wrapResult(output, error)); @@ -945,17 +827,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Returns the maximum exposure offset supported by the camera. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.getMaxExposureOffset", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.getMaxExposureOffset", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(getMaximumExposureOffset:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(getMaximumExposureOffset:)", - api); + NSCAssert([api respondsToSelector:@selector(getMaximumExposureOffset:)], @"FCPCameraApi api (%@) doesn't respond to @selector(getMaximumExposureOffset:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api getMaximumExposureOffset:^(NSNumber *_Nullable output, FlutterError *_Nullable error) { callback(wrapResult(output, error)); @@ -967,25 +845,19 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Sets the exposure offset manually to the given value. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.setExposureOffset", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setExposureOffset", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert( - [api respondsToSelector:@selector(setExposureOffset:completion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(setExposureOffset:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(setExposureOffset:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(setExposureOffset:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; double arg_offset = [GetNullableObjectAtIndex(args, 0) doubleValue]; - [api setExposureOffset:arg_offset - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api setExposureOffset:arg_offset completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -993,26 +865,20 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Switches the camera to the given focus mode. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setFocusMode", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setFocusMode", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(setFocusMode:completion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(setFocusMode:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(setFocusMode:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(setFocusMode:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; FCPPlatformFocusModeBox *boxedFCPPlatformFocusMode = GetNullableObjectAtIndex(args, 0); FCPPlatformFocusMode arg_mode = boxedFCPPlatformFocusMode.value; - [api setFocusMode:arg_mode - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api setFocusMode:arg_mode completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -1022,25 +888,19 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, /// /// A null value resets to the default focus point. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setFocusPoint", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setFocusPoint", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(setFocusPoint:completion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(setFocusPoint:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(setFocusPoint:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(setFocusPoint:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; FCPPlatformPoint *arg_point = GetNullableObjectAtIndex(args, 0); - [api setFocusPoint:arg_point - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api setFocusPoint:arg_point completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -1048,17 +908,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Returns the minimum zoom level supported by the camera. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.getMinZoomLevel", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.getMinZoomLevel", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(getMinimumZoomLevel:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(getMinimumZoomLevel:)", api); + NSCAssert([api respondsToSelector:@selector(getMinimumZoomLevel:)], @"FCPCameraApi api (%@) doesn't respond to @selector(getMinimumZoomLevel:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api getMinimumZoomLevel:^(NSNumber *_Nullable output, FlutterError *_Nullable error) { callback(wrapResult(output, error)); @@ -1070,17 +926,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Returns the maximum zoom level supported by the camera. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.getMaxZoomLevel", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.getMaxZoomLevel", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(getMaximumZoomLevel:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(getMaximumZoomLevel:)", api); + NSCAssert([api respondsToSelector:@selector(getMaximumZoomLevel:)], @"FCPCameraApi api (%@) doesn't respond to @selector(getMaximumZoomLevel:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api getMaximumZoomLevel:^(NSNumber *_Nullable output, FlutterError *_Nullable error) { callback(wrapResult(output, error)); @@ -1092,25 +944,61 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Sets the zoom factor. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setZoomLevel", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setZoomLevel", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(setZoomLevel:completion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(setZoomLevel:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(setZoomLevel:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(setZoomLevel:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; double arg_zoom = [GetNullableObjectAtIndex(args, 0) doubleValue]; - [api setZoomLevel:arg_zoom - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api setZoomLevel:arg_zoom completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Sets the video stabilization mode. + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setVideoStabilizationMode", messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FCPGetMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(setVideoStabilizationMode:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(setVideoStabilizationMode:completion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FCPPlatformVideoStabilizationModeBox *boxedFCPPlatformVideoStabilizationMode = GetNullableObjectAtIndex(args, 0); + FCPPlatformVideoStabilizationMode arg_mode = boxedFCPPlatformVideoStabilizationMode.value; + [api setVideoStabilizationMode:arg_mode completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } + /// Sets the video stabilization mode. + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.isVideoStabilizationModeSupported", messageChannelSuffix] + binaryMessenger:binaryMessenger + codec:FCPGetMessagesCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(isVideoStabilizationModeSupported:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(isVideoStabilizationModeSupported:completion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + FCPPlatformVideoStabilizationModeBox *boxedFCPPlatformVideoStabilizationMode = GetNullableObjectAtIndex(args, 0); + FCPPlatformVideoStabilizationMode arg_mode = boxedFCPPlatformVideoStabilizationMode.value; + [api isVideoStabilizationModeSupported:arg_mode completion:^(NSNumber *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -1118,18 +1006,13 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Pauses streaming of preview frames. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.pausePreview", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.pausePreview", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(pausePreviewWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(pausePreviewWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(pausePreviewWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(pausePreviewWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api pausePreviewWithCompletion:^(FlutterError *_Nullable error) { callback(wrapResult(nil, error)); @@ -1139,20 +1022,15 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, [channel setMessageHandler:nil]; } } - /// Resumes a previously paused preview stream. + /// Resumes a previously paused preview stream.ƒ { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString - stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraApi.resumePreview", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.resumePreview", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(resumePreviewWithCompletion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(resumePreviewWithCompletion:)", - api); + NSCAssert([api respondsToSelector:@selector(resumePreviewWithCompletion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(resumePreviewWithCompletion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { [api resumePreviewWithCompletion:^(FlutterError *_Nullable error) { callback(wrapResult(nil, error)); @@ -1166,26 +1044,19 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, /// /// This should only be called while video recording is active. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.updateDescriptionWhileRecording", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.updateDescriptionWhileRecording", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert([api respondsToSelector:@selector(updateDescriptionWhileRecordingCameraName: - completion:)], - @"FCPCameraApi api (%@) doesn't respond to " - @"@selector(updateDescriptionWhileRecordingCameraName:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(updateDescriptionWhileRecordingCameraName:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(updateDescriptionWhileRecordingCameraName:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; NSString *arg_cameraName = GetNullableObjectAtIndex(args, 0); - [api updateDescriptionWhileRecordingCameraName:arg_cameraName - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api updateDescriptionWhileRecordingCameraName:arg_cameraName completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -1193,27 +1064,20 @@ void SetUpFCPCameraApiWithSuffix(id binaryMessenger, } /// Sets the file format used for taking pictures. { - FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc] - initWithName:[NSString stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation." - @"CameraApi.setImageFileFormat", - messageChannelSuffix] + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] + initWithName:[NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraApi.setImageFileFormat", messageChannelSuffix] binaryMessenger:binaryMessenger - codec:FCPGetMessagesCodec()]; + codec:FCPGetMessagesCodec()]; if (api) { - NSCAssert( - [api respondsToSelector:@selector(setImageFileFormat:completion:)], - @"FCPCameraApi api (%@) doesn't respond to @selector(setImageFileFormat:completion:)", - api); + NSCAssert([api respondsToSelector:@selector(setImageFileFormat:completion:)], @"FCPCameraApi api (%@) doesn't respond to @selector(setImageFileFormat:completion:)", api); [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { NSArray *args = message; - FCPPlatformImageFileFormatBox *boxedFCPPlatformImageFileFormat = - GetNullableObjectAtIndex(args, 0); + FCPPlatformImageFileFormatBox *boxedFCPPlatformImageFileFormat = GetNullableObjectAtIndex(args, 0); FCPPlatformImageFileFormat arg_format = boxedFCPPlatformImageFileFormat.value; - [api setImageFileFormat:arg_format - completion:^(FlutterError *_Nullable error) { - callback(wrapResult(nil, error)); - }]; + [api setImageFileFormat:arg_format completion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; }]; } else { [channel setMessageHandler:nil]; @@ -1230,42 +1094,32 @@ @implementation FCPCameraGlobalEventApi - (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger { return [self initWithBinaryMessenger:binaryMessenger messageChannelSuffix:@""]; } -- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger - messageChannelSuffix:(nullable NSString *)messageChannelSuffix { +- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger messageChannelSuffix:(nullable NSString*)messageChannelSuffix{ self = [self init]; if (self) { _binaryMessenger = binaryMessenger; - _messageChannelSuffix = [messageChannelSuffix length] == 0 - ? @"" - : [NSString stringWithFormat:@".%@", messageChannelSuffix]; + _messageChannelSuffix = [messageChannelSuffix length] == 0 ? @"" : [NSString stringWithFormat: @".%@", messageChannelSuffix]; } return self; } -- (void)deviceOrientationChangedOrientation:(FCPPlatformDeviceOrientation)arg_orientation - completion:(void (^)(FlutterError *_Nullable))completion { - NSString *channelName = [NSString - stringWithFormat: - @"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraGlobalEventApi.deviceOrientationChanged", - _messageChannelSuffix]; +- (void)deviceOrientationChangedOrientation:(FCPPlatformDeviceOrientation)arg_orientation completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraGlobalEventApi.deviceOrientationChanged", _messageChannelSuffix]; FlutterBasicMessageChannel *channel = - [FlutterBasicMessageChannel messageChannelWithName:channelName - binaryMessenger:self.binaryMessenger - codec:FCPGetMessagesCodec()]; - [channel sendMessage:@[ [[FCPPlatformDeviceOrientationBox alloc] initWithValue:arg_orientation] ] - reply:^(NSArray *reply) { - if (reply != nil) { - if (reply.count > 1) { - completion([FlutterError errorWithCode:reply[0] - message:reply[1] - details:reply[2]]); - } else { - completion(nil); - } - } else { - completion(createConnectionError(channelName)); - } - }]; + [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FCPGetMessagesCodec()]; + [channel sendMessage:@[[[FCPPlatformDeviceOrientationBox alloc] initWithValue:arg_orientation]] reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] message:reply[1] details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; } @end @@ -1279,64 +1133,51 @@ @implementation FCPCameraEventApi - (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger { return [self initWithBinaryMessenger:binaryMessenger messageChannelSuffix:@""]; } -- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger - messageChannelSuffix:(nullable NSString *)messageChannelSuffix { +- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger messageChannelSuffix:(nullable NSString*)messageChannelSuffix{ self = [self init]; if (self) { _binaryMessenger = binaryMessenger; - _messageChannelSuffix = [messageChannelSuffix length] == 0 - ? @"" - : [NSString stringWithFormat:@".%@", messageChannelSuffix]; + _messageChannelSuffix = [messageChannelSuffix length] == 0 ? @"" : [NSString stringWithFormat: @".%@", messageChannelSuffix]; } return self; } -- (void)initializedWithState:(FCPPlatformCameraState *)arg_initialState - completion:(void (^)(FlutterError *_Nullable))completion { - NSString *channelName = [NSString - stringWithFormat:@"%@%@", - @"dev.flutter.pigeon.camera_avfoundation.CameraEventApi.initialized", - _messageChannelSuffix]; +- (void)initializedWithState:(FCPPlatformCameraState *)arg_initialState completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraEventApi.initialized", _messageChannelSuffix]; FlutterBasicMessageChannel *channel = - [FlutterBasicMessageChannel messageChannelWithName:channelName - binaryMessenger:self.binaryMessenger - codec:FCPGetMessagesCodec()]; - [channel sendMessage:@[ arg_initialState ?: [NSNull null] ] - reply:^(NSArray *reply) { - if (reply != nil) { - if (reply.count > 1) { - completion([FlutterError errorWithCode:reply[0] - message:reply[1] - details:reply[2]]); - } else { - completion(nil); - } - } else { - completion(createConnectionError(channelName)); - } - }]; + [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FCPGetMessagesCodec()]; + [channel sendMessage:@[arg_initialState ?: [NSNull null]] reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] message:reply[1] details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; } -- (void)reportError:(NSString *)arg_message - completion:(void (^)(FlutterError *_Nullable))completion { - NSString *channelName = [NSString - stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraEventApi.error", - _messageChannelSuffix]; +- (void)reportError:(NSString *)arg_message completion:(void (^)(FlutterError *_Nullable))completion { + NSString *channelName = [NSString stringWithFormat:@"%@%@", @"dev.flutter.pigeon.camera_avfoundation.CameraEventApi.error", _messageChannelSuffix]; FlutterBasicMessageChannel *channel = - [FlutterBasicMessageChannel messageChannelWithName:channelName - binaryMessenger:self.binaryMessenger - codec:FCPGetMessagesCodec()]; - [channel sendMessage:@[ arg_message ?: [NSNull null] ] - reply:^(NSArray *reply) { - if (reply != nil) { - if (reply.count > 1) { - completion([FlutterError errorWithCode:reply[0] - message:reply[1] - details:reply[2]]); - } else { - completion(nil); - } - } else { - completion(createConnectionError(channelName)); - } - }]; + [FlutterBasicMessageChannel + messageChannelWithName:channelName + binaryMessenger:self.binaryMessenger + codec:FCPGetMessagesCodec()]; + [channel sendMessage:@[arg_message ?: [NSNull null]] reply:^(NSArray *reply) { + if (reply != nil) { + if (reply.count > 1) { + completion([FlutterError errorWithCode:reply[0] message:reply[1] details:reply[2]]); + } else { + completion(nil); + } + } else { + completion(createConnectionError(channelName)); + } + }]; } @end + diff --git a/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart b/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart index 3e48a5e17d6..2be9e4b1c86 100644 --- a/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart +++ b/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart @@ -369,6 +369,50 @@ class AVFoundationCamera extends CameraPlatform { } } + @override + Future setVideoStabilizationMode( + int cameraId, VideoStabilizationMode mode) async { + try { + final Map + availableModes = + await _getSupportedVideoStabilizationModeMap(cameraId); + + final PlatformVideoStabilizationMode? platformMode = availableModes[mode]; + if (platformMode == null) { + throw ArgumentError('Unavailable video stabilization mode.', 'mode'); + } + await _hostApi.setVideoStabilizationMode(platformMode); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + @override + Future> getSupportedVideoStabilizationModes( + int cameraId) async { + return (await _getSupportedVideoStabilizationModeMap(cameraId)).keys; + } + + Future> + _getSupportedVideoStabilizationModeMap(int cameraId) async { + final Map ret = + {}; + + for (final VideoStabilizationMode mode in VideoStabilizationMode.values) { + final PlatformVideoStabilizationMode? platformMode = + _pigeonVideoStabilizationMode(mode); + if (platformMode != null) { + final bool isSupported = + await _hostApi.isVideoStabilizationModeSupported(platformMode); + if (isSupported) { + ret[mode] = platformMode; + } + } + } + + return ret; + } + @override Future pausePreview(int cameraId) async { await _hostApi.pausePreview(); @@ -481,6 +525,28 @@ class AVFoundationCamera extends CameraPlatform { return PlatformResolutionPreset.max; } + /// Returns a [ResolutionPreset]'s Pigeon representation. + PlatformVideoStabilizationMode? _pigeonVideoStabilizationMode( + VideoStabilizationMode videoStabilizationMode) { + switch (videoStabilizationMode) { + case VideoStabilizationMode.off: + return PlatformVideoStabilizationMode.off; + case VideoStabilizationMode.level1: + return PlatformVideoStabilizationMode.standard; + case VideoStabilizationMode.level2: + return PlatformVideoStabilizationMode.cinematic; + case VideoStabilizationMode.level3: + return PlatformVideoStabilizationMode.cinematicExtended; + } + // The enum comes from a different package, which could get a new value at + // any time, so provide a fallback that ensures this won't break when used + // with a version that contains new values. This is deliberately outside + // the switch rather than a `default` so that the linter will flag the + // switch as needing an update. + // ignore: dead_code + return PlatformVideoStabilizationMode.cinematic; + } + /// Returns an [ImageFormatGroup]'s Pigeon representation. PlatformImageFormatGroup _pigeonImageFormat(ImageFormatGroup format) { switch (format) { diff --git a/packages/camera/camera_avfoundation/lib/src/messages.g.dart b/packages/camera/camera_avfoundation/lib/src/messages.g.dart index 535f03e34c2..e2a17170309 100644 --- a/packages/camera/camera_avfoundation/lib/src/messages.g.dart +++ b/packages/camera/camera_avfoundation/lib/src/messages.g.dart @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v22.4.2), do not edit directly. +// Autogenerated from Pigeon (v22.7.2), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers @@ -18,8 +18,7 @@ PlatformException _createConnectionError(String channelName) { ); } -List wrapResponse( - {Object? result, PlatformException? error, bool empty = false}) { +List wrapResponse({Object? result, PlatformException? error, bool empty = false}) { if (empty) { return []; } @@ -32,10 +31,8 @@ List wrapResponse( enum PlatformCameraLensDirection { /// Front facing camera (a user looking at the screen is seen by the camera). front, - /// Back facing camera (a user looking at the screen is not seen by the camera). back, - /// External camera which may not be mounted to the device. external, } @@ -84,6 +81,13 @@ enum PlatformResolutionPreset { max, } +enum PlatformVideoStabilizationMode { + off, + standard, + cinematic, + cinematicExtended, +} + class PlatformCameraDescription { PlatformCameraDescription({ required this.name, @@ -251,6 +255,7 @@ class PlatformSize { } } + class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -258,45 +263,48 @@ class _PigeonCodec extends StandardMessageCodec { if (value is int) { buffer.putUint8(4); buffer.putInt64(value); - } else if (value is PlatformCameraLensDirection) { + } else if (value is PlatformCameraLensDirection) { buffer.putUint8(129); writeValue(buffer, value.index); - } else if (value is PlatformDeviceOrientation) { + } else if (value is PlatformDeviceOrientation) { buffer.putUint8(130); writeValue(buffer, value.index); - } else if (value is PlatformExposureMode) { + } else if (value is PlatformExposureMode) { buffer.putUint8(131); writeValue(buffer, value.index); - } else if (value is PlatformFlashMode) { + } else if (value is PlatformFlashMode) { buffer.putUint8(132); writeValue(buffer, value.index); - } else if (value is PlatformFocusMode) { + } else if (value is PlatformFocusMode) { buffer.putUint8(133); writeValue(buffer, value.index); - } else if (value is PlatformImageFileFormat) { + } else if (value is PlatformImageFileFormat) { buffer.putUint8(134); writeValue(buffer, value.index); - } else if (value is PlatformImageFormatGroup) { + } else if (value is PlatformImageFormatGroup) { buffer.putUint8(135); writeValue(buffer, value.index); - } else if (value is PlatformResolutionPreset) { + } else if (value is PlatformResolutionPreset) { buffer.putUint8(136); writeValue(buffer, value.index); - } else if (value is PlatformCameraDescription) { + } else if (value is PlatformVideoStabilizationMode) { buffer.putUint8(137); - writeValue(buffer, value.encode()); - } else if (value is PlatformCameraState) { + writeValue(buffer, value.index); + } else if (value is PlatformCameraDescription) { buffer.putUint8(138); writeValue(buffer, value.encode()); - } else if (value is PlatformMediaSettings) { + } else if (value is PlatformCameraState) { buffer.putUint8(139); writeValue(buffer, value.encode()); - } else if (value is PlatformPoint) { + } else if (value is PlatformMediaSettings) { buffer.putUint8(140); writeValue(buffer, value.encode()); - } else if (value is PlatformSize) { + } else if (value is PlatformPoint) { buffer.putUint8(141); writeValue(buffer, value.encode()); + } else if (value is PlatformSize) { + buffer.putUint8(142); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -305,39 +313,42 @@ class _PigeonCodec extends StandardMessageCodec { @override Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { - case 129: + case 129: final int? value = readValue(buffer) as int?; return value == null ? null : PlatformCameraLensDirection.values[value]; - case 130: + case 130: final int? value = readValue(buffer) as int?; return value == null ? null : PlatformDeviceOrientation.values[value]; - case 131: + case 131: final int? value = readValue(buffer) as int?; return value == null ? null : PlatformExposureMode.values[value]; - case 132: + case 132: final int? value = readValue(buffer) as int?; return value == null ? null : PlatformFlashMode.values[value]; - case 133: + case 133: final int? value = readValue(buffer) as int?; return value == null ? null : PlatformFocusMode.values[value]; - case 134: + case 134: final int? value = readValue(buffer) as int?; return value == null ? null : PlatformImageFileFormat.values[value]; - case 135: + case 135: final int? value = readValue(buffer) as int?; return value == null ? null : PlatformImageFormatGroup.values[value]; - case 136: + case 136: final int? value = readValue(buffer) as int?; return value == null ? null : PlatformResolutionPreset.values[value]; - case 137: + case 137: + final int? value = readValue(buffer) as int?; + return value == null ? null : PlatformVideoStabilizationMode.values[value]; + case 138: return PlatformCameraDescription.decode(readValue(buffer)!); - case 138: + case 139: return PlatformCameraState.decode(readValue(buffer)!); - case 139: + case 140: return PlatformMediaSettings.decode(readValue(buffer)!); - case 140: + case 141: return PlatformPoint.decode(readValue(buffer)!); - case 141: + case 142: return PlatformSize.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); @@ -349,11 +360,9 @@ class CameraApi { /// Constructor for [CameraApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - CameraApi( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + CameraApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); @@ -362,10 +371,8 @@ class CameraApi { /// Returns the list of available cameras. Future> getAvailableCameras() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.getAvailableCameras$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.getAvailableCameras$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -386,23 +393,20 @@ class CameraApi { message: 'Host platform returned null value for non-null return value.', ); } else { - return (pigeonVar_replyList[0] as List?)! - .cast(); + return (pigeonVar_replyList[0] as List?)!.cast(); } } /// Create a new camera with the given settings, and returns its ID. Future create(String cameraName, PlatformMediaSettings settings) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.create$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.create$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = await pigeonVar_channel - .send([cameraName, settings]) as List?; + final List? pigeonVar_replyList = + await pigeonVar_channel.send([cameraName, settings]) as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -422,18 +426,15 @@ class CameraApi { } /// Initializes the camera with the given ID. - Future initialize( - int cameraId, PlatformImageFormatGroup imageFormat) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.initialize$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future initialize(int cameraId, PlatformImageFormatGroup imageFormat) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.initialize$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final List? pigeonVar_replyList = await pigeonVar_channel - .send([cameraId, imageFormat]) as List?; + final List? pigeonVar_replyList = + await pigeonVar_channel.send([cameraId, imageFormat]) as List?; if (pigeonVar_replyList == null) { throw _createConnectionError(pigeonVar_channelName); } else if (pigeonVar_replyList.length > 1) { @@ -449,10 +450,8 @@ class CameraApi { /// Begins streaming frames from the camera. Future startImageStream() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.startImageStream$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.startImageStream$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -474,10 +473,8 @@ class CameraApi { /// Stops streaming frames from the camera. Future stopImageStream() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.stopImageStream$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.stopImageStream$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -502,10 +499,8 @@ class CameraApi { /// /// This is used to throttle sending frames across the channel. Future receivedImageStreamData() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.receivedImageStreamData$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.receivedImageStreamData$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -528,10 +523,8 @@ class CameraApi { /// Indicates that the given camera is no longer being used on the Dart side, /// and any associated resources can be cleaned up. Future dispose(int cameraId) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.dispose$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.dispose$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -552,12 +545,9 @@ class CameraApi { } /// Locks the camera capture to the current device orientation. - Future lockCaptureOrientation( - PlatformDeviceOrientation orientation) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.lockCaptureOrientation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future lockCaptureOrientation(PlatformDeviceOrientation orientation) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.lockCaptureOrientation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -580,10 +570,8 @@ class CameraApi { /// Unlocks camera capture orientation, allowing it to automatically adapt to /// device orientation. Future unlockCaptureOrientation() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.unlockCaptureOrientation$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.unlockCaptureOrientation$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -606,10 +594,8 @@ class CameraApi { /// Takes a picture with the current settings, and returns the path to the /// resulting file. Future takePicture() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.takePicture$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.takePicture$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -636,10 +622,8 @@ class CameraApi { /// Does any preprocessing necessary before beginning to record video. Future prepareForVideoRecording() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.prepareForVideoRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.prepareForVideoRecording$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -662,10 +646,8 @@ class CameraApi { /// Begins recording video, optionally enabling streaming to Dart at the same /// time. Future startVideoRecording(bool enableStream) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.startVideoRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.startVideoRecording$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -687,10 +669,8 @@ class CameraApi { /// Stops recording video, and results the path to the resulting file. Future stopVideoRecording() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.stopVideoRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.stopVideoRecording$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -717,10 +697,8 @@ class CameraApi { /// Pauses video recording. Future pauseVideoRecording() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.pauseVideoRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.pauseVideoRecording$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -742,10 +720,8 @@ class CameraApi { /// Resumes a previously paused video recording. Future resumeVideoRecording() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.resumeVideoRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.resumeVideoRecording$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -767,10 +743,8 @@ class CameraApi { /// Switches the camera to the given flash mode. Future setFlashMode(PlatformFlashMode mode) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setFlashMode$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setFlashMode$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -792,10 +766,8 @@ class CameraApi { /// Switches the camera to the given exposure mode. Future setExposureMode(PlatformExposureMode mode) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setExposureMode$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setExposureMode$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -819,10 +791,8 @@ class CameraApi { /// /// A null value resets to the default exposure point. Future setExposurePoint(PlatformPoint? point) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setExposurePoint$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setExposurePoint$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -844,10 +814,8 @@ class CameraApi { /// Returns the minimum exposure offset supported by the camera. Future getMinExposureOffset() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.getMinExposureOffset$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.getMinExposureOffset$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -874,10 +842,8 @@ class CameraApi { /// Returns the maximum exposure offset supported by the camera. Future getMaxExposureOffset() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.getMaxExposureOffset$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.getMaxExposureOffset$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -904,10 +870,8 @@ class CameraApi { /// Sets the exposure offset manually to the given value. Future setExposureOffset(double offset) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setExposureOffset$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setExposureOffset$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -929,10 +893,8 @@ class CameraApi { /// Switches the camera to the given focus mode. Future setFocusMode(PlatformFocusMode mode) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setFocusMode$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setFocusMode$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -956,10 +918,8 @@ class CameraApi { /// /// A null value resets to the default focus point. Future setFocusPoint(PlatformPoint? point) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setFocusPoint$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setFocusPoint$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -981,10 +941,8 @@ class CameraApi { /// Returns the minimum zoom level supported by the camera. Future getMinZoomLevel() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.getMinZoomLevel$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.getMinZoomLevel$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1011,10 +969,8 @@ class CameraApi { /// Returns the maximum zoom level supported by the camera. Future getMaxZoomLevel() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.getMaxZoomLevel$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.getMaxZoomLevel$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1041,10 +997,8 @@ class CameraApi { /// Sets the zoom factor. Future setZoomLevel(double zoom) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setZoomLevel$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setZoomLevel$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1064,12 +1018,61 @@ class CameraApi { } } + /// Sets the video stabilization mode. + Future setVideoStabilizationMode(PlatformVideoStabilizationMode mode) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setVideoStabilizationMode$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([mode]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + /// Sets the video stabilization mode. + Future isVideoStabilizationModeSupported(PlatformVideoStabilizationMode mode) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.isVideoStabilizationModeSupported$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([mode]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else if (pigeonVar_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (pigeonVar_replyList[0] as bool?)!; + } + } + /// Pauses streaming of preview frames. Future pausePreview() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.pausePreview$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.pausePreview$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1089,12 +1092,10 @@ class CameraApi { } } - /// Resumes a previously paused preview stream. + /// Resumes a previously paused preview stream.ƒ Future resumePreview() async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.resumePreview$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.resumePreview$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1118,10 +1119,8 @@ class CameraApi { /// /// This should only be called while video recording is active. Future updateDescriptionWhileRecording(String cameraName) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.updateDescriptionWhileRecording$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.updateDescriptionWhileRecording$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1143,10 +1142,8 @@ class CameraApi { /// Sets the file format used for taking pictures. Future setImageFileFormat(PlatformImageFileFormat format) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setImageFileFormat$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final String pigeonVar_channelName = 'dev.flutter.pigeon.camera_avfoundation.CameraApi.setImageFileFormat$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, @@ -1174,29 +1171,20 @@ abstract class CameraGlobalEventApi { /// Called when the device's physical orientation changes. void deviceOrientationChanged(PlatformDeviceOrientation orientation); - static void setUp( - CameraGlobalEventApi? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp(CameraGlobalEventApi? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.camera_avfoundation.CameraGlobalEventApi.deviceOrientationChanged$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.camera_avfoundation.CameraGlobalEventApi.deviceOrientationChanged$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraGlobalEventApi.deviceOrientationChanged was null.'); + 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraGlobalEventApi.deviceOrientationChanged was null.'); final List args = (message as List?)!; - final PlatformDeviceOrientation? arg_orientation = - (args[0] as PlatformDeviceOrientation?); + final PlatformDeviceOrientation? arg_orientation = (args[0] as PlatformDeviceOrientation?); assert(arg_orientation != null, 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraGlobalEventApi.deviceOrientationChanged was null, expected non-null PlatformDeviceOrientation.'); try { @@ -1204,9 +1192,8 @@ abstract class CameraGlobalEventApi { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } @@ -1229,29 +1216,20 @@ abstract class CameraEventApi { /// handling a specific HostApi call, such as during streaming. void error(String message); - static void setUp( - CameraEventApi? api, { - BinaryMessenger? binaryMessenger, - String messageChannelSuffix = '', - }) { - messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + static void setUp(CameraEventApi? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.camera_avfoundation.CameraEventApi.initialized$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.camera_avfoundation.CameraEventApi.initialized$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraEventApi.initialized was null.'); + 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraEventApi.initialized was null.'); final List args = (message as List?)!; - final PlatformCameraState? arg_initialState = - (args[0] as PlatformCameraState?); + final PlatformCameraState? arg_initialState = (args[0] as PlatformCameraState?); assert(arg_initialState != null, 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraEventApi.initialized was null, expected non-null PlatformCameraState.'); try { @@ -1259,26 +1237,22 @@ abstract class CameraEventApi { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } } { - final BasicMessageChannel< - Object?> pigeonVar_channel = BasicMessageChannel< - Object?>( - 'dev.flutter.pigeon.camera_avfoundation.CameraEventApi.error$messageChannelSuffix', - pigeonChannelCodec, + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.camera_avfoundation.CameraEventApi.error$messageChannelSuffix', pigeonChannelCodec, binaryMessenger: binaryMessenger); if (api == null) { pigeonVar_channel.setMessageHandler(null); } else { pigeonVar_channel.setMessageHandler((Object? message) async { assert(message != null, - 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraEventApi.error was null.'); + 'Argument for dev.flutter.pigeon.camera_avfoundation.CameraEventApi.error was null.'); final List args = (message as List?)!; final String? arg_message = (args[0] as String?); assert(arg_message != null, @@ -1288,9 +1262,8 @@ abstract class CameraEventApi { return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); - } catch (e) { - return wrapResponse( - error: PlatformException(code: 'error', message: e.toString())); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); } }); } diff --git a/packages/camera/camera_avfoundation/pigeons/messages.dart b/packages/camera/camera_avfoundation/pigeons/messages.dart index 272ea288960..229a3561edd 100644 --- a/packages/camera/camera_avfoundation/pigeons/messages.dart +++ b/packages/camera/camera_avfoundation/pigeons/messages.dart @@ -79,6 +79,13 @@ enum PlatformResolutionPreset { max, } +enum PlatformVideoStabilizationMode { + off, + standard, + cinematic, + cinematicExtended, +} + // Pigeon version of CameraDescription. class PlatformCameraDescription { PlatformCameraDescription({ @@ -289,11 +296,21 @@ abstract class CameraApi { @ObjCSelector('setZoomLevel:') void setZoomLevel(double zoom); + /// Sets the video stabilization mode. + @async + @ObjCSelector('setVideoStabilizationMode:') + void setVideoStabilizationMode(PlatformVideoStabilizationMode mode); + + /// Sets the video stabilization mode. + @async + @ObjCSelector('isVideoStabilizationModeSupported:') + bool isVideoStabilizationModeSupported(PlatformVideoStabilizationMode mode); + /// Pauses streaming of preview frames. @async void pausePreview(); - /// Resumes a previously paused preview stream. + /// Resumes a previously paused preview stream.ƒ @async void resumePreview(); diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index e8d3a9d3fa3..9e21ee3481b 100644 --- a/packages/camera/camera_avfoundation/pubspec.yaml +++ b/packages/camera/camera_avfoundation/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_avfoundation description: iOS implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_avfoundation issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.9.18+9 +version: 0.10.0 environment: sdk: ^3.4.0 @@ -17,7 +17,7 @@ flutter: dartPluginClass: AVFoundationCamera dependencies: - camera_platform_interface: ^2.9.0 + camera_platform_interface: ^2.10.0 flutter: sdk: flutter stream_transform: ^2.0.0 @@ -33,3 +33,8 @@ dev_dependencies: topics: - camera + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {camera_platform_interface: {path: ../../camera/camera_platform_interface}} diff --git a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart index 1e8ad7def5d..90481e93b51 100644 --- a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart +++ b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart @@ -578,6 +578,130 @@ void main() { verify(mockApi.setFocusMode(PlatformFocusMode.locked)); }); + test('Should set video stabilization mode to off', () async { + when(mockApi.isVideoStabilizationModeSupported( + PlatformVideoStabilizationMode.off)) + .thenAnswer((_) async => true); + + await camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.off); + + verify(mockApi + .setVideoStabilizationMode(PlatformVideoStabilizationMode.off)); + }); + + test('Should set video stabilization mode to level1', () async { + when(mockApi.isVideoStabilizationModeSupported( + PlatformVideoStabilizationMode.standard)) + .thenAnswer((_) async => true); + + await camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.level1); + + verify(mockApi + .setVideoStabilizationMode(PlatformVideoStabilizationMode.standard)); + }); + + test('Should set video stabilization mode to cinematic', () async { + when(mockApi.isVideoStabilizationModeSupported( + PlatformVideoStabilizationMode.cinematic)) + .thenAnswer((_) async => true); + + await camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.level2); + + verify(mockApi + .setVideoStabilizationMode(PlatformVideoStabilizationMode.cinematic)); + }); + + test('Should set video stabilization mode to cinematicExtended', () async { + when(mockApi.isVideoStabilizationModeSupported( + PlatformVideoStabilizationMode.cinematicExtended)) + .thenAnswer((_) async => true); + + await camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.level3); + + verify(mockApi.setVideoStabilizationMode( + PlatformVideoStabilizationMode.cinematicExtended)); + }); + + test('Should get no video stabilization mode', () async { + when(mockApi.isVideoStabilizationModeSupported(any)) + .thenAnswer((_) async => false); + + final Iterable modes = + await camera.getSupportedVideoStabilizationModes(cameraId); + + expect(modes, isEmpty); + }); + + test('Should get off and standard video stabilization modes', () async { + when(mockApi.isVideoStabilizationModeSupported( + PlatformVideoStabilizationMode.off)) + .thenAnswer((_) async => true); + when(mockApi.isVideoStabilizationModeSupported( + PlatformVideoStabilizationMode.standard)) + .thenAnswer((_) async => true); + when(mockApi.isVideoStabilizationModeSupported( + PlatformVideoStabilizationMode.cinematic)) + .thenAnswer((_) async => false); + when(mockApi.isVideoStabilizationModeSupported( + PlatformVideoStabilizationMode.cinematicExtended)) + .thenAnswer((_) async => false); + + final List modes = + (await camera.getSupportedVideoStabilizationModes(cameraId)).toList(); + + expect(modes, [ + VideoStabilizationMode.off, + VideoStabilizationMode.level1, + ]); + }); + + test('Should get all video stabilization modes', () async { + when(mockApi.isVideoStabilizationModeSupported(any)) + .thenAnswer((_) async => true); + + final List modes = + (await camera.getSupportedVideoStabilizationModes(cameraId)).toList(); + + expect(modes, [ + VideoStabilizationMode.off, + VideoStabilizationMode.level1, + VideoStabilizationMode.level2, + VideoStabilizationMode.level3, + ]); + }); + + test( + 'Should throw ArgumentError when unavailable video stabilization mode is set', + () async { + when(mockApi.isVideoStabilizationModeSupported(any)) + .thenAnswer((_) async => false); + + expect( + () => camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.off), + throwsA(isA() + .having((ArgumentError e) => e.name, 'name', 'mode'))); + expect( + () => camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.level1), + throwsA(isA() + .having((ArgumentError e) => e.name, 'name', 'mode'))); + expect( + () => camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.level2), + throwsA(isA() + .having((ArgumentError e) => e.name, 'name', 'mode'))); + expect( + () => camera.setVideoStabilizationMode( + cameraId, VideoStabilizationMode.level3), + throwsA(isA() + .having((ArgumentError e) => e.name, 'name', 'mode'))); + }); + test('Should set the focus point to a value', () async { const Point point = Point(0.4, 0.6); await camera.setFocusPoint(cameraId, point); diff --git a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.mocks.dart b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.mocks.dart index b1118578a16..1957ada0c82 100644 --- a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.mocks.dart +++ b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.mocks.dart @@ -351,6 +351,30 @@ class MockCameraApi extends _i1.Mock implements _i2.CameraApi { returnValueForMissingStub: _i4.Future.value(), ) as _i4.Future); + @override + _i4.Future setVideoStabilizationMode( + _i2.PlatformVideoStabilizationMode? mode) => + (super.noSuchMethod( + Invocation.method( + #setVideoStabilizationMode, + [mode], + ), + returnValue: _i4.Future.value(), + returnValueForMissingStub: _i4.Future.value(), + ) as _i4.Future); + + @override + _i4.Future isVideoStabilizationModeSupported( + _i2.PlatformVideoStabilizationMode? mode) => + (super.noSuchMethod( + Invocation.method( + #isVideoStabilizationModeSupported, + [mode], + ), + returnValue: _i4.Future.value(false), + returnValueForMissingStub: _i4.Future.value(false), + ) as _i4.Future); + @override _i4.Future pausePreview() => (super.noSuchMethod( Invocation.method( diff --git a/packages/camera/camera_platform_interface/AUTHORS b/packages/camera/camera_platform_interface/AUTHORS index 0d1bfa6a90c..d21929d105f 100644 --- a/packages/camera/camera_platform_interface/AUTHORS +++ b/packages/camera/camera_platform_interface/AUTHORS @@ -65,3 +65,4 @@ Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> Mairramer +Rui Craveiro \ No newline at end of file diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index d122ae154d0..411e4aa3801 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.10.0 + +* Adds support for video stabilization. + ## 2.9.0 * Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. @@ -9,6 +13,7 @@ most platforms, and there is no plan to implement it in the future. * Updates minimum supported SDK version to Flutter 3.16/Dart 3.2. + ## 2.7.4 * Updates minimum supported SDK version to Flutter 3.13/Dart 3.1. diff --git a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart index e38df486533..258a0583a98 100644 --- a/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart +++ b/packages/camera/camera_platform_interface/lib/src/method_channel/method_channel_camera.dart @@ -502,6 +502,44 @@ class MethodChannelCamera extends CameraPlatform { } } + @override + Future> getSupportedVideoStabilizationModes( + int cameraId) async { + try { + final List? modes = await _channel.invokeMethod>( + 'getSupportedVideoStabilizationModes', + { + 'cameraId': cameraId, + }, + ); + + if (modes == null) { + return []; + } + return modes + .map((Object? e) => VideoStabilizationMode.fromString(e! as String)); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + + /// Sets the video stabilization mode for the selected camera + @override + Future setVideoStabilizationMode( + int cameraId, VideoStabilizationMode mode) async { + try { + await _channel.invokeMethod( + 'setVideoStabilizationMode', + { + 'cameraId': cameraId, + 'mode': mode.name, + }, + ); + } on PlatformException catch (e) { + throw CameraException(e.code, e.message); + } + } + @override Future pausePreview(int cameraId) async { await _channel.invokeMethod( diff --git a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart index 78228c63693..303ff5a8ba4 100644 --- a/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart +++ b/packages/camera/camera_platform_interface/lib/src/platform_interface/camera_platform.dart @@ -275,6 +275,22 @@ abstract class CameraPlatform extends PlatformInterface { throw UnimplementedError('setZoomLevel() is not implemented.'); } + /// Gets a list of video stabilization modes that are supported for the selected camera. + Future> getSupportedVideoStabilizationModes( + int cameraId) async { + throw UnimplementedError( + 'getSupportedVideoStabilizationModes() is not implemented.'); + } + + /// Sets the video stabilization mode for the selected camera. + /// + /// Throws a [ArgumentError] when a not supported video stabilization + /// mode is supplied. + Future setVideoStabilizationMode( + int cameraId, VideoStabilizationMode mode) async { + throw UnimplementedError('setVideoStabilizationMode() is not implemented.'); + } + /// Pause the active preview on the current frame for the selected camera. Future pausePreview(int cameraId) { throw UnimplementedError('pausePreview() is not implemented.'); diff --git a/packages/camera/camera_platform_interface/lib/src/types/types.dart b/packages/camera/camera_platform_interface/lib/src/types/types.dart index e56b9b4c49a..34e906a2808 100644 --- a/packages/camera/camera_platform_interface/lib/src/types/types.dart +++ b/packages/camera/camera_platform_interface/lib/src/types/types.dart @@ -13,3 +13,4 @@ export 'image_format_group.dart'; export 'media_settings.dart'; export 'resolution_preset.dart'; export 'video_capture_options.dart'; +export 'video_stabilization_mode.dart'; diff --git a/packages/camera/camera_platform_interface/lib/src/types/video_stabilization_mode.dart b/packages/camera/camera_platform_interface/lib/src/types/video_stabilization_mode.dart new file mode 100644 index 00000000000..9868d899c96 --- /dev/null +++ b/packages/camera/camera_platform_interface/lib/src/types/video_stabilization_mode.dart @@ -0,0 +1,24 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// The possible video stabilization modes that can be capturing video. +enum VideoStabilizationMode { + /// 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; + + /// Returns the video stabilization mode for a given String. + factory VideoStabilizationMode.fromString(String str) { + return VideoStabilizationMode.values + .firstWhere((VideoStabilizationMode mode) => mode.name == str); + } +} diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index bea9eef2319..a26c038ed11 100644 --- a/packages/camera/camera_platform_interface/pubspec.yaml +++ b/packages/camera/camera_platform_interface/pubspec.yaml @@ -4,7 +4,7 @@ repository: https://github.com/flutter/packages/tree/main/packages/camera/camera issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 # NOTE: We strongly prefer non-breaking changes, even at the expense of a # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes -version: 2.9.0 +version: 2.10.0 environment: sdk: ^3.4.0 diff --git a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart index 063633255c9..fb2e4549cfa 100644 --- a/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart +++ b/packages/camera/camera_platform_interface/test/method_channel/method_channel_camera_test.dart @@ -1014,6 +1014,149 @@ void main() { 'Illegal zoom error'))); }); + test('Should get empty list from getSupportedVideoStabilizationModes', + () async { + // Arrange + final MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: { + 'getSupportedVideoStabilizationModes': [], + }, + ); + + // Act + final Iterable modes = + await camera.getSupportedVideoStabilizationModes( + cameraId, + ); + + // Assert + expect(modes, []); + + expect(channel.log, [ + isMethodCall('getSupportedVideoStabilizationModes', + arguments: { + 'cameraId': cameraId, + }), + ]); + }); + + test( + 'Should get list containing off from getSupportedVideoStabilizationModes', + () async { + // Arrange + final MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: { + 'getSupportedVideoStabilizationModes': ['off'], + }, + ); + + // Act + final Iterable modes = + await camera.getSupportedVideoStabilizationModes( + cameraId, + ); + + // Assert + expect(modes, [VideoStabilizationMode.off]); + + expect(channel.log, [ + isMethodCall('getSupportedVideoStabilizationModes', + arguments: { + 'cameraId': cameraId, + }), + ]); + }); + + test( + 'Should get list containing all from getSupportedVideoStabilizationModes', + () async { + // Arrange + final MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: { + 'getSupportedVideoStabilizationModes': [ + 'off', + 'level1', + 'level2', + 'level3', + ], + }, + ); + + // Act + final Iterable modes = + await camera.getSupportedVideoStabilizationModes( + cameraId, + ); + + // Assert + expect(modes, [ + VideoStabilizationMode.off, + VideoStabilizationMode.level1, + VideoStabilizationMode.level2, + VideoStabilizationMode.level3, + ]); + + expect(channel.log, [ + isMethodCall('getSupportedVideoStabilizationModes', + arguments: { + 'cameraId': cameraId, + }), + ]); + }); + + test('Should set the video stabilization mode', () async { + // Arrange + final MethodChannelMock channel = MethodChannelMock( + channelName: 'plugins.flutter.io/camera', + methods: {'setVideoStabilizationMode': null}, + ); + + // Act + await camera.setVideoStabilizationMode( + cameraId, + VideoStabilizationMode.off, + ); + await camera.setVideoStabilizationMode( + cameraId, + VideoStabilizationMode.level1, + ); + await camera.setVideoStabilizationMode( + cameraId, + VideoStabilizationMode.level2, + ); + await camera.setVideoStabilizationMode( + cameraId, + VideoStabilizationMode.level3, + ); + + // Assert + expect(channel.log, [ + isMethodCall('setVideoStabilizationMode', + arguments: { + 'cameraId': cameraId, + 'mode': VideoStabilizationMode.off.name, + }), + isMethodCall('setVideoStabilizationMode', + arguments: { + 'cameraId': cameraId, + 'mode': VideoStabilizationMode.level1.name, + }), + isMethodCall('setVideoStabilizationMode', + arguments: { + 'cameraId': cameraId, + 'mode': VideoStabilizationMode.level2.name, + }), + isMethodCall('setVideoStabilizationMode', + arguments: { + 'cameraId': cameraId, + 'mode': VideoStabilizationMode.level3.name, + }), + ]); + }); + test('Should lock the capture orientation', () async { // Arrange final MethodChannelMock channel = MethodChannelMock( diff --git a/packages/camera/camera_platform_interface/test/types/video_stabilization_mode_test.dart b/packages/camera/camera_platform_interface/test/types/video_stabilization_mode_test.dart new file mode 100644 index 00000000000..8491d6d05d2 --- /dev/null +++ b/packages/camera/camera_platform_interface/test/types/video_stabilization_mode_test.dart @@ -0,0 +1,34 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:camera_platform_interface/src/types/video_stabilization_mode.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('VideoStabilizationMode should contain 4 options', () { + const List values = VideoStabilizationMode.values; + + expect(values.length, 4); + }); + + test('VideoStabilizationMode enum should have items in correct index', () { + const List values = VideoStabilizationMode.values; + + expect(values[0], VideoStabilizationMode.off); + expect(values[1], VideoStabilizationMode.level1); + expect(values[2], VideoStabilizationMode.level2); + expect(values[3], VideoStabilizationMode.level3); + }); + + test('deserializeVideoStabilizationMode() should deserialize correctly', () { + expect( + VideoStabilizationMode.fromString('off'), VideoStabilizationMode.off); + expect(VideoStabilizationMode.fromString('level1'), + VideoStabilizationMode.level1); + expect(VideoStabilizationMode.fromString('level2'), + VideoStabilizationMode.level2); + expect(VideoStabilizationMode.fromString('level3'), + VideoStabilizationMode.level3); + }); +} diff --git a/packages/camera/camera_web/CHANGELOG.md b/packages/camera/camera_web/CHANGELOG.md index fe5ec3a9d1d..dbdcef2179a 100644 --- a/packages/camera/camera_web/CHANGELOG.md +++ b/packages/camera/camera_web/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.3.5+1 +* Updates camera_platform_interface lib to 2.9.0. * Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. ## 0.3.5 diff --git a/packages/camera/camera_web/example/pubspec.yaml b/packages/camera/camera_web/example/pubspec.yaml index 8305d8434ab..8aa35e950bf 100644 --- a/packages/camera/camera_web/example/pubspec.yaml +++ b/packages/camera/camera_web/example/pubspec.yaml @@ -26,3 +26,10 @@ dev_dependencies: integration_test: sdk: flutter mocktail: 0.3.0 + + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {camera_platform_interface: {path: ../../../camera/camera_platform_interface}, camera_web: {path: ../../../camera/camera_web}} + diff --git a/packages/camera/camera_web/pubspec.yaml b/packages/camera/camera_web/pubspec.yaml index 4052a701b86..7d389968b1c 100644 --- a/packages/camera/camera_web/pubspec.yaml +++ b/packages/camera/camera_web/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_web description: A Flutter plugin for getting information about and controlling the camera on Web. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_web issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.3.5 +version: 0.3.5+1 environment: sdk: ^3.4.0 @@ -17,7 +17,7 @@ flutter: fileName: camera_web.dart dependencies: - camera_platform_interface: ^2.6.0 + camera_platform_interface: ^2.9.0 flutter: sdk: flutter flutter_web_plugins: @@ -31,3 +31,8 @@ dev_dependencies: topics: - camera + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {camera_platform_interface: {path: ../../camera/camera_platform_interface}} diff --git a/packages/camera/camera_windows/CHANGELOG.md b/packages/camera/camera_windows/CHANGELOG.md index 7b0cca7134b..7170db2cbf3 100644 --- a/packages/camera/camera_windows/CHANGELOG.md +++ b/packages/camera/camera_windows/CHANGELOG.md @@ -23,6 +23,7 @@ ## 0.2.4+1 +* Updates camera_platform_interface lib to 2.9.0. * Updates to pigeon 21. ## 0.2.4 diff --git a/packages/camera/camera_windows/example/pubspec.yaml b/packages/camera/camera_windows/example/pubspec.yaml index 7eabccf3d65..50959680642 100644 --- a/packages/camera/camera_windows/example/pubspec.yaml +++ b/packages/camera/camera_windows/example/pubspec.yaml @@ -27,3 +27,8 @@ dev_dependencies: flutter: uses-material-design: true + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {camera_platform_interface: {path: ../../../camera/camera_platform_interface}, camera_windows: {path: ../../../camera/camera_windows}} diff --git a/packages/camera/camera_windows/pubspec.yaml b/packages/camera/camera_windows/pubspec.yaml index d66f36f2550..e3c0151e90a 100644 --- a/packages/camera/camera_windows/pubspec.yaml +++ b/packages/camera/camera_windows/pubspec.yaml @@ -17,7 +17,7 @@ flutter: dartPluginClass: CameraWindows dependencies: - camera_platform_interface: ^2.6.0 + camera_platform_interface: ^2.9.0 cross_file: ^0.3.1 flutter: sdk: flutter @@ -34,3 +34,8 @@ dev_dependencies: topics: - camera + +# FOR TESTING AND INITIAL REVIEW ONLY. DO NOT MERGE. +# See https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changing-federated-plugins +dependency_overrides: + {camera_platform_interface: {path: ../../camera/camera_platform_interface}}