Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 4f8587f

Browse files
committed
use canvaskit toByteData for unsupported videoFrame formats
1 parent 3626c48 commit 4f8587f

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

lib/web_ui/lib/src/engine/canvaskit/image.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,8 @@ class CkImage implements ui.Image, StackTraceDebugger {
376376
ui.ImageByteFormat format = ui.ImageByteFormat.rawRgba,
377377
}) {
378378
assert(_debugCheckIsNotDisposed());
379-
if (videoFrame != null) {
379+
// Web codecs do not support I420, I444, I422 videoFrame formats.
380+
if (videoFrame != null && videoFrame!.format != 'I420' && videoFrame!.format != 'I444' && videoFrame!.format != 'I422') {
380381
return readPixelsFromVideoFrame(videoFrame!, format);
381382
} else {
382383
return _readPixelsFromSkImage(format);

lib/web_ui/test/canvaskit/image_golden_test.dart

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,57 @@ void _testForImageCodecs({required bool useBrowserImageDecoder}) {
192192
testCollector.collectNow();
193193
});
194194

195+
test('toByteData with decodeImageFromPixels on videoFrame formats', () async {
196+
// This test ensures that toByteData() returns pixels that can be used by decodeImageFromPixels
197+
// for the following videoFrame formats:
198+
// [BGRX, I422, I420, I444, BGRA]
199+
final DomResponse listingResponse = await httpFetch('/test_images/');
200+
final List<String> testFiles = (await listingResponse.json() as List<dynamic>).cast<String>();
201+
202+
Future<ui.Image> testDecodeFromPixels(Uint8List pixels, int width, int height) async {
203+
final Completer<ui.Image> completer = Completer<ui.Image>();
204+
ui.decodeImageFromPixels(
205+
pixels,
206+
width,
207+
height,
208+
ui.PixelFormat.rgba8888,
209+
(ui.Image image) {
210+
completer.complete(image);
211+
},
212+
);
213+
return completer.future;
214+
}
215+
216+
// Sanity-check the test file list. If suddenly test files are moved or
217+
// deleted, and the test server returns an empty list, or is missing some
218+
// important test files, we want to know.
219+
expect(testFiles, isNotEmpty);
220+
expect(testFiles, contains(matches(RegExp(r'.*\.jpg'))));
221+
expect(testFiles, contains(matches(RegExp(r'.*\.png'))));
222+
expect(testFiles, contains(matches(RegExp(r'.*\.gif'))));
223+
expect(testFiles, contains(matches(RegExp(r'.*\.webp'))));
224+
expect(testFiles, contains(matches(RegExp(r'.*\.bmp'))));
225+
226+
for (final String testFile in testFiles) {
227+
final DomResponse imageResponse = await httpFetch('/test_images/$testFile');
228+
final Uint8List imageData = (await imageResponse.arrayBuffer() as ByteBuffer).asUint8List();
229+
final ui.Codec codec = await skiaInstantiateImageCodec(imageData);
230+
expect(codec.frameCount, greaterThan(0));
231+
expect(codec.repetitionCount, isNotNull);
232+
233+
final ui.FrameInfo frame = await codec.getNextFrame();
234+
final CkImage ckImage = frame.image as CkImage;
235+
final ByteData imageBytes = await ckImage.toByteData();
236+
expect(imageBytes.lengthInBytes, greaterThan(0));
237+
238+
final Uint8List pixels = imageBytes.buffer.asUint8List();
239+
final ui.Image testImage = await testDecodeFromPixels(pixels, ckImage.width, ckImage.height);
240+
expect(testImage, isNotNull);
241+
codec.dispose();
242+
}
243+
// TODO(hterkelsen): Firefox and Safari do not currently support ImageDecoder.
244+
}, skip: isFirefox || isSafari);
245+
195246
test('CkImage.clone also clones the VideoFrame', () async {
196247
final CkBrowserImageDecoder image = await CkBrowserImageDecoder.create(
197248
data: kAnimatedGif,

0 commit comments

Comments
 (0)