Commit 71d6ab0d authored by Thomas Guilbert's avatar Thomas Guilbert Committed by Commit Bot

Cleanup WebCodecs WPT

A lot of WebCodecs tests are using async_test, which lead to time outs
when there is an error, and potentially missed test failures.

Additionally, a lot of code verifying configs, and which calls are
allowed in which codec state are common to many test files. This CL
extracts some of common elements into its own utils file

Bug: 1094096, 1094182
Change-Id: I7dd6c9ab76959ed6adb86fd2e6bf94d21610838a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2389008
Commit-Queue: Thomas Guilbert <tguilbert@chromium.org>
Reviewed-by: default avatarPhilip Jägenstedt <foolip@chromium.org>
Cr-Commit-Position: refs/heads/master@{#804479}
parent 4df2ec50
......@@ -3,70 +3,14 @@
<title>Test the AudioDecoder API.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/webcodecs/utils.js"></script>
<script>
// Calls done after giving async output/error callbacks a final chance to run.
async function asyncDone(test) {
test.step_timeout(test.step_func_done(), 0);
}
async_test(async (t) => {
// AudioDecoderInit lacks required fields.
assert_throws_js(TypeError, () => { new AudioDecoder({}); });
// AudioDecoderInit has required fields.
let decoder = new AudioDecoder({
output(chunk) { t.unreached_func("Unexpected output").call(); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
asyncDone(t);
}, 'Test AudioDecoder construction');
async_test(async (t) => {
let decoder = new AudioDecoder({
output(chunk) { t.unreached_func("Unexpected output").call(); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
let config = {
sampleRate: 48000,
numberOfChannels: 2
}
assert_equals(decoder.state, "unconfigured");
// Empty codec rejected.
config.codec = '';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Invalid codec rejected.
config.codec = 'bogus';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Video codec rejected.
config.codec = 'vp8';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Codec with mime type rejected.
config.codec = 'audio/webm; codecs="opus"';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Valid audio codec accepted.
config.codec = 'opus';
decoder.configure(config);
assert_equals(decoder.state, "configured");
// Test we can configure after a reset.
decoder.reset()
assert_equals(decoder.state, "unconfigured");
decoder.configure(config);
assert_equals(decoder.state, "configured");
asyncDone(t);
}, 'Test AudioDecoder.configure() codec validity');
const defaultConfig = {
codec: "opus",
sampleRate: 48000,
numberOfChannels: 2
};
function getFakeChunk() {
return new EncodedAudioChunk({
......@@ -77,79 +21,44 @@ function getFakeChunk() {
}
promise_test(t => {
let decoder = new AudioDecoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
t.step(() => {
throw "unexpected error";
});
}
});
// AudioDecoderInit lacks required fields.
assert_throws_js(TypeError, () => { new AudioDecoder({}); });
// AudioDecoderInit has required fields.
let decoder = new AudioDecoder(getDefaultCodecInit(t));
assert_equals(decoder.state, "unconfigured");
decoder.close();
assert_equals(decoder.state, "closed");
let config = {
sampleRate: 48000,
numberOfChannels: 2,
codec: 'opus'
}
let fakeChunk = getFakeChunk();
assert_throws_dom("InvalidStateError",
() => decoder.configure(config),
"configure");
assert_throws_dom("InvalidStateError",
() => decoder.decode(fakeChunk),
"decode");
assert_throws_dom("InvalidStateError",
() => decoder.reset(),
"reset");
assert_throws_dom("InvalidStateError",
() => decoder.close(),
"close");
return promise_rejects_dom(t, 'InvalidStateError', decoder.flush(), 'flush');
}, 'Closed decoder');
return endAfterEventLoopTurn();
}, 'Test AudioDecoder construction');
promise_test(t => {
let decoder = new AudioDecoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
t.step(() => {
throw "unexpected error";
});
}
});
let decoder = new AudioDecoder(getDefaultCodecInit(t));
assert_equals(decoder.state, "unconfigured");
let badCodecsList = [
'', // Empty codec
'bogus', // Non exsitent codec
'vp8', // Video codec
'audio/webm; codecs="opus"' // Codec with mime type
]
// Reseting an unconfigured encoder is a no-op.
decoder.reset();
assert_equals(decoder.state, "unconfigured");
testConfigurations(decoder, defaultConfig, badCodecsList);
let config = {
sampleRate: 48000,
numberOfChannels: 2,
codec: 'opus'
}
return endAfterEventLoopTurn();
}, 'Test AudioDecoder.configure()');
let fakeChunk = getFakeChunk();
promise_test(t => {
let decoder = new AudioDecoder(getDefaultCodecInit(t));
return testClosedCodec(t, decoder, defaultConfig, getFakeChunk());
}, 'Verify closed AudioDecoder operations');
promise_test(t => {
let decoder = new AudioDecoder(getDefaultCodecInit(t));
assert_throws_dom("InvalidStateError",
() => decoder.decode(fakeChunk),
"decode");
return promise_rejects_dom(t, 'InvalidStateError', decoder.flush(), 'flush');
}, 'Unconfigured decoder');
return testUnconfiguredCodec(t, decoder, getFakeChunk());
}, 'Verify unconfigured AudioDecoder operations');
</script>
......
function makeImageBitmap(width, height) {
let canvas = new OffscreenCanvas(width, height);
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(50, 100, 150, 255)';
ctx.fillRect(0, 0, width, height);
return canvas.transferToImageBitmap();
}
// Gives a chance to pending output and error callbacks to complete before
// resolving.
function endAfterEventLoopTurn() {
return new Promise(resolve => step_timeout(resolve, 0));
}
// Returns a codec initialization with callbacks that expected to not be called.
function getDefaultCodecInit(test) {
return {
output: test.unreached_func("unexpected output"),
error: test.unreached_func("unexpected error"),
}
}
// Checks that codec can be configured, reset, reconfigured, and that incomplete
// or invalid configs throw errors immediately.
function testConfigurations(codec, validCondig, invalidCodecs) {
assert_equals(codec.state, "unconfigured");
const requiredConfigPairs = validCondig;
let incrementalConfig = {};
for (let key in requiredConfigPairs) {
// Configure should fail while required keys are missing.
assert_throws_js(TypeError, () => { codec.configure(incrementalConfig); });
incrementalConfig[key] = requiredConfigPairs[key];
assert_equals(codec.state, "unconfigured");
}
// Configure should pass once incrementalConfig meets all requirements.
codec.configure(incrementalConfig);
assert_equals(codec.state, "configured");
// We should be able to reconfigure the codec.
codec.configure(incrementalConfig);
assert_equals(codec.state, "configured");
let config = incrementalConfig;
invalidCodecs.forEach(badCodec => {
// Invalid codecs should fail.
config.codec = badCodec;
assert_throws_js(TypeError, () => { codec.configure(config); }, badCodec);
})
// The failed configures should not affect the current config.
assert_equals(codec.state, "configured");
// Test we can configure after a reset.
codec.reset()
assert_equals(codec.state, "unconfigured");
codec.configure(validCondig);
assert_equals(codec.state, "configured");
}
// Performs an encode or decode with the provided input, depending on whether
// the passed codec is an encoder or a decoder.
function encodeOrDecodeShouldThrow(codec, input) {
// We are testing encode/decode on codecs in invalid states.
assert_not_equals(codec.state, "configured");
if (codec.decode) {
assert_throws_dom("InvalidStateError",
() => codec.decode(input),
"decode");
} else if (codec.encode) {
// Encoders consume frames, so clone it to be safe.
assert_throws_dom("InvalidStateError",
() => codec.encode(input.clone()),
"encode");
} else {
assert_unreached("Codec should have encode or decode function");
}
}
// Makes sure that we cannot close, configure, reset, flush, decode or encode a
// closed codec.
function testClosedCodec(test, codec, validconfig, codecInput) {
assert_equals(codec.state, "unconfigured");
codec.close();
assert_equals(codec.state, "closed");
assert_throws_dom("InvalidStateError",
() => codec.configure(validconfig),
"configure");
assert_throws_dom("InvalidStateError",
() => codec.reset(),
"reset");
assert_throws_dom("InvalidStateError",
() => codec.close(),
"close");
encodeOrDecodeShouldThrow(codec, codecInput);
return promise_rejects_dom(test, 'InvalidStateError', codec.flush(), 'flush');
}
// Makes sure we cannot flush, encode or decode with an unconfigured coded, and
// that reset is a valid no-op.
function testUnconfiguredCodec(test, codec, codecInput) {
assert_equals(codec.state, "unconfigured");
// Configure() and Close() are valid operations that would transition us into
// a different state.
// Resetting an unconfigured encoder is a no-op.
codec.reset();
assert_equals(codec.state, "unconfigured");
encodeOrDecodeShouldThrow(codec, codecInput);
return promise_rejects_dom(test, 'InvalidStateError', codec.flush(), 'flush');
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
<title>Test the VideoDecoder API.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/webcodecs/utils.js"></script>
<script>
'use strict';
......@@ -10,7 +11,7 @@
// TODO(sandersd): Add H.264 idecode test once there is an API to query for
// supported codecs.
let h264 = {
buffer: fetch('h264.mp4').then(r => r.arrayBuffer()),
async buffer() { return (await fetch('h264.mp4')).arrayBuffer(); },
codec: "avc1.64000c",
description: {offset: 7229, size: 46},
frames: [{offset: 48, size: 4007},
......@@ -26,7 +27,7 @@ let h264 = {
};
let vp9 = {
buffer: fetch('vp9.mp4').then(r => r.arrayBuffer()),
async buffer() { return (await fetch('vp9.mp4')).arrayBuffer(); },
// TODO(sandersd): Verify that the file is actually level 1.
codec: "vp09.00.10.08",
frames: [{offset: 44, size: 3315},
......@@ -53,79 +54,39 @@ function getFakeChunk() {
});
}
// Calls done after giving async output/error callbacks a final chance to run.
async function asyncDone(test) {
test.step_timeout(test.step_func_done(), 0);
}
async_test(async (t) => {
promise_test(t => {
// VideoDecoderInit lacks required fields.
assert_throws_js(TypeError, () => { new VideoDecoder({}); });
// VideoDecoderInit has required fields.
let decoder = new VideoDecoder({
output(chunk) { t.unreached_func("Unexpected output").call(); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
let decoder = new VideoDecoder(getDefaultCodecInit(t));
assert_equals(decoder.state, "unconfigured");
asyncDone(t);
}, 'Test VideoDecoder construction');
async_test(async (t) => {
let decoder = new VideoDecoder({
output(chunk) { t.unreached_func("Unexpected output").call(); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
let config = {};
// Bogus codec rejected.
config.codec = 'bogus';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Audio codec rejected.
config.codec = 'vorbis';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Ambiguous codec rejected.
config.codec = 'vp9';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Codec with mime type rejected.
config.codec = 'video/webm; codecs="vp9"';
assert_throws_js(TypeError, () => { decoder.configure(config); });
// Valid unambiguous codec accepted.
config.codec = 'vp09.00.10.08';
decoder.configure(config);
assert_equals(decoder.state, "configured");
// Verify a failed reconfigure does not affect the current configuration.
config.codec = 'bogus';
assert_throws_js(TypeError, () => { decoder.configure(config); });
decoder.close();
assert_equals(decoder.state, "configured");
return endAfterEventLoopTurn();
}, 'Test VideoDecoder construction');
// Verify we can reconfigure.
config.codec = 'vp09.00.10.08';
decoder.configure(config);
promise_test(t => {
let decoder = new VideoDecoder(getDefaultCodecInit(t));
assert_equals(decoder.state, "configured");
let badCodecsList = [
'', // Empty codec
'bogus', // Non exsitent codec
'vorbis', // Audio codec
'vp9', // Ambiguous codec
'video/webm; codecs="vp9"' // Codec with mime type
]
// Test we can configure after a reset.
decoder.reset()
assert_equals(decoder.state, "unconfigured");
testConfigurations(decoder, { codec: vp9.codec }, badCodecsList);
decoder.configure(config);
assert_equals(decoder.state, "configured");
return endAfterEventLoopTurn();
}, 'Test VideoDecoder.configure()');
asyncDone(t);
}, 'Test VideoDecoder.configure() codec validity');
promise_test(async t => {
let buffer = await vp9.buffer();
promise_test(t => vp9.buffer.then(buffer => {
let numOutputs = 0;
let decoder = new VideoDecoder({
output(frame) {
......@@ -153,92 +114,36 @@ promise_test(t => vp9.buffer.then(buffer => {
data: view(buffer, vp9.frames[0])
}));
return decoder.flush().then(() => {
assert_equals(numOutputs, 1, "outputs");
});
}), 'Decode VP9');
await decoder.flush();
promise_test(t => {
let decoder = new VideoDecoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
t.step(() => {
throw "unexpected error";
});
}
});
decoder.close();
assert_equals(decoder.state, "closed");
let fakeChunk = getFakeChunk();
assert_throws_dom("InvalidStateError",
() => decoder.configure({codec: vp9.codec}),
"configure");
assert_throws_dom("InvalidStateError",
() => decoder.decode(fakeChunk),
"decode");
assert_throws_dom("InvalidStateError",
() => decoder.reset(),
"reset");
assert_throws_dom("InvalidStateError",
() => decoder.close(),
"close");
return promise_rejects_dom(t, 'InvalidStateError', decoder.flush(), 'flush');
}, 'Closed decoder');
assert_equals(numOutputs, 1, "outputs");
}, 'Decode VP9');
promise_test(t => {
let decoder = new VideoDecoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
t.step(() => {
throw "unexpected error";
});
}
});
let decoder = new VideoDecoder(getDefaultCodecInit(t));
assert_equals(decoder.state, "unconfigured");
return testClosedCodec(t, decoder, { codec: vp9.codec }, getFakeChunk());
}, 'Verify closed VideoDecoder operations');
// Reseting an unconfigured encoder is a no-op.
decoder.reset();
assert_equals(decoder.state, "unconfigured");
promise_test(t => {
let decoder = new VideoDecoder(getDefaultCodecInit(t));
let fakeChunk = getFakeChunk();
assert_throws_dom("InvalidStateError",
() => decoder.decode(fakeChunk),
"decode");
return promise_rejects_dom(t, 'InvalidStateError', decoder.flush(), 'flush');
}, 'Unconfigured decoder');
return testUnconfiguredCodec(t, decoder, getFakeChunk());
}, 'Verify unconfigured VideoDecoder operations');
promise_test(t => {
let numErrors = 0;
let decoder = new VideoDecoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
numErrors++;
}
});
let codecInit = getDefaultCodecInit(t);
codecInit.error = _ => numErrors++;
let decoder = new VideoDecoder(codecInit);
decoder.configure({codec: vp9.codec});
let fakeChunk = getFakeChunk();
decoder.decode(fakeChunk);
return decoder.flush().then(
() => { throw "flush succeeded unexpectedly"; },
return promise_rejects_exactly(t, undefined, decoder.flush()).then(
() => {
assert_equals(numErrors, 1, "errors");
assert_equals(decoder.state, "closed");
......@@ -247,41 +152,25 @@ promise_test(t => {
promise_test(t => {
let numErrors = 0;
let decoder = new VideoDecoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
numErrors++;
}
});
let codecInit = getDefaultCodecInit(t);
codecInit.error = _ => numErrors++;
let decoder = new VideoDecoder(codecInit);
decoder.configure({codec: vp9.codec});
let fakeChunk = getFakeChunk();
decoder.decode(fakeChunk);
return decoder.flush().then(
() => { throw "flush succeeded unexpectedly"; },
() => { assert_equals(numErrors, 1, "errors"); });
return promise_rejects_exactly(t, undefined, decoder.flush()).then(
() => {
assert_equals(numErrors, 1, "errors");
assert_equals(decoder.state, "closed");
});
}, 'Decode empty VP9 frame');
promise_test(t => {
let decoder = new VideoDecoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
t.step(() => {
// TODO(sandersd): Change to 'throw e' once e is defined.
throw "decode error";
});
}
});
let decoder = new VideoDecoder(getDefaultCodecInit(t));
decoder.configure({codec: vp9.codec});
......@@ -296,9 +185,7 @@ promise_test(t => {
// TODO(sandersd): Wait for a bit in case there is a lingering output
// or error coming.
return flushPromise.then(
() => { throw "flush succeeded unexpectedly"; },
() => {});
return promise_rejects_exactly(t, undefined, flushPromise);
}, 'Close while decoding corrupt VP9 frame');
</script>
</html>
......@@ -7,6 +7,7 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/media.js"></script>
<script src="/webcodecs/utils.js"></script>
<script>
const defaultConfig = {
......@@ -27,113 +28,42 @@ async function createVideoFrame(width, height, timestamp) {
return new VideoFrame(bitmap, { timestamp: timestamp });
}
// Calls done after giving async output/error callbacks a final chance to run.
async function asyncDone(test) {
test.step_timeout(test.done.bind(test), 0);
}
async_test(async (t) => {
promise_test(t => {
// VideoEncoderInit lacks required fields.
assert_throws_js(TypeError, () => { new VideoEncoder({}); });
// VideoEncoderInit has required fields.
let encoder = new VideoEncoder({
output(chunk) { t.unreached_func("Unexpected output").call(); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
let encoder = new VideoEncoder(getDefaultCodecInit(t));
assert_equals(encoder.state, "unconfigured");
encoder.close();
asyncDone(t);
return endAfterEventLoopTurn();
}, 'Test VideoEncoder construction');
async_test(async (t) => {
let encoder = new VideoEncoder({
output(chunk) { t.unreached_func("Unexpected output").call(); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
const requiredConfigPairs = defaultConfig;
let incrementalConfig = {};
for (let key in requiredConfigPairs) {
// Configure should fail while required keys are missing.
assert_throws_js(TypeError, () => { encoder.configure(incrementalConfig); });
incrementalConfig[key] = requiredConfigPairs[key];
assert_equals(encoder.state, "unconfigured");
}
// Configure should pass once incrementalConfig meets all requirements.
encoder.configure(incrementalConfig);
assert_equals(encoder.state, "configured");
// We should be able to reconfigure the encoder.
encoder.configure(incrementalConfig);
assert_equals(encoder.state, "configured");
let config = incrementalConfig;
// Bogus codec rejected.
config.codec = 'bogus';
assert_throws_js(TypeError, () => { encoder.configure(config); });
// Audio codec rejected.
config.codec = 'vorbis';
assert_throws_js(TypeError, () => { encoder.configure(config); });
// Ambiguous codec rejected.
config.codec = 'vp9';
assert_throws_js(TypeError, () => { encoder.configure(config); });
promise_test(t => {
let encoder = new VideoEncoder(getDefaultCodecInit(t));
// Codec with mime type rejected.
config.codec = 'video/webm; codecs="vp9"';
assert_throws_js(TypeError, () => { encoder.configure(config); });
let badCodecsList = [
'', // Empty codec
'bogus', // Non exsitent codec
'vorbis', // Audio codec
'vp9', // Ambiguous codec
'video/webm; codecs="vp9"' // Codec with mime type
]
// The failed configures should not affect the current config.
assert_equals(encoder.state, "configured");
// Test we can configure after a reset.
encoder.reset()
assert_equals(encoder.state, "unconfigured");
testConfigurations(encoder, defaultConfig, badCodecsList);
encoder.configure(defaultConfig);
assert_equals(encoder.state, "configured");
encoder.close();
asyncDone(t);
return endAfterEventLoopTurn();
}, 'Test VideoEncoder.configure()');
async_test(async (t) => {
let encoder = new VideoEncoder({
output(chunk) { t.unreached_func("Unexpected output").call(); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
let videoFrame = await createVideoFrame(640, 480, 0);
assert_throws_dom('InvalidStateError',
() => { encoder.encode(videoFrame); },
'first encode');
// Once more for good measure.
assert_throws_dom('InvalidStateError',
() => { encoder.encode(videoFrame); },
'second encode');
encoder.close();
asyncDone(t);
}, 'Test encode() before configure() throws InvalidStateError.');
async_test(async (t) => {
promise_test(async t => {
let output_chunks = [];
let encoder = new VideoEncoder({
output(chunk) { output_chunks.push(chunk); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
let codecInit = getDefaultCodecInit(t);
codecInit.output = chunk => output_chunks.push(chunk);
let encoder = new VideoEncoder(codecInit);
// No encodes yet.
assert_equals(encoder.encodeQueueSize, 0);
......@@ -161,18 +91,14 @@ async_test(async (t) => {
assert_equals(output_chunks.length, 2);
assert_equals(output_chunks[0].timestamp, frame1.timestamp);
assert_equals(output_chunks[1].timestamp, frame2.timestamp);
encoder.close();
asyncDone(t);
}, 'Test successful configure(), encode(), and flush()');
async_test(async (t) => {
promise_test(async t => {
let output_chunks = [];
let encoder = new VideoEncoder({
output(chunk) { output_chunks.push(chunk); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
let codecInit = getDefaultCodecInit(t);
codecInit.output = chunk => output_chunks.push(chunk);
let encoder = new VideoEncoder(codecInit);
// No encodes yet.
assert_equals(encoder.encodeQueueSize, 0);
......@@ -217,8 +143,9 @@ async_test(async (t) => {
encoder.encode(frame3.clone());
// Verify that a failed call to configure does not change the encoder's state.
config.codec = 'bogus';
assert_throws_js(TypeError, () => encoder.configure(config));
let badConfig = {...defaultConfig};
badConfig.codec = 'bogus';
assert_throws_js(TypeError, () => encoder.configure(badConfig));
encoder.encode(frame4.clone());
......@@ -226,101 +153,47 @@ async_test(async (t) => {
assert_equals(output_chunks[0].timestamp, frame3.timestamp);
assert_equals(output_chunks[1].timestamp, frame4.timestamp);
encoder.close();
asyncDone(t);
}, 'Test successful encode() after re-configure().');
async_test(async (t) => {
promise_test(async t => {
let output_chunks = [];
let encoder = new VideoEncoder({
output(chunk) { output_chunks.push(chunk); },
error(error) { t.unreached_func("Unexpected error:" + error).call(); },
});
let codecInit = getDefaultCodecInit(t);
codecInit.output = chunk => output_chunks.push(chunk);
let encoder = new VideoEncoder(codecInit);
let timestamp = 33333;
let frame = await createVideoFrame(640, 480, timestamp);
t.step(() => {
// No encodes yet.
assert_equals(encoder.encodeQueueSize, 0);
encoder.configure(defaultConfig);
encoder.configure(defaultConfig);
assert_equals(encoder.state, "configured");
encoder.encode(frame);
encoder.encode(frame);
assert_not_equals(frame.timestamp, timestamp);
assert_throws_dom("InvalidStateError", () => frame.clone());
// |frame| is not longer valid since it has been destroyed.
assert_not_equals(frame.timestamp, timestamp);
assert_throws_dom("InvalidStateError", () => frame.clone());
encoder.close();
});
encoder.close();
asyncDone(t);
return endAfterEventLoopTurn();
}, 'Test encoder consumes (destroys) frames.');
promise_test(async t => {
let encoder = new VideoEncoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
t.step(() => {
throw "unexpected error";
});
}
});
encoder.close();
assert_equals(encoder.state, "closed")
let encoder = new VideoEncoder(getDefaultCodecInit(t));
let frame = await createVideoFrame(640, 480, 0);
assert_throws_dom("InvalidStateError",
() => encoder.configure(defaultConfig),
"configure");
assert_throws_dom("InvalidStateError",
() => encoder.encode(frame),
"encode");
assert_throws_dom("InvalidStateError",
() => encoder.reset(),
"reset");
assert_throws_dom("InvalidStateError",
() => encoder.close(),
"close");
return promise_rejects_dom(t, 'InvalidStateError', encoder.flush(), 'flush');
}, 'Closed encoder');
return testClosedCodec(t, encoder, defaultConfig, frame);
}, 'Verify closed VideoEncoder operations');
promise_test(async t => {
let encoder = new VideoEncoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
t.step(() => {
throw "unexpected error";
});
}
});
assert_equals(encoder.state, "unconfigured");
let encoder = new VideoEncoder(getDefaultCodecInit(t));
let frame = await createVideoFrame(640, 480, 0);
// Resetting an unconfigured encoder is a no-op.
encoder.reset();
assert_equals(encoder.state, "unconfigured");
assert_throws_dom("InvalidStateError",
() => encoder.encode(frame),
"encode");
return promise_rejects_dom(t, 'InvalidStateError', encoder.flush(), 'flush');
}, 'Unconfigured encoder');
return testUnconfiguredCodec(t, encoder, frame);
}, 'Verify unconfigured VideoEncoder operations');
</script>
</html>
......@@ -5,33 +5,22 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/media.js"></script>
<script src="/webcodecs/utils.js"></script>
<script>
function makeImageBitmap(width, height) {
let canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(50, 100, 150, 255)';
ctx.fillRect(0, 0, width, height);
return createImageBitmap(canvas);
}
var defaultInit = {
timestamp : 100,
duration : 33,
}
async function createDefaultVideoFrame() {
let image = await makeImageBitmap(32,16);
function createDefaultVideoFrame() {
let image = makeImageBitmap(32,16);
return new VideoFrame(image, defaultInit);
}
async_test(async function(t) {
let frame = await createDefaultVideoFrame();
test(t => {
let frame = createDefaultVideoFrame();
let clone = frame.clone();
......@@ -44,12 +33,10 @@ async_test(async function(t) {
frame.destroy();
clone.destroy();
t.done();
}, 'Test we can clone a VideoFrame.');
async_test(async function(t) {
let frame = await createDefaultVideoFrame();
test(t => {
let frame = createDefaultVideoFrame();
let copy = frame;
let clone = frame.clone();
......@@ -60,24 +47,20 @@ async_test(async function(t) {
assert_equals(clone.timestamp, defaultInit.timestamp);
clone.destroy();
t.done();
}, 'Verify destroying a frame doesn\'t affect its clones.');
async_test(async function(t) {
let frame = await createDefaultVideoFrame();
test(t => {
let frame = createDefaultVideoFrame();
frame.destroy();
assert_throws_dom("InvalidStateError", () => {
let clone = frame.clone();
});
t.done();
}, 'Verify cloning a destroyed frame throws.');
async_test(async function(t) {
let localFrame = await createDefaultVideoFrame();
async_test(t => {
let localFrame = createDefaultVideoFrame();
let channel = new MessageChannel();
let localPort = channel.port1;
......@@ -97,8 +80,8 @@ async_test(async function(t) {
}, 'Verify destroying frames propagates accross contexts.');
async_test(async function(t) {
let localFrame = await createDefaultVideoFrame();
async_test(t => {
let localFrame = createDefaultVideoFrame();
let channel = new MessageChannel();
let localPort = channel.port1;
......@@ -119,8 +102,8 @@ async_test(async function(t) {
}, 'Verify destroying cloned frames doesn\'t propagate accross contexts.');
async_test(async function(t) {
let localFrame = await createDefaultVideoFrame();
async_test(t => {
let localFrame = createDefaultVideoFrame();
let channel = new MessageChannel();
let localPort = channel.port1;
......
......@@ -4,16 +4,8 @@
<body></body>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/webcodecs/utils.js"></script>
<script>
function makeImageBitmap(width, height) {
let canvas = new OffscreenCanvas(width, height);
let ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgba(50, 100, 150, 255)';
ctx.fillRect(0, 0, width, height);
return canvas.transferToImageBitmap();
}
test(t => {
let image = makeImageBitmap(32, 16);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment