| // META: global=window,dedicatedworker | |
| // META: script=/webcodecs/utils.js | |
| const detachedArrayBuffer = new ArrayBuffer(4); | |
| var b = detachedArrayBuffer.transferToFixedLength(); | |
| const invalidConfigs = [ | |
| { | |
| comment: 'Missing codec', | |
| config: {}, | |
| }, | |
| { | |
| comment: 'Empty codec', | |
| config: {codec: ''}, | |
| }, | |
| { | |
| comment: 'Valid codec, detached description', | |
| config: {codec: 'vp8', description: detachedArrayBuffer}, | |
| }, | |
| ]; // invalidConfigs | |
| 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); | |
| }); | |
| const arrayBuffer = new ArrayBuffer(12583); | |
| const arrayBufferView = new DataView(arrayBuffer); | |
| const validButUnsupportedConfigs = [ | |
| { | |
| comment: 'Unrecognized codec', | |
| config: {codec: 'bogus'}, | |
| }, | |
| { | |
| comment: 'Unrecognized codec with dataview description', | |
| config: { | |
| codec: '7ﷺ۹.9', | |
| description: arrayBufferView, | |
| }, | |
| }, | |
| { | |
| comment: 'Audio codec', | |
| config: {codec: 'vorbis'}, | |
| }, | |
| { | |
| comment: 'Ambiguous codec', | |
| config: {codec: 'vp9'}, | |
| }, | |
| { | |
| comment: 'Codec with bad casing', | |
| config: {codec: 'Vp09.00.10.08'}, | |
| }, | |
| { | |
| comment: 'Codec with MIME type', | |
| config: {codec: 'video/webm; codecs="vp8"'}, | |
| }, | |
| { | |
| comment: 'Possible future H264 codec string', | |
| config: {codec: 'avc1.FF000b'}, | |
| }, | |
| { | |
| comment: 'Possible future H264 codec string (level 2.9)', | |
| config: {codec: 'avc1.4D401D'}, | |
| }, | |
| { | |
| comment: 'Possible future HEVC codec string', | |
| config: {codec: 'hvc1.C99.6FFFFFF.L93'}, | |
| }, | |
| { | |
| comment: 'Possible future VP9 codec string', | |
| config: {codec: 'vp09.99.99.08'}, | |
| }, | |
| { | |
| comment: 'Possible future AV1 codec string', | |
| config: {codec: 'av01.9.99M.08'}, | |
| }, | |
| { | |
| comment: 'codec with spaces', | |
| config: {codec: ' vp09.00.10.08 '}, | |
| }, | |
| ]; // validButUnsupportedConfigs | |
| validButUnsupportedConfigs.forEach(entry => { | |
| promise_test( | |
| t => { | |
| return VideoDecoder.isConfigSupported(entry.config).then(support => { | |
| assert_false(support.supported); | |
| }); | |
| }, | |
| 'Test that VideoDecoder.isConfigSupported() doesn\'t support config: ' + | |
| entry.comment); | |
| }); | |
| validButUnsupportedConfigs.forEach(entry => { | |
| promise_test( | |
| t => { | |
| let isErrorCallbackCalled = false; | |
| let codec = new VideoDecoder({ | |
| output: t.unreached_func('unexpected output'), | |
| error: t.step_func(e => { | |
| isErrorCallbackCalled = true; | |
| assert_true(e instanceof DOMException); | |
| assert_equals(e.name, 'NotSupportedError'); | |
| assert_equals(codec.state, 'closed', 'state'); | |
| }) | |
| }); | |
| codec.configure(entry.config); | |
| return codec.flush() | |
| .then(t.unreached_func('flush succeeded unexpectedly')) | |
| .catch(t.step_func(e => { | |
| assert_true(isErrorCallbackCalled, "isErrorCallbackCalled"); | |
| assert_true(e instanceof DOMException); | |
| assert_equals(e.name, 'NotSupportedError'); | |
| assert_equals(codec.state, 'closed', 'state'); | |
| })); | |
| }, | |
| 'Test that VideoDecoder.configure() doesn\'t support config: ' + | |
| entry.comment); | |
| }); | |
| promise_test(t => { | |
| // VideoDecoderInit lacks required fields. | |
| assert_throws_js(TypeError, () => { | |
| new VideoDecoder({}); | |
| }); | |
| // VideoDecoderInit has required fields. | |
| let decoder = new VideoDecoder(getDefaultCodecInit(t)); | |
| assert_equals(decoder.state, 'unconfigured'); | |
| decoder.close(); | |
| return endAfterEventLoopTurn(); | |
| }, 'Test VideoDecoder construction'); | |
| const validConfigs = [ | |
| { | |
| comment: 'variant 1 of h264 codec string', | |
| config: {codec: 'avc3.42001E'}, | |
| }, | |
| { | |
| comment: 'variant 2 of h264 codec string', | |
| config: {codec: 'avc1.42001E'}, | |
| }, | |
| ]; // validConfigs | |
| validConfigs.forEach(entry => { | |
| promise_test(async t => { | |
| try { | |
| await VideoDecoder.isConfigSupported(entry.config); | |
| var decoder = new VideoDecoder(getDefaultCodecInit(t)); | |
| // Something that works with all codecs: | |
| entry.config.width = 1280; | |
| entry.config.height = 720; | |
| decoder.configure(entry.config); | |
| return decoder | |
| .flush() | |
| .then( | |
| t.step_func(e => { | |
| assert_equals(decoder.state, 'configured', 'codec is configured'); | |
| }) | |
| ) | |
| .catch(t.unreached_func('flush succeeded unexpectedly')); | |
| } catch (e) { | |
| assert_true(false, entry.comment + ' should not throw'); | |
| } | |
| }, 'Test that VideoDecoder.isConfigSupported() accepts config:' + entry.comment); | |
| }); |