| // META: global=window,dedicatedworker | |
| // META: script=/webcodecs/utils.js | |
| const invalidConfigs = [ | |
| { | |
| comment: 'Missing codec', | |
| config: { | |
| width: 640, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'Empty codec', | |
| config: { | |
| codec: '', | |
| width: 640, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'Width is 0', | |
| config: { | |
| codec: 'vp8', | |
| width: 0, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'Height is 0', | |
| config: { | |
| codec: 'vp8', | |
| width: 640, | |
| height: 0, | |
| }, | |
| }, | |
| { | |
| comment: 'displayWidth is 0', | |
| config: { | |
| codec: 'vp8', | |
| displayWidth: 0, | |
| width: 640, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'displayHeight is 0', | |
| config: { | |
| codec: 'vp8', | |
| width: 640, | |
| displayHeight: 0, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'bitrate is present but zero', | |
| config: { | |
| codec: 'vp8', | |
| width: 640, | |
| height: 480, | |
| bitrate: 0 | |
| }, | |
| }, | |
| ]; | |
| invalidConfigs.forEach(entry => { | |
| promise_test( | |
| t => { | |
| return promise_rejects_js( | |
| t, TypeError, VideoEncoder.isConfigSupported(entry.config)); | |
| }, | |
| 'Test that VideoEncoder.isConfigSupported() rejects invalid config: ' + | |
| entry.comment); | |
| }); | |
| invalidConfigs.forEach(entry => { | |
| async_test( | |
| t => { | |
| let codec = new VideoEncoder(getDefaultCodecInit(t)); | |
| assert_throws_js(TypeError, () => { | |
| codec.configure(entry.config); | |
| }); | |
| t.done(); | |
| }, | |
| 'Test that VideoEncoder.configure() rejects invalid config: ' + | |
| entry.comment); | |
| }); | |
| const validButUnsupportedConfigs = [ | |
| { | |
| comment: 'Invalid scalability mode', | |
| config: {codec: 'vp8', width: 640, height: 480, scalabilityMode: 'ABC'} | |
| }, | |
| { | |
| comment: 'Unrecognized codec', | |
| config: { | |
| codec: 'bogus', | |
| width: 640, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'VP8 codec string not accepted by Web Codecs', | |
| config: { | |
| codec: 'vp08.00.10.08', | |
| width: 640, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'Codec with bad casing', | |
| config: { | |
| codec: 'vP8', | |
| width: 640, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'Width is too large', | |
| config: { | |
| codec: 'vp8', | |
| width: 1000000, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'Height is too large', | |
| config: { | |
| codec: 'vp8', | |
| width: 640, | |
| height: 1000000, | |
| }, | |
| }, | |
| { | |
| comment: 'Too strenuous accelerated encoding parameters', | |
| config: { | |
| codec: 'vp8', | |
| hardwareAcceleration: 'prefer-hardware', | |
| width: 30000, | |
| height: 30000, | |
| bitrate: 1, | |
| framerate: 240, | |
| } | |
| }, | |
| { | |
| comment: 'Odd sized frames for H264', | |
| config: { | |
| codec: 'avc1.42001E', | |
| width: 641, | |
| height: 480, | |
| bitrate: 1000000, | |
| framerate: 24, | |
| } | |
| }, | |
| { | |
| comment: 'Possible future H264 codec string', | |
| config: { | |
| codec: 'avc1.FF000b', | |
| width: 640, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'Possible future HEVC codec string', | |
| config: { | |
| codec: 'hvc1.C99.6FFFFFF.L93', | |
| width: 640, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'Possible future VP9 codec string', | |
| config: { | |
| codec: 'vp09.99.99.08', | |
| width: 640, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'Possible future AV1 codec string', | |
| config: { | |
| codec: 'av01.9.99M.08', | |
| width: 640, | |
| height: 480, | |
| }, | |
| }, | |
| { | |
| comment: 'codec with spaces', | |
| config: { | |
| codec: ' vp09.00.10.08 ', | |
| width: 640, | |
| height: 480, | |
| } | |
| } | |
| ]; | |
| validButUnsupportedConfigs.forEach(entry => { | |
| let config = entry.config; | |
| promise_test( | |
| async t => { | |
| let support = await VideoEncoder.isConfigSupported(config); | |
| assert_false(support.supported); | |
| let new_config = support.config; | |
| assert_equals(new_config.codec, config.codec); | |
| assert_equals(new_config.width, config.width); | |
| assert_equals(new_config.height, config.height); | |
| if (config.bitrate) | |
| assert_equals(new_config.bitrate, config.bitrate); | |
| if (config.framerate) | |
| assert_equals(new_config.framerate, config.framerate); | |
| }, | |
| 'Test that VideoEncoder.isConfigSupported() doesn\'t support config: ' + | |
| entry.comment); | |
| }); | |
| validButUnsupportedConfigs.forEach(entry => { | |
| promise_test( | |
| t => { | |
| let isErrorCallbackCalled = false; | |
| let codec = new VideoEncoder({ | |
| output: t.unreached_func('unexpected output'), | |
| error: t.step_func_done(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 VideoEncoder.configure() doesn\'t support config: ' + | |
| entry.comment); | |
| }); | |
| const validConfigs = [ | |
| { | |
| codec: 'avc1.42001E', | |
| hardwareAcceleration: 'no-preference', | |
| width: 640, | |
| height: 480, | |
| bitrate: 5000000, | |
| framerate: 24, | |
| avc: {format: 'annexb'}, | |
| futureConfigFeature: 'foo', | |
| }, | |
| { | |
| codec: 'vp8', | |
| hardwareAcceleration: 'no-preference', | |
| width: 800, | |
| height: 600, | |
| bitrate: 7000000, | |
| bitrateMode: 'variable', | |
| framerate: 60, | |
| scalabilityMode: 'L1T2', | |
| futureConfigFeature: 'foo', | |
| latencyMode: 'quality', | |
| avc: {format: 'annexb'} | |
| }, | |
| { | |
| codec: 'vp09.00.10.08', | |
| hardwareAcceleration: 'no-preference', | |
| width: 1280, | |
| height: 720, | |
| bitrate: 7000000, | |
| bitrateMode: 'constant', | |
| framerate: 25, | |
| futureConfigFeature: 'foo', | |
| latencyMode: 'realtime', | |
| alpha: 'discard' | |
| } | |
| ]; | |
| validConfigs.forEach(config => { | |
| promise_test(async t => { | |
| let support = await VideoEncoder.isConfigSupported(config); | |
| assert_implements_optional(support.supported); | |
| let new_config = support.config; | |
| assert_false(new_config.hasOwnProperty('futureConfigFeature')); | |
| assert_equals(new_config.codec, config.codec); | |
| assert_equals(new_config.width, config.width); | |
| assert_equals(new_config.height, config.height); | |
| if (config.bitrate) | |
| assert_equals(new_config.bitrate, config.bitrate); | |
| if (config.framerate) | |
| assert_equals(new_config.framerate, config.framerate); | |
| if (config.bitrateMode) | |
| assert_equals(new_config.bitrateMode, config.bitrateMode); | |
| if (config.latencyMode) | |
| assert_equals(new_config.latencyMode, config.latencyMode); | |
| if (config.alpha) | |
| assert_equals(new_config.alpha, config.alpha); | |
| if (config.avc) | |
| assert_equals(new_config.avc.format, config.avc.format); | |
| }, "VideoEncoder.isConfigSupported() supports:" + JSON.stringify(config)); | |
| }); |