feat: implemented onStreamedFrameAvailable
diff --git a/packages/camera/camera_web/lib/src/camera.dart b/packages/camera/camera_web/lib/src/camera.dart index 210a0df..be01768 100644 --- a/packages/camera/camera_web/lib/src/camera.dart +++ b/packages/camera/camera_web/lib/src/camera.dart
@@ -230,20 +230,17 @@ /// Captures a picture and returns the saved file in a JPEG format. /// - /// Enables the camera flash (torch mode) for a period of taking a picture - /// if the flash mode is either [FlashMode.auto] or [FlashMode.always]. - Future<XFile> takePicture() async { - final bool shouldEnableTorchMode = - flashMode == FlashMode.auto || flashMode == FlashMode.always; - - if (shouldEnableTorchMode) { - _setTorchMode(enabled: true); - } - + /// The picture might be mirrored horizontally depending on the chosen camera. + /// + /// **NOTE**: It doesn't enable the camera flash (torch mode) when taking the picture. + /// If you want so, consider using [takePicture]. + Future<html.Blob> _takePicture() async { final int videoWidth = videoElement.videoWidth; final int videoHeight = videoElement.videoHeight; - final html.CanvasElement canvas = - html.CanvasElement(width: videoWidth, height: videoHeight); + final html.CanvasElement canvas = html.CanvasElement( + width: videoWidth, + height: videoHeight, + ); final bool isBackCamera = getLensDirection() == CameraLensDirection.back; // Flip the picture horizontally if it is not taken from a back camera. @@ -255,8 +252,22 @@ canvas.context2D .drawImageScaled(videoElement, 0, 0, videoWidth, videoHeight); + return await canvas.toBlob('image/jpeg'); + } - final html.Blob blob = await canvas.toBlob('image/jpeg'); + /// Captures a picture and returns the saved file in a JPEG format. + /// + /// Enables the camera flash (torch mode) for a period of taking a picture + /// if the flash mode is either [FlashMode.auto] or [FlashMode.always]. + Future<XFile> takePicture() async { + final bool shouldEnableTorchMode = + flashMode == FlashMode.auto || flashMode == FlashMode.always; + + if (shouldEnableTorchMode) { + _setTorchMode(enabled: true); + } + + final html.Blob blob = await _takePicture(); if (shouldEnableTorchMode) { _setTorchMode(enabled: false); @@ -578,6 +589,36 @@ return _videoAvailableCompleter!.future; } + late final StreamController<CameraImageData> _cameraFrameStreamController = + StreamController<CameraImageData>.broadcast(); + + /// Returns a stream of camera frames. + /// + /// To stop listening to new animation frames close all listening streams. + Stream<CameraImageData> cameraFrameStream({ + CameraImageStreamOptions? options, + }) { + final Stream<CameraImageData> stream = _cameraFrameStreamController.stream; + window!.requestAnimationFrame(_onAnimationFrame); + return stream; + } + + /// Called when a new animation frame is available. + Future<void> _onAnimationFrame([num? _]) async { + final html.Blob picture = await _takePicture(); + print('picture taken at ${DateTime.now()}'); + final CameraImageData cameraImageData = + _cameraService.getCameraImageDataFromBlob( + picture, + width: videoElement.videoWidth, + height: videoElement.videoHeight, + ); + _cameraFrameStreamController.add(cameraImageData); + + if (_cameraFrameStreamController.hasListener) + window!.requestAnimationFrame(_onAnimationFrame); + } + /// Disposes the camera by stopping the camera stream, /// the video recording and reloading the camera source. Future<void> dispose() async {
diff --git a/packages/camera/camera_web/lib/src/camera_service.dart b/packages/camera/camera_web/lib/src/camera_service.dart index 5f4a5fd..ed24101 100644 --- a/packages/camera/camera_web/lib/src/camera_service.dart +++ b/packages/camera/camera_web/lib/src/camera_service.dart
@@ -336,4 +336,20 @@ return DeviceOrientation.portraitUp; } } + + CameraImageData getCameraImageDataFromBlob( + html.Blob blob, { + required int height, + required int width, + }) { + return CameraImageData( + format: const CameraImageFormat( + ImageFormatGroup.jpeg, + raw: '', + ), + planes: [], + height: height, + width: width, + ); + } }
diff --git a/packages/camera/camera_web/lib/src/camera_web.dart b/packages/camera/camera_web/lib/src/camera_web.dart index 26f965d..a6ec84c 100644 --- a/packages/camera/camera_web/lib/src/camera_web.dart +++ b/packages/camera/camera_web/lib/src/camera_web.dart
@@ -689,4 +689,11 @@ ), ); } + + @override + Stream<CameraImageData> onStreamedFrameAvailable( + int cameraId, { + CameraImageStreamOptions? options, + }) => + getCamera(cameraId).cameraFrameStream(options: options); }