Skip to content

[camera_web] Re: Support for camera stream on web #7950

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 53 commits into
base: main
Choose a base branch
from

Conversation

TecHaxter
Copy link

This PR aims to provide support for strartImageStream and stopImageStream on Web.

#92460

Based on #6944 from the archived plugins repository

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [relevant style guides] and ran the auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages repo does use dart format.)
  • I signed the [CLA].
  • The title of the PR starts with the name of the package surrounded by square brackets, e.g. [shared_preferences]
  • I [linked to at least one issue that this PR fixes] in the description above.
  • I updated pubspec.yaml with an appropriate new version according to the [pub versioning philosophy], or this PR is [exempt from version changes].
  • I updated CHANGELOG.md to add a description of the change, [following repository CHANGELOG style].
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is [test-exempt].
  • All existing and new tests are passing.

POV: my first PR on a public repo
Contains required commits from the PR #6443, resolves unnecessary 202 commits

@github-actions github-actions bot removed the p: interactive_media_ads Plugin for IMA SDK label Oct 28, 2024
@ditman
Copy link
Member

ditman commented Oct 29, 2024

I'll re-review this tomorrow!

Copy link
Member

@ditman ditman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution @TecHaxter! This is getting close. I left some comments that should improve the performance of the frame capture (maybe hit 60fps!) and the accuracy of the image data reported.

Have you used this code in any demo app compiled for the web?

Comment on lines 3 to 4
* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.
- Supporting camera image stream on web.
- Updates minimum supported SDK version to Flutter 3.22/Dart 3.4.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably an automatic update/fix, but please don't change all the early changelog entries of this file, stick to the * for lists. This should simplify this file greatly.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed, can be marked as resolved?

@@ -106,6 +106,10 @@ void main() {
).thenAnswer(
(_) => Future<MediaStream>.value(canvasElement.captureStream()));

when(
() => cameraService.hasPropertyOffScreenCanvas(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to mock this? The code should be running on Chrome, which AFAIK has an offscreen canvas. What happens to this test if we revert this change?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cameraService is a mock class object itself.
If we don't stub hasPropertyOffScreenCanvas, it throws an error - "TypeError: null: type 'Null' is not a subtype of type 'bool'

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we mark this resolved?

await completer.future;
final CameraImageData cameraImageData = cameraService.takeFrame(
videoElement,
canUseOffscreenCanvas: true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need a test for canUseOffscreenCanvas: false

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed, can be marked as resolved?

Comment on lines +66 to +68
when(
() => cameraService.hasPropertyOffScreenCanvas(),
).thenAnswer((_) => true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above, we need a test where offscreen canvas is available, and one where it isn't, so we test both code paths.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed, can be marked as resolved?

)..videoElement = videoElement;

when(
() => cameraService.takeFrame(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're already mocking the videoElement, why are we mocking the cameraService too?

Copy link
Author

@TecHaxter TecHaxter Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cameraService is a mock class object itself.
If we don't stub hasPropertyOffScreenCanvas, it throws an error - "TypeError: null: type 'Null' is not a subtype of type 'bool'

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we mark this resolved?

@@ -6,7 +6,6 @@ import 'dart:async';
import 'dart:js_interop';
import 'dart:ui';
import 'dart:ui_web' as ui_web;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not delete this empty line please :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed, can be marked as resolved?

Comment on lines 676 to 677
Completer<void> completer = Completer<void>();
completer.complete();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this? Remove?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed, can be marked as resolved?

return;
}

if (!completer.isCompleted) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is always false, isn't it? The completer is being .complete()d unconditionally in line 677?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed the implementation of _triggerAnimationFramesLoop in upcoming commits.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed, can be marked as resolved?

Comment on lines 680 to 682
if (!_cameraFrameStreamController.hasListener) {
return;
}
Copy link
Member

@ditman ditman Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not control the stop of the animation like this. What you need to do is to keep the return value of window.requestAnimationFrame (which is an int), and then when the stream controller ceases to have any listeners (see StreamController.onCancel), call window.cancelAnimationFrame with the last ID returned by rAF.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fixed, can be marked as resolved?

Comment on lines 427 to 436
format: const CameraImageFormat(
ImageFormatGroup.jpeg,
raw: '',
),
planes: <CameraImagePlane>[
CameraImagePlane(
bytes: byteBuffer.asUint8List(),
bytesPerRow: 0,
),
],
Copy link
Member

@ditman ditman Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this CameraImageData correctly constructed?

First it says that this is a jpeg (which it isn't), and then puts it in the first plane, but we say it's "0 bytesPerRow".

My suggestions are:

More docs here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found FLEX_RGBA_8888 in Android and kCVPixelFormatType_32RGBA in iOS which looks promising for compatibility with RGBA 4 bytes per-pixel arranged image coming from ImageData of Canvas (Although I haven't tested it yet)

Also found a comment in \camera\camera_android_camerax\lib\src\android_camera_camerax.dart

  /// [imageFormatGroup] is used to specify the image format used for image
  /// streaming, but CameraX currently only supports YUV_420_888 (supported by
  /// Flutter) and RGBA (not supported by Flutter). CameraX uses YUV_420_888
  /// by default, so [imageFormatGroup] is not used.

Seeing this, I went with the values you suggested

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tested this in the example app of google_mediapipe_face_detection (code not pushed yet). It works like charm ✨✨

Can we mark this resolved?

@TecHaxter TecHaxter requested a review from ditman November 6, 2024 19:10
@TecHaxter
Copy link
Author

Hi @ditman The PR is ready for another review, Thanks :)

@stuartmorgan-g
Copy link
Contributor

From triage: Ping @ditman on this re-review.

@stuartmorgan-g stuartmorgan-g added the triage-web Should be looked at in web triage label Jan 14, 2025
@stuartmorgan-g
Copy link
Contributor

Update from triage: we're working through trying to find a web reviewer with availability to look at this. Apologies for the delay.

@Piinks
Copy link
Contributor

Piinks commented Jun 4, 2025

@yjbanov can you suggest a reviewer for this change? It has been blocked on a web review.

@mdebbar mdebbar self-requested a review June 11, 2025 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p: camera platform-web triage-web Should be looked at in web triage
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants