Implement VideoDecoder.isConfigSupported()
API and motivations described here:
https://github.com/WICG/web-codecs/issues/98
Spec PR here:
https://github.com/WICG/web-codecs/pull/120
Bug: 1141707
Test: new layout tests
Change-Id: I3e53da5961119b4b36ec76666ad1a67cca19b963
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2612684
Commit-Queue: Chrome Cunningham <chcunningham@chromium.org>
Reviewed-by: Thomas Guilbert <tguilbert@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841376}
diff --git a/webcodecs/video-decoder.any.js b/webcodecs/video-decoder.any.js
index 2dd85ad..33ea2db 100644
--- a/webcodecs/video-decoder.any.js
+++ b/webcodecs/video-decoder.any.js
@@ -4,7 +4,7 @@
// TODO(sandersd): Move metadata into a helper library.
// TODO(sandersd): Add H.264 decode test once there is an API to query for
// supported codecs.
-let h264 = {
+const h264 = {
async buffer() { return (await fetch('h264.mp4')).arrayBuffer(); },
codec: "avc1.64000c",
description: {offset: 7229, size: 46},
@@ -20,7 +20,7 @@
{offset: 6429, size: 281}]
};
-let vp9 = {
+const vp9 = {
async buffer() { return (await fetch('vp9.mp4')).arrayBuffer(); },
// TODO(sandersd): Verify that the file is actually level 1.
codec: "vp09.00.10.08",
@@ -36,6 +36,88 @@
{offset: 5193, size: 159}]
};
+const badCodecsList = [
+ '', // Empty codec
+ 'bogus', // Non exsitent codec
+ 'vorbis', // Audio codec
+ 'vp9', // Ambiguous codec
+ 'video/webm; codecs="vp9"' // Codec with mime type
+ ]
+
+const invalidConfigs = [
+ {
+ comment: 'Emtpy codec',
+ config: {codec: ''},
+ },
+ {
+ comment: 'Unrecognized codec',
+ config: {codec: 'bogus'},
+ },
+ {
+ comment: 'Audio codec',
+ config: {codec: 'vorbis'},
+ },
+ {
+ comment: 'Ambiguous codec',
+ config: {codec: 'vp9'},
+ },
+ {
+ comment: 'Codec with MIME type',
+ config: {codec: 'video/webm; codecs="vp8"'},
+ },
+ {
+ comment: 'Zero coded size',
+ config: {
+ codec: h264.codec,
+ codedWidth: 0,
+ codedHeight: 0,
+ },
+ },
+ {
+ comment: 'Out of bounds crop size caused by left/top offset',
+ config: {
+ codec: h264.codec,
+ codedWidth: 1920,
+ codedHeight: 1088,
+ cropLeft: 10,
+ cropTop: 10,
+ // When unspecified, these default to coded dimensions
+ // cropWidth: 1920,
+ // cropHeight: 1088
+ },
+ },
+ {
+ comment: 'Out of bounds crop size',
+ config: {
+ codec: h264.codec,
+ codedWidth: 1920,
+ codedHeight: 1088,
+ cropLeft: 10,
+ cropTop: 10,
+ cropWidth: 1920,
+ cropHeight: 1088,
+ },
+ },
+ {
+ comment: 'Way out of bounds crop size',
+ config: {
+ codec: h264.codec,
+ codedWidth: 1920,
+ codedHeight: 1088,
+ cropWidth: 4000,
+ cropHeight: 5000,
+ },
+ },
+ {
+ comment: 'Invalid display size',
+ config: {
+ codec: h264.codec,
+ displayWidth: 0,
+ displayHeight: 0,
+ },
+ },
+] // invalidConfigs
+
function view(buffer, {offset, size}) {
return new Uint8Array(buffer, offset, size);
}
@@ -48,6 +130,40 @@
});
}
+invalidConfigs.forEach(entry => {
+ promise_test(t => {
+ return promise_rejects_js(t, TypeError, VideoDecoder.isConfigSupported(entry.config));
+ }, 'Test that VideoDecoder.isConfigSupported() rejects invalid config:' + entry.comment);
+});
+
+invalidConfigs.forEach(entry => {
+ async_test(t => {
+ let codec = new VideoDecoder(getDefaultCodecInit(t));
+ assert_throws_js(TypeError, () => { codec.configure(entry.config); });
+ t.done();
+ }, 'Test that VideoDecoder.configure() rejects invalid config:' + entry.comment);
+});
+
+promise_test(t => {
+ return VideoDecoder.isConfigSupported({codec: vp9.codec});
+}, 'Test VideoDecoder.isConfigSupported() with minimal valid config');
+
+promise_test(t => {
+ // This config specifies a slight crop. H264 1080p content always crops
+ // because H264 coded dimensions are a multiple of 16 (e.g. 1088).
+ return VideoDecoder.isConfigSupported({
+ codec: h264.codec,
+ codedWidth: 1920,
+ codedHeight: 1088,
+ cropLeft: 0,
+ cropTop: 0,
+ cropWidth: 1920,
+ cropHeight: 1080,
+ displayWidth: 1920,
+ displayHeight: 1080
+ });
+}, 'Test VideoDecoder.isConfigSupported() with valid expanded config');
+
promise_test(t => {
// VideoDecoderInit lacks required fields.
assert_throws_js(TypeError, () => { new VideoDecoder({}); });
@@ -65,18 +181,12 @@
promise_test(t => {
let decoder = new VideoDecoder(getDefaultCodecInit(t));
- let badCodecsList = [
- '', // Empty codec
- 'bogus', // Non exsitent codec
- 'vorbis', // Audio codec
- 'vp9', // Ambiguous codec
- 'video/webm; codecs="vp9"' // Codec with mime type
- ]
-
+ // TODO(chcunningham): Remove badCodecsList testing. It's now covered more
+ // extensively by other tests.
testConfigurations(decoder, { codec: vp9.codec }, badCodecsList);
return endAfterEventLoopTurn();
-}, 'Test VideoDecoder.configure()');
+}, 'Test VideoDecoder.configure() with various codec strings');
promise_test(async t => {
let buffer = await vp9.buffer();