Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
2552bdc
[camera/camera_web] Supporting camera stream on web
TecHaxter Mar 31, 2024
72a7127
[camera_web] Version and Changelog updated
TecHaxter Apr 22, 2024
d366566
[camera_web] - integration test updated: mock videoElement initialize…
TecHaxter Apr 23, 2024
4a18e22
[camera_web] - integration test updated: mock videoElement initialize…
TecHaxter Apr 23, 2024
b12f7e7
[camera_web] camera service takeFrame with better exception handelling
TecHaxter May 8, 2024
8697046
[camera_web] - integration test updated: mock videoElement initialize…
TecHaxter Apr 23, 2024
b42fbb9
[camera_web] camera service takeFrame with better exception handelling
TecHaxter May 8, 2024
b7b9342
[camera_web] tested takeFrame camera service function
TecHaxter May 8, 2024
8ec3a04
[camera_web] - integration test updated: mock videoElement initialize…
TecHaxter Apr 23, 2024
622841c
[camera_web] camera service takeFrame with better exception handelling
TecHaxter May 8, 2024
096ac4d
[camera_web] tested takeFrame camera service function
TecHaxter May 8, 2024
ed6f086
[camera_web] tested cameraFrameStream
TecHaxter May 8, 2024
d1244a0
[camera_web] - integration test updated: mock videoElement initialize…
TecHaxter Apr 23, 2024
d891a36
[camera_web] camera service takeFrame with better exception handelling
TecHaxter May 8, 2024
7dfb194
[camera_web] tested takeFrame camera service function
TecHaxter May 8, 2024
b9111cb
[camera_web] tested cameraFrameStream
TecHaxter May 8, 2024
f80cb03
[camera_web] platform version updated according to guidelines
TecHaxter May 8, 2024
41ac242
[camera_web] - integration test updated: mock videoElement initialize…
TecHaxter Apr 23, 2024
3edea8c
[camera_web] camera service takeFrame with better exception handelling
TecHaxter May 8, 2024
d1e4d95
[camera_web] tested takeFrame camera service function
TecHaxter May 8, 2024
86da719
[camera_web] tested cameraFrameStream
TecHaxter May 8, 2024
dcf48f9
[camera_web] platform version updated according to guidelines
TecHaxter May 8, 2024
7e01244
style: removed late from late final_cameraFrameStreamController
TecHaxter May 23, 2024
6d20e38
refactor: cameraFrameStream handles looping of animation frames
TecHaxter May 23, 2024
f56879e
refactor: saperated _triggerAnimationFramesLoop from cameraFrameStrea…
TecHaxter May 23, 2024
1e7c869
chore: can use off screen canvas constant
TecHaxter May 26, 2024
5b10bce
chore: removed unnecessary string interpolation from videoElement sty…
TecHaxter May 26, 2024
90bb72e
chore: reusing the OffscreenCanvas or CanvasElement depending on canU…
TecHaxter May 26, 2024
b196180
refactor: removed getCameraImageDataFromBytes to be used in-line
TecHaxter May 26, 2024
5c1c662
fix: setup hasPropertyOffScreenCanvas in tests
TecHaxter May 26, 2024
f484f02
chore: version and changelog updated
TecHaxter Jul 14, 2024
98bceb7
docs: removed "Streaming of frames" from Missing implementation
TecHaxter Jul 14, 2024
bf9c3fe
Revert "docs: removed "Streaming of frames" from Missing implementation"
TecHaxter Jul 14, 2024
f183b04
merge: branch 'main' flutter/packages + replaced dart:html import wit…
TecHaxter Oct 28, 2024
22cad65
fix: version bump
TecHaxter Oct 28, 2024
380c35b
fix: import organized in camera_test
TecHaxter Oct 28, 2024
e31fbf2
Merge branch 'main' of https://github.com/TecHaxter/flutter_packages …
TecHaxter Nov 1, 2024
cc818ba
[camera_web] fix: Changelog.md
TecHaxter Nov 1, 2024
a04a472
[camera_web] chore: imports organized for camera.dart
TecHaxter Nov 1, 2024
aa9a819
[camera_web] fix: CameraImageData constructed with unkown ImageFormat…
TecHaxter Nov 4, 2024
5941119
[camera_web]: chore: preserving animationFrameId from requestAnimatio…
TecHaxter Nov 4, 2024
3756949
[camera_web] chore: removed completer from _triggerAnimationFramesLoo…
TecHaxter Nov 4, 2024
74bb74e
[camera_web] fix: jsified willReadFrequently in getContext of Offscre…
TecHaxter Nov 4, 2024
54aa92e
[camera_web] chore: optimized frame rate by using simple arithmatic c…
TecHaxter Nov 4, 2024
e46ef6f
[camera_web] chore: removed canUseOffScreenCanvas named paramater fro…
TecHaxter Nov 4, 2024
5e7bb5e
[camera_web] chore: initializing canUseOffscreenCanvas from construct…
TecHaxter Nov 4, 2024
c48418b
[camera_web]: replaced dynamic with Object? in map value for willRead…
TecHaxter Nov 6, 2024
a0cd373
[camera_web] test: camera image stream test cases for with and withou…
TecHaxter Nov 6, 2024
d7b7d5c
[camera_web] test: camera frame stream test cases for with and withou…
TecHaxter Nov 6, 2024
6cd955a
Merge branch 'main' into camera_web_stream
TecHaxter Nov 6, 2024
a959df5
chore: updated animate function in _triggerAnimationFramesLoop to get…
TecHaxter Nov 12, 2024
526160b
Merge branch 'main' into camera_web_stream
TecHaxter Nov 12, 2024
98af1e3
Merge branch 'camera_web_stream' of https://github.com/TecHaxter/flut…
TecHaxter Nov 12, 2024
94954d1
Merge branch 'main' into camera_web_stream
TecHaxter Sep 21, 2025
006de9c
[camera_web] chore: addressed review comments
TecHaxter Sep 27, 2025
f5b3793
Merge branch 'main' into camera_web_stream
TecHaxter Sep 27, 2025
f0a1d27
[camera_web] fix: reformatting
TecHaxter Sep 27, 2025
def248d
[camera_web] fix: todo comment
TecHaxter Sep 27, 2025
1b5e9a1
[camera_web] fix: todo comment
TecHaxter Sep 27, 2025
33174ca
[camera_web] fix: reformatting
TecHaxter Sep 28, 2025
18d2a1a
Merge branch 'main' into camera_web_stream
TecHaxter Apr 3, 2026
08d33a8
[camera_web] chore: streaming frame time tolerance
TecHaxter Apr 3, 2026
cc1b895
[camera_web] docs: updated comment indentation
TecHaxter Apr 3, 2026
37a029e
[camera_web] chore: imageData late to final
TecHaxter Apr 3, 2026
0a3390a
[camera_web] chore: optimized offscreen canvas resize
TecHaxter Apr 3, 2026
19ec1c3
[camera_web] chore: optimized canvas element resize
TecHaxter Apr 3, 2026
526df97
[camera_web] perf: Reuse offscreen canvas context
TecHaxter Apr 3, 2026
e0ec25e
[camera_web] bump: camera_platform_interface
TecHaxter Apr 3, 2026
0c0d694
[camera_web] feat: enabled supportsImageStreaming to return true
TecHaxter Apr 3, 2026
f38e0b7
[camera_web] test: added test for supportsImageStreaming
TecHaxter Apr 3, 2026
6ac4c87
[camera_web] fix: changelog *
TecHaxter Apr 3, 2026
06ce8de
[camera_web]: fix lint issues
TecHaxter Apr 8, 2026
15f28b5
[camera_web] fix mockito mock code gen by removing const record
TecHaxter Apr 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/camera/camera_web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## NEXT
## 0.3.6

* Adds support for camera image stream on web.
* Updates minimum supported SDK version to Flutter 3.35/Dart 3.9.

## 0.3.5+3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,11 @@ void main() {
mockWindow.navigator = navigator;
mockNavigator.mediaDevices = mediaDevices;

final canvasElement = HTMLCanvasElement()
..width = videoSize.width.toInt()
..height = videoSize.height.toInt()
..context2D.clearRect(0, 0, videoSize.width, videoSize.height);
final canvasElement =
HTMLCanvasElement()
..width = videoSize.width.toInt()
..height = videoSize.height.toInt()
..context2D.clearRect(0, 0, videoSize.width, videoSize.height);

final videoElement = HTMLVideoElement();

Expand All @@ -91,6 +92,8 @@ void main() {
cameraService.getMediaStreamForOptions(options, cameraId: cameraId),
).thenAnswer((_) async => canvasElement.captureStream());

when(cameraService.hasPropertyOffScreenCanvas()).thenAnswer((_) => true);

final camera = Camera(
textureId: cameraId,
cameraService: cameraService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

// ignore_for_file: only_throw_errors

import 'dart:async';
import 'dart:js_interop';
import 'dart:js_interop_unsafe';

Expand Down Expand Up @@ -975,5 +976,55 @@ void main() {
);
});
});

group('camera image stream', () {
setUp(() {
cameraService = cameraService..jsUtil = jsUtil;
});
testWidgets('returns true if broswer has OffscreenCanvas '
'otherwise false', (WidgetTester widgetTester) async {
for (final supportsOffscreenCanvas in <bool>[true, false]) {
when(
jsUtil.hasProperty(window, 'OffscreenCanvas'.toJS),
).thenReturn(supportsOffscreenCanvas);
final bool hasOffScreenCanvas = cameraService
.hasPropertyOffScreenCanvas();
expect(
hasOffScreenCanvas,
supportsOffscreenCanvas ? isTrue : isFalse,
);
}
});
testWidgets('returns Camera Image of Size '
'when videoElement is of Size '
'regardless of OffscreenCanvas support', (
WidgetTester widgetTester,
) async {
const size = Size(10, 10);
final completer = Completer<void>();
final web.VideoElement videoElement =
getVideoElementWithBlankStream(size)
..onLoadedMetadata.listen((_) {
completer.complete();
})
..load();
await completer.future;
for (final supportsOffscreenCanvas in <bool>[true, false]) {
when(
jsUtil.hasProperty(window, 'OffscreenCanvas'.toJS),
).thenReturn(supportsOffscreenCanvas);
final CameraImageData cameraImageData = cameraService.takeFrame(
videoElement,
);
expect(
size,
Size(
cameraImageData.width.toDouble(),
cameraImageData.height.toDouble(),
),
);
}
});
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'dart:async';
import 'dart:js_interop';
import 'dart:js_interop_unsafe';
import 'dart:typed_data';
import 'dart:ui';

import 'package:async/async.dart';
Expand Down Expand Up @@ -61,6 +62,8 @@ void main() {
cameraId: anyNamed('cameraId'),
),
).thenAnswer((_) => Future<MediaStream>.value(mediaStream));

when(cameraService.hasPropertyOffScreenCanvas()).thenAnswer((_) => true);
});

group('initialize', () {
Expand Down Expand Up @@ -1537,5 +1540,52 @@ void main() {
});
});
});
group('cameraFrameStream', () {
testWidgets('CameraImageData bytes is a multiple of 4 '
'regardless of OffscreenCanvas support', (WidgetTester tester) async {
final VideoElement videoElement = getVideoElementWithBlankStream(
const Size(10, 10),
);
final camera = Camera(
textureId: textureId,
cameraService: cameraService,
)..videoElement = videoElement;

for (final supportsOffscreenCanvas in <bool>[true, false]) {
when(
cameraService.hasPropertyOffScreenCanvas(),
).thenReturn(supportsOffscreenCanvas);

when(cameraService.takeFrame(videoElement)).thenAnswer(
(_) => CameraImageData(
format: const CameraImageFormat(ImageFormatGroup.unknown, raw: 0),
planes: <CameraImagePlane>[
CameraImagePlane(
bytes: Uint8List(32),
bytesPerRow: videoElement.width * 4,
),
],
height: 10,
width: 10,
),
);

final CameraImageData cameraImageData = await camera
.cameraFrameStream()
.first;

expect(
cameraImageData,
equals(
isA<CameraImageData>().having(
(CameraImageData e) => e.planes.first.bytes.length % 4,
'bytes',
equals(0),
),
),
);
}
});
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ void main() {
),
).thenAnswer((_) async => videoElement.captureStream());

when(cameraService.hasPropertyOffScreenCanvas()).thenAnswer((_) => true);

CameraPlatform.instance = CameraPlugin(cameraService: cameraService)
..window = window;
});
Expand Down Expand Up @@ -2219,6 +2221,12 @@ void main() {
);
});

testWidgets('supportsImageStreaming returns true', (
WidgetTester tester,
) async {
expect(CameraPlatform.instance.supportsImageStreaming(), isTrue);
});

group('dispose', () {
late Camera camera;
late MockVideoElement mockVideoElement;
Expand Down
Loading