diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index ef066c8e56bf..750145ea1cb4 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -1,7 +1,3 @@ -## 0.10.1 - -* Implements option to also stream when recording a video. - ## 0.10.0+5 * Fixes `ArrayIndexOutOfBoundsException` when the permission request is interrupted. diff --git a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java index 7c592b9c7e99..3d2df98b60da 100644 --- a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -522,21 +522,6 @@ private void refreshPreviewCaptureSession( } } - private void startCapture(boolean record, boolean stream) throws CameraAccessException { - List surfaces = new ArrayList<>(); - Runnable successCallback = null; - if (record) { - surfaces.add(mediaRecorder.getSurface()); - successCallback = () -> mediaRecorder.start(); - } - if (stream) { - surfaces.add(imageStreamReader.getSurface()); - } - - createCaptureSession( - CameraDevice.TEMPLATE_RECORD, successCallback, surfaces.toArray(new Surface[0])); - } - public void takePicture(@NonNull final Result result) { // Only take one picture at a time. if (cameraCaptureCallback.getCameraState() != CameraState.STATE_PREVIEW) { @@ -746,17 +731,29 @@ private void unlockAutoFocus() { dartMessenger.error(flutterResult, errorCode, errorMessage, null)); } - public void startVideoRecording( - @NonNull Result result, @Nullable EventChannel imageStreamChannel) { - prepareRecording(result); - - if (imageStreamChannel != null) { - setStreamHandler(imageStreamChannel); + public void startVideoRecording(@NonNull Result result) { + final File outputDir = applicationContext.getCacheDir(); + try { + captureFile = File.createTempFile("REC", ".mp4", outputDir); + } catch (IOException | SecurityException e) { + result.error("cannotCreateFile", e.getMessage(), null); + return; } - + try { + prepareMediaRecorder(captureFile.getAbsolutePath()); + } catch (IOException e) { + recordingVideo = false; + captureFile = null; + result.error("videoRecordingFailed", e.getMessage(), null); + return; + } + // Re-create autofocus feature so it's using video focus mode now. + cameraFeatures.setAutoFocus( + cameraFeatureFactory.createAutoFocusFeature(cameraProperties, true)); recordingVideo = true; try { - startCapture(true, imageStreamChannel != null); + createCaptureSession( + CameraDevice.TEMPLATE_RECORD, () -> mediaRecorder.start(), mediaRecorder.getSurface()); result.success(null); } catch (CameraAccessException e) { recordingVideo = false; @@ -1076,10 +1073,21 @@ public void startPreview() throws CameraAccessException { public void startPreviewWithImageStream(EventChannel imageStreamChannel) throws CameraAccessException { - setStreamHandler(imageStreamChannel); - - startCapture(false, true); + createCaptureSession(CameraDevice.TEMPLATE_RECORD, imageStreamReader.getSurface()); Log.i(TAG, "startPreviewWithImageStream"); + + imageStreamChannel.setStreamHandler( + new EventChannel.StreamHandler() { + @Override + public void onListen(Object o, EventChannel.EventSink imageStreamSink) { + setImageStreamImageAvailableListener(imageStreamSink); + } + + @Override + public void onCancel(Object o) { + imageStreamReader.setOnImageAvailableListener(null, backgroundHandler); + } + }); } /** @@ -1109,42 +1117,6 @@ public void onError(String errorCode, String errorMessage) { cameraCaptureCallback.setCameraState(CameraState.STATE_PREVIEW); } - private void prepareRecording(@NonNull Result result) { - final File outputDir = applicationContext.getCacheDir(); - try { - captureFile = File.createTempFile("REC", ".mp4", outputDir); - } catch (IOException | SecurityException e) { - result.error("cannotCreateFile", e.getMessage(), null); - return; - } - try { - prepareMediaRecorder(captureFile.getAbsolutePath()); - } catch (IOException e) { - recordingVideo = false; - captureFile = null; - result.error("videoRecordingFailed", e.getMessage(), null); - return; - } - // Re-create autofocus feature so it's using video focus mode now. - cameraFeatures.setAutoFocus( - cameraFeatureFactory.createAutoFocusFeature(cameraProperties, true)); - } - - private void setStreamHandler(EventChannel imageStreamChannel) { - imageStreamChannel.setStreamHandler( - new EventChannel.StreamHandler() { - @Override - public void onListen(Object o, EventChannel.EventSink imageStreamSink) { - setImageStreamImageAvailableListener(imageStreamSink); - } - - @Override - public void onCancel(Object o) { - imageStreamReader.setOnImageAvailableListener(null, backgroundHandler); - } - }); - } - private void setImageStreamImageAvailableListener(final EventChannel.EventSink imageStreamSink) { imageStreamReader.setOnImageAvailableListener( reader -> { diff --git a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index 432344ade8cd..38201e1136c9 100644 --- a/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/camera_android/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -26,7 +26,6 @@ import io.flutter.view.TextureRegistry; import java.util.HashMap; import java.util.Map; -import java.util.Objects; final class MethodCallHandlerImpl implements MethodChannel.MethodCallHandler { private final Activity activity; @@ -119,9 +118,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) } case "startVideoRecording": { - camera.startVideoRecording( - result, - Objects.equals(call.argument("enableStream"), true) ? imageStreamChannel : null); + camera.startVideoRecording(result); break; } case "stopVideoRecording": diff --git a/packages/camera/camera_android/example/integration_test/camera_test.dart b/packages/camera/camera_android/example/integration_test/camera_test.dart index 4c51a593f259..3b1aae6aec51 100644 --- a/packages/camera/camera_android/example/integration_test/camera_test.dart +++ b/packages/camera/camera_android/example/integration_test/camera_test.dart @@ -245,44 +245,4 @@ void main() { await controller.dispose(); }, ); - - testWidgets( - 'recording with image stream', - (WidgetTester tester) async { - final List cameras = - await CameraPlatform.instance.availableCameras(); - if (cameras.isEmpty) { - return; - } - - final CameraController controller = CameraController( - cameras[0], - ResolutionPreset.low, - enableAudio: false, - ); - - await controller.initialize(); - bool isDetecting = false; - - await controller.startVideoRecording( - streamCallback: (CameraImageData image) { - if (isDetecting) { - return; - } - - isDetecting = true; - - expectLater(image, isNotNull).whenComplete(() => isDetecting = false); - }); - - expect(controller.value.isStreamingImages, true); - - sleep(const Duration(milliseconds: 500)); - - await controller.stopVideoRecording(); - await controller.dispose(); - - expect(controller.value.isStreamingImages, false); - }, - ); } diff --git a/packages/camera/camera_android/example/lib/camera_controller.dart b/packages/camera/camera_android/example/lib/camera_controller.dart index 94d8ef6540b1..09441cc5449c 100644 --- a/packages/camera/camera_android/example/lib/camera_controller.dart +++ b/packages/camera/camera_android/example/lib/camera_controller.dart @@ -306,14 +306,11 @@ class CameraController extends ValueNotifier { /// /// The video is returned as a [XFile] after calling [stopVideoRecording]. /// Throws a [CameraException] if the capture fails. - Future startVideoRecording( - {Function(CameraImageData image)? streamCallback}) async { - await CameraPlatform.instance.startVideoCapturing( - VideoCaptureOptions(_cameraId, streamCallback: streamCallback)); + Future startVideoRecording() async { + await CameraPlatform.instance.startVideoRecording(_cameraId); value = value.copyWith( isRecordingVideo: true, isRecordingPaused: false, - isStreamingImages: streamCallback != null, recordingOrientation: Optional.of( value.lockedCaptureOrientation ?? value.deviceOrientation)); } @@ -322,15 +319,10 @@ class CameraController extends ValueNotifier { /// /// Throws a [CameraException] if the capture failed. Future stopVideoRecording() async { - if (value.isStreamingImages) { - await stopImageStream(); - } - final XFile file = await CameraPlatform.instance.stopVideoRecording(_cameraId); value = value.copyWith( isRecordingVideo: false, - isRecordingPaused: false, recordingOrientation: const Optional.absent(), ); return file; diff --git a/packages/camera/camera_android/example/pubspec.yaml b/packages/camera/camera_android/example/pubspec.yaml index 8c985d94fd5a..2e530e02ca71 100644 --- a/packages/camera/camera_android/example/pubspec.yaml +++ b/packages/camera/camera_android/example/pubspec.yaml @@ -14,7 +14,7 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - camera_platform_interface: ^2.3.1 + camera_platform_interface: ^2.2.0 flutter: sdk: flutter path_provider: ^2.0.0 diff --git a/packages/camera/camera_android/lib/src/android_camera.dart b/packages/camera/camera_android/lib/src/android_camera.dart index 4b342eee08d5..36077eac8eed 100644 --- a/packages/camera/camera_android/lib/src/android_camera.dart +++ b/packages/camera/camera_android/lib/src/android_camera.dart @@ -248,25 +248,13 @@ class AndroidCamera extends CameraPlatform { @override Future startVideoRecording(int cameraId, {Duration? maxVideoDuration}) async { - return startVideoCapturing( - VideoCaptureOptions(cameraId, maxDuration: maxVideoDuration)); - } - - @override - Future startVideoCapturing(VideoCaptureOptions options) async { await _channel.invokeMethod( 'startVideoRecording', { - 'cameraId': options.cameraId, - 'maxVideoDuration': options.maxDuration?.inMilliseconds, - 'enableStream': options.streamCallback != null, + 'cameraId': cameraId, + 'maxVideoDuration': maxVideoDuration?.inMilliseconds, }, ); - - if (options.streamCallback != null) { - _installStreamController().stream.listen(options.streamCallback); - _startStreamListener(); - } } @override @@ -302,19 +290,13 @@ class AndroidCamera extends CameraPlatform { @override Stream onStreamedFrameAvailable(int cameraId, {CameraImageStreamOptions? options}) { - _installStreamController(onListen: _onFrameStreamListen); - return _frameStreamController!.stream; - } - - StreamController _installStreamController( - {Function()? onListen}) { _frameStreamController = StreamController( - onListen: onListen ?? () {}, + onListen: _onFrameStreamListen, onPause: _onFrameStreamPauseResume, onResume: _onFrameStreamPauseResume, onCancel: _onFrameStreamCancel, ); - return _frameStreamController!; + return _frameStreamController!.stream; } void _onFrameStreamListen() { @@ -323,10 +305,6 @@ class AndroidCamera extends CameraPlatform { Future _startPlatformStream() async { await _channel.invokeMethod('startImageStream'); - _startStreamListener(); - } - - void _startStreamListener() { const EventChannel cameraEventChannel = EventChannel('plugins.flutter.io/camera_android/imageStream'); _platformImageStreamSubscription = diff --git a/packages/camera/camera_android/pubspec.yaml b/packages/camera/camera_android/pubspec.yaml index 7ed5077c315e..6aa78268cb00 100644 --- a/packages/camera/camera_android/pubspec.yaml +++ b/packages/camera/camera_android/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_android description: Android implementation of the camera plugin. repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.10.1 +version: 0.10.0+5 environment: sdk: ">=2.14.0 <3.0.0" @@ -18,7 +18,7 @@ flutter: dartPluginClass: AndroidCamera dependencies: - camera_platform_interface: ^2.3.1 + camera_platform_interface: ^2.2.0 flutter: sdk: flutter flutter_plugin_android_lifecycle: ^2.0.2 diff --git a/packages/camera/camera_android/test/android_camera_test.dart b/packages/camera/camera_android/test/android_camera_test.dart index e35d0fd1beb4..3e50e6918648 100644 --- a/packages/camera/camera_android/test/android_camera_test.dart +++ b/packages/camera/camera_android/test/android_camera_test.dart @@ -587,7 +587,6 @@ void main() { isMethodCall('startVideoRecording', arguments: { 'cameraId': cameraId, 'maxVideoDuration': null, - 'enableStream': false, }), ]); }); @@ -610,33 +609,7 @@ void main() { expect(channel.log, [ isMethodCall('startVideoRecording', arguments: { 'cameraId': cameraId, - 'maxVideoDuration': 10000, - 'enableStream': false, - }), - ]); - }); - - test( - 'Should pass enableStream if callback is passed when starting recording a video', - () async { - // Arrange - final MethodChannelMock channel = MethodChannelMock( - channelName: _channelName, - methods: {'startVideoRecording': null}, - ); - - // Act - await camera.startVideoCapturing( - VideoCaptureOptions(cameraId, - streamCallback: (CameraImageData imageData) {}), - ); - - // Assert - expect(channel.log, [ - isMethodCall('startVideoRecording', arguments: { - 'cameraId': cameraId, - 'maxVideoDuration': null, - 'enableStream': true, + 'maxVideoDuration': 10000 }), ]); }); diff --git a/packages/camera/camera_avfoundation/CHANGELOG.md b/packages/camera/camera_avfoundation/CHANGELOG.md index 641272af2246..12d9a53ea248 100644 --- a/packages/camera/camera_avfoundation/CHANGELOG.md +++ b/packages/camera/camera_avfoundation/CHANGELOG.md @@ -1,7 +1,3 @@ -## 0.9.9 - -* Implements option to also stream when recording a video. - ## 0.9.8+6 * Updates code for `no_leading_underscores_for_local_identifiers` lint. diff --git a/packages/camera/camera_avfoundation/example/integration_test/camera_test.dart b/packages/camera/camera_avfoundation/example/integration_test/camera_test.dart index 2b23d82e619f..3e62edc2c495 100644 --- a/packages/camera/camera_avfoundation/example/integration_test/camera_test.dart +++ b/packages/camera/camera_avfoundation/example/integration_test/camera_test.dart @@ -253,33 +253,4 @@ void main() { expect(image.planes.length, 1); }, ); - - testWidgets('Recording with video streaming', (WidgetTester tester) async { - final List cameras = - await CameraPlatform.instance.availableCameras(); - if (cameras.isEmpty) { - return; - } - - final CameraController controller = CameraController( - cameras[0], - ResolutionPreset.low, - enableAudio: false, - ); - - await controller.initialize(); - await controller.prepareForVideoRecording(); - final Completer completer = Completer(); - await controller.startVideoRecording( - streamCallback: (CameraImageData image) { - if (!completer.isCompleted) { - completer.complete(image); - } - }); - sleep(const Duration(milliseconds: 500)); - await controller.stopVideoRecording(); - await controller.dispose(); - - expect(await completer.future, isNotNull); - }); } diff --git a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart index 2fcd868934fb..09441cc5449c 100644 --- a/packages/camera/camera_avfoundation/example/lib/camera_controller.dart +++ b/packages/camera/camera_avfoundation/example/lib/camera_controller.dart @@ -306,14 +306,11 @@ class CameraController extends ValueNotifier { /// /// The video is returned as a [XFile] after calling [stopVideoRecording]. /// Throws a [CameraException] if the capture fails. - Future startVideoRecording( - {Function(CameraImageData image)? streamCallback}) async { - await CameraPlatform.instance.startVideoCapturing( - VideoCaptureOptions(_cameraId, streamCallback: streamCallback)); + Future startVideoRecording() async { + await CameraPlatform.instance.startVideoRecording(_cameraId); value = value.copyWith( isRecordingVideo: true, isRecordingPaused: false, - isStreamingImages: streamCallback != null, recordingOrientation: Optional.of( value.lockedCaptureOrientation ?? value.deviceOrientation)); } @@ -322,10 +319,6 @@ class CameraController extends ValueNotifier { /// /// Throws a [CameraException] if the capture failed. Future stopVideoRecording() async { - if (value.isStreamingImages) { - await stopImageStream(); - } - final XFile file = await CameraPlatform.instance.stopVideoRecording(_cameraId); value = value.copyWith( diff --git a/packages/camera/camera_avfoundation/ios/Classes/CameraPlugin.m b/packages/camera/camera_avfoundation/ios/Classes/CameraPlugin.m index b85f68d1f957..628211ac7f7a 100644 --- a/packages/camera/camera_avfoundation/ios/Classes/CameraPlugin.m +++ b/packages/camera/camera_avfoundation/ios/Classes/CameraPlugin.m @@ -201,12 +201,7 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call [self.camera setUpCaptureSessionForAudio]; [result sendSuccess]; } else if ([@"startVideoRecording" isEqualToString:call.method]) { - BOOL enableStream = [call.arguments[@"enableStream"] boolValue]; - if (enableStream) { - [_camera startVideoRecordingWithResult:result messengerForStreaming:_messenger]; - } else { - [_camera startVideoRecordingWithResult:result]; - } + [_camera startVideoRecordingWithResult:result]; } else if ([@"stopVideoRecording" isEqualToString:call.method]) { [_camera stopVideoRecordingWithResult:result]; } else if ([@"pauseVideoRecording" isEqualToString:call.method]) { diff --git a/packages/camera/camera_avfoundation/ios/Classes/FLTCam.h b/packages/camera/camera_avfoundation/ios/Classes/FLTCam.h index 85b8e2ae06f2..8a5dafaf8354 100644 --- a/packages/camera/camera_avfoundation/ios/Classes/FLTCam.h +++ b/packages/camera/camera_avfoundation/ios/Classes/FLTCam.h @@ -50,15 +50,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)captureToFile:(FLTThreadSafeFlutterResult *)result API_AVAILABLE(ios(10)); - (void)close; - (void)startVideoRecordingWithResult:(FLTThreadSafeFlutterResult *)result; -/** - * Starts recording a video with an optional streaming messenger. - * If the messenger is non-null then it will be called for each - * captured frame, allowing streaming concurrently with recording. - * - * @param messenger Nullable messenger for capturing each frame. - */ -- (void)startVideoRecordingWithResult:(FLTThreadSafeFlutterResult *)result - messengerForStreaming:(nullable NSObject *)messenger; - (void)stopVideoRecordingWithResult:(FLTThreadSafeFlutterResult *)result; - (void)pauseVideoRecordingWithResult:(FLTThreadSafeFlutterResult *)result; - (void)resumeVideoRecordingWithResult:(FLTThreadSafeFlutterResult *)result; diff --git a/packages/camera/camera_avfoundation/ios/Classes/FLTCam.m b/packages/camera/camera_avfoundation/ios/Classes/FLTCam.m index a7d6cd24be3c..90b81adbd84c 100644 --- a/packages/camera/camera_avfoundation/ios/Classes/FLTCam.m +++ b/packages/camera/camera_avfoundation/ios/Classes/FLTCam.m @@ -623,16 +623,7 @@ - (CVPixelBufferRef)copyPixelBuffer { } - (void)startVideoRecordingWithResult:(FLTThreadSafeFlutterResult *)result { - [self startVideoRecordingWithResult:result messengerForStreaming:nil]; -} - -- (void)startVideoRecordingWithResult:(FLTThreadSafeFlutterResult *)result - messengerForStreaming:(nullable NSObject *)messenger { if (!_isRecording) { - if (messenger != nil) { - [self startImageStreamWithMessenger:messenger]; - } - NSError *error; _videoRecordingPath = [self getTemporaryFilePathWithExtension:@"mp4" subfolder:@"videos" diff --git a/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart b/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart index 011616d2d9f4..9bdadfb4536f 100644 --- a/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart +++ b/packages/camera/camera_avfoundation/lib/src/avfoundation_camera.dart @@ -248,26 +248,13 @@ class AVFoundationCamera extends CameraPlatform { @override Future startVideoRecording(int cameraId, {Duration? maxVideoDuration}) async { - return startVideoCapturing( - VideoCaptureOptions(cameraId, maxDuration: maxVideoDuration)); - } - - @override - Future startVideoCapturing(VideoCaptureOptions options) async { await _channel.invokeMethod( 'startVideoRecording', { - 'cameraId': options.cameraId, - 'maxVideoDuration': options.maxDuration?.inMilliseconds, - 'enableStream': options.streamCallback != null, + 'cameraId': cameraId, + 'maxVideoDuration': maxVideoDuration?.inMilliseconds, }, ); - - if (options.streamCallback != null) { - _frameStreamController = _createStreamController(); - _frameStreamController!.stream.listen(options.streamCallback); - _startStreamListener(); - } } @override @@ -303,19 +290,13 @@ class AVFoundationCamera extends CameraPlatform { @override Stream onStreamedFrameAvailable(int cameraId, {CameraImageStreamOptions? options}) { - _frameStreamController = - _createStreamController(onListen: _onFrameStreamListen); - return _frameStreamController!.stream; - } - - StreamController _createStreamController( - {Function()? onListen}) { - return StreamController( - onListen: onListen ?? () {}, + _frameStreamController = StreamController( + onListen: _onFrameStreamListen, onPause: _onFrameStreamPauseResume, onResume: _onFrameStreamPauseResume, onCancel: _onFrameStreamCancel, ); + return _frameStreamController!.stream; } void _onFrameStreamListen() { @@ -324,10 +305,6 @@ class AVFoundationCamera extends CameraPlatform { Future _startPlatformStream() async { await _channel.invokeMethod('startImageStream'); - _startStreamListener(); - } - - void _startStreamListener() { const EventChannel cameraEventChannel = EventChannel('plugins.flutter.io/camera_avfoundation/imageStream'); _platformImageStreamSubscription = diff --git a/packages/camera/camera_avfoundation/pubspec.yaml b/packages/camera/camera_avfoundation/pubspec.yaml index e60f5e406aad..f394d59e81d5 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/plugins/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.9 +version: 0.9.8+6 environment: sdk: ">=2.14.0 <3.0.0" @@ -17,7 +17,7 @@ flutter: dartPluginClass: AVFoundationCamera dependencies: - camera_platform_interface: ^2.3.1 + camera_platform_interface: ^2.2.0 flutter: sdk: flutter stream_transform: ^2.0.0 diff --git a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart index 8c5fad1fec8e..60109a4172b7 100644 --- a/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart +++ b/packages/camera/camera_avfoundation/test/avfoundation_camera_test.dart @@ -587,7 +587,6 @@ void main() { isMethodCall('startVideoRecording', arguments: { 'cameraId': cameraId, 'maxVideoDuration': null, - 'enableStream': false, }), ]); }); @@ -610,31 +609,7 @@ void main() { expect(channel.log, [ isMethodCall('startVideoRecording', arguments: { 'cameraId': cameraId, - 'maxVideoDuration': 10000, - 'enableStream': false, - }), - ]); - }); - - test( - 'Should pass enableStream if callback is passed when starting recording a video', - () async { - // Arrange - final MethodChannelMock channel = MethodChannelMock( - channelName: _channelName, - methods: {'startVideoRecording': null}, - ); - - // Act - await camera.startVideoCapturing(VideoCaptureOptions(cameraId, - streamCallback: (CameraImageData imageData) {})); - - // Assert - expect(channel.log, [ - isMethodCall('startVideoRecording', arguments: { - 'cameraId': cameraId, - 'maxVideoDuration': null, - 'enableStream': true, + 'maxVideoDuration': 10000 }), ]); }); diff --git a/packages/camera/camera_platform_interface/CHANGELOG.md b/packages/camera/camera_platform_interface/CHANGELOG.md index 5cde03c2e0db..9c93cf93887e 100644 --- a/packages/camera/camera_platform_interface/CHANGELOG.md +++ b/packages/camera/camera_platform_interface/CHANGELOG.md @@ -1,7 +1,3 @@ -## 2.3.2 - -* Updates MethodChannelCamera to have startVideoRecording call the newer startVideoCapturing. - ## 2.3.1 * Exports VideoCaptureOptions to allow dependencies to implement concurrent stream and record. 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 34c3fa2cca36..37c00d64ede2 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 @@ -240,25 +240,13 @@ class MethodChannelCamera extends CameraPlatform { @override Future startVideoRecording(int cameraId, {Duration? maxVideoDuration}) async { - return startVideoCapturing( - VideoCaptureOptions(cameraId, maxDuration: maxVideoDuration)); - } - - @override - Future startVideoCapturing(VideoCaptureOptions options) async { await _channel.invokeMethod( 'startVideoRecording', { - 'cameraId': options.cameraId, - 'maxVideoDuration': options.maxDuration?.inMilliseconds, - 'enableStream': options.streamCallback != null, + 'cameraId': cameraId, + 'maxVideoDuration': maxVideoDuration?.inMilliseconds, }, ); - - if (options.streamCallback != null) { - _installStreamController().stream.listen(options.streamCallback); - _startStreamListener(); - } } @override @@ -294,19 +282,13 @@ class MethodChannelCamera extends CameraPlatform { @override Stream onStreamedFrameAvailable(int cameraId, {CameraImageStreamOptions? options}) { - _installStreamController(onListen: _onFrameStreamListen); - return _frameStreamController!.stream; - } - - StreamController _installStreamController( - {Function()? onListen}) { _frameStreamController = StreamController( - onListen: onListen ?? () {}, + onListen: _onFrameStreamListen, onPause: _onFrameStreamPauseResume, onResume: _onFrameStreamPauseResume, onCancel: _onFrameStreamCancel, ); - return _frameStreamController!; + return _frameStreamController!.stream; } void _onFrameStreamListen() { @@ -315,10 +297,6 @@ class MethodChannelCamera extends CameraPlatform { Future _startPlatformStream() async { await _channel.invokeMethod('startImageStream'); - _startStreamListener(); - } - - void _startStreamListener() { const EventChannel cameraEventChannel = EventChannel('plugins.flutter.io/camera/imageStream'); _platformImageStreamSubscription = diff --git a/packages/camera/camera_platform_interface/pubspec.yaml b/packages/camera/camera_platform_interface/pubspec.yaml index cb21a6c7e09c..19642a0c958e 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/plugins/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.3.2 +version: 2.3.1 environment: sdk: '>=2.12.0 <3.0.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 a58f7b4c5841..60f42fd4af4a 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 @@ -569,7 +569,6 @@ void main() { isMethodCall('startVideoRecording', arguments: { 'cameraId': cameraId, 'maxVideoDuration': null, - 'enableStream': false, }), ]); }); @@ -592,8 +591,7 @@ void main() { expect(channel.log, [ isMethodCall('startVideoRecording', arguments: { 'cameraId': cameraId, - 'maxVideoDuration': 10000, - 'enableStream': false, + 'maxVideoDuration': 10000 }), ]); }); diff --git a/packages/camera/camera_web/CHANGELOG.md b/packages/camera/camera_web/CHANGELOG.md index d8d0c93dde11..f4989cfd5bff 100644 --- a/packages/camera/camera_web/CHANGELOG.md +++ b/packages/camera/camera_web/CHANGELOG.md @@ -1,7 +1,3 @@ -## 0.3.1 - -* Updates to latest camera platform interface, and fails if user attempts to use streaming with recording (since streaming is currently unsupported on web). - ## 0.3.0+1 * Updates imports for `prefer_relative_imports`. diff --git a/packages/camera/camera_web/example/integration_test/camera_web_test.dart b/packages/camera/camera_web/example/integration_test/camera_web_test.dart index 820a84be7207..8aefea6b2172 100644 --- a/packages/camera/camera_web/example/integration_test/camera_web_test.dart +++ b/packages/camera/camera_web/example/integration_test/camera_web_test.dart @@ -1191,33 +1191,6 @@ void main() { }); }); - group('startVideoCapturing', () { - late Camera camera; - - setUp(() { - camera = MockCamera(); - - when(camera.startVideoRecording).thenAnswer((Invocation _) async {}); - - when(() => camera.onVideoRecordingError) - .thenAnswer((Invocation _) => const Stream.empty()); - }); - - testWidgets('fails if trying to stream', (WidgetTester tester) async { - // Save the camera in the camera plugin. - (CameraPlatform.instance as CameraPlugin).cameras[cameraId] = camera; - - expect( - () => CameraPlatform.instance.startVideoCapturing(VideoCaptureOptions( - cameraId, - streamCallback: (CameraImageData imageData) {})), - throwsA( - isA(), - ), - ); - }); - }); - group('stopVideoRecording', () { testWidgets('stops a video recording', (WidgetTester tester) async { final MockCamera camera = MockCamera(); diff --git a/packages/camera/camera_web/lib/src/camera_web.dart b/packages/camera/camera_web/lib/src/camera_web.dart index 52fdc1c3f8d6..d440653cd424 100644 --- a/packages/camera/camera_web/lib/src/camera_web.dart +++ b/packages/camera/camera_web/lib/src/camera_web.dart @@ -451,33 +451,23 @@ class CameraPlugin extends CameraPlatform { @override Future startVideoRecording(int cameraId, {Duration? maxVideoDuration}) { - return startVideoCapturing( - VideoCaptureOptions(cameraId, maxDuration: maxVideoDuration)); - } - - @override - Future startVideoCapturing(VideoCaptureOptions options) { - if (options.streamCallback != null || options.streamOptions != null) { - throw UnimplementedError('Streaming is not currently supported on web'); - } - try { - final Camera camera = getCamera(options.cameraId); + final Camera camera = getCamera(cameraId); // Add camera's video recording errors to the camera events stream. // The error event fires when the video recording is not allowed or an unsupported // codec is used. - _cameraVideoRecordingErrorSubscriptions[options.cameraId] = + _cameraVideoRecordingErrorSubscriptions[cameraId] = camera.onVideoRecordingError.listen((html.ErrorEvent errorEvent) { cameraEventStreamController.add( CameraErrorEvent( - options.cameraId, + cameraId, 'Error code: ${errorEvent.type}, error message: ${errorEvent.message}.', ), ); }); - return camera.startVideoRecording(maxVideoDuration: options.maxDuration); + return camera.startVideoRecording(maxVideoDuration: maxVideoDuration); } on html.DomException catch (e) { throw PlatformException(code: e.name, message: e.message); } on CameraWebException catch (e) { diff --git a/packages/camera/camera_web/pubspec.yaml b/packages/camera/camera_web/pubspec.yaml index 2368e62abee6..ef9c45c71796 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/plugins/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.1 +version: 0.3.0+1 environment: sdk: ">=2.12.0 <3.0.0" @@ -17,7 +17,7 @@ flutter: fileName: camera_web.dart dependencies: - camera_platform_interface: ^2.3.1 + camera_platform_interface: ^2.1.0 flutter: sdk: flutter flutter_web_plugins: diff --git a/packages/camera/camera_windows/CHANGELOG.md b/packages/camera/camera_windows/CHANGELOG.md index f46bb667735f..71c5d56524a6 100644 --- a/packages/camera/camera_windows/CHANGELOG.md +++ b/packages/camera/camera_windows/CHANGELOG.md @@ -1,7 +1,3 @@ -## 0.2.1+3 - -* Updates to latest camera platform interface but fails if user attempts to use streaming with recording (since streaming is currently unsupported on Windows). - ## 0.2.1+2 * Updates code for `no_leading_underscores_for_local_identifiers` lint. diff --git a/packages/camera/camera_windows/lib/camera_windows.dart b/packages/camera/camera_windows/lib/camera_windows.dart index 79dd305e2e14..14134479994b 100644 --- a/packages/camera/camera_windows/lib/camera_windows.dart +++ b/packages/camera/camera_windows/lib/camera_windows.dart @@ -214,24 +214,15 @@ class CameraWindows extends CameraPlatform { pluginChannel.invokeMethod('prepareForVideoRecording'); @override - Future startVideoRecording(int cameraId, - {Duration? maxVideoDuration}) async { - return startVideoCapturing( - VideoCaptureOptions(cameraId, maxDuration: maxVideoDuration)); - } - - @override - Future startVideoCapturing(VideoCaptureOptions options) async { - if (options.streamCallback != null || options.streamOptions != null) { - throw UnimplementedError( - 'Streaming is not currently supported on Windows'); - } - + Future startVideoRecording( + int cameraId, { + Duration? maxVideoDuration, + }) async { await pluginChannel.invokeMethod( 'startVideoRecording', { - 'cameraId': options.cameraId, - 'maxVideoDuration': options.maxDuration?.inMilliseconds, + 'cameraId': cameraId, + 'maxVideoDuration': maxVideoDuration?.inMilliseconds, }, ); } diff --git a/packages/camera/camera_windows/pubspec.yaml b/packages/camera/camera_windows/pubspec.yaml index 523ee14d186e..1eab9fa108ef 100644 --- a/packages/camera/camera_windows/pubspec.yaml +++ b/packages/camera/camera_windows/pubspec.yaml @@ -2,7 +2,7 @@ name: camera_windows description: A Flutter plugin for getting information about and controlling the camera on Windows. repository: https://github.com/flutter/plugins/tree/main/packages/camera/camera_windows issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.2.1+3 +version: 0.2.1+2 environment: sdk: ">=2.12.0 <3.0.0" @@ -17,7 +17,7 @@ flutter: dartPluginClass: CameraWindows dependencies: - camera_platform_interface: ^2.3.1 + camera_platform_interface: ^2.1.2 cross_file: ^0.3.1 flutter: sdk: flutter diff --git a/packages/camera/camera_windows/test/camera_windows_test.dart b/packages/camera/camera_windows/test/camera_windows_test.dart index 615020e9f17d..c1a0fe40325f 100644 --- a/packages/camera/camera_windows/test/camera_windows_test.dart +++ b/packages/camera/camera_windows/test/camera_windows_test.dart @@ -447,15 +447,6 @@ void main() { ]); }); - test('capturing fails if trying to stream', () async { - // Act and Assert - expect( - () => plugin.startVideoCapturing(VideoCaptureOptions(cameraId, - streamCallback: (CameraImageData imageData) {})), - throwsA(isA()), - ); - }); - test('Should stop a video recording and return the file', () async { // Arrange final MethodChannelMock channel = MethodChannelMock(