blob: c70366dc37d16f87a66226b8e6916e2cda98c11a [file] [log] [blame]
<!DOCTYPE html>
<html>
<title>Test the VideoDecoder API.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
'use strict';
// TODO(sandersd): Move metadata into a helper library.
// 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()),
codec: "avc1.64000c",
description: {offset: 7229, size: 46},
frames: [{offset: 48, size: 4007},
{offset: 4055, size: 926},
{offset: 4981, size: 241},
{offset: 5222, size: 97},
{offset: 5319, size: 98},
{offset: 5417, size: 624},
{offset: 6041, size: 185},
{offset: 6226, size: 94},
{offset: 6320, size: 109},
{offset: 6429, size: 281}]
};
let vp9 = {
buffer: fetch('vp9.mp4').then(r => r.arrayBuffer()),
// TODO(sandersd): Verify that the file is actually level 1.
codec: "vp09.00.10.08",
frames: [{offset: 44, size: 3315},
{offset: 3359, size: 203},
{offset: 3562, size: 245},
{offset: 3807, size: 172},
{offset: 3979, size: 312},
{offset: 4291, size: 170},
{offset: 4461, size: 195},
{offset: 4656, size: 181},
{offset: 4837, size: 356},
{offset: 5193, size: 159}]
};
function view(buffer, {offset, size}) {
return new Uint8Array(buffer, offset, size);
}
// 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) => {
// 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(); },
});
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);
asyncDone(t);
}, 'Test VideoDecoder.configure() codec validity');
promise_test(t => vp9.buffer.then(buffer => {
let numOutputs = 0;
let decoder = new VideoDecoder({
output(frame) {
t.step(() => {
assert_equals(++numOutputs, 1, "outputs");
assert_equals(frame.cropWidth, 320, "cropWidth");
assert_equals(frame.cropHeight, 240, "cropHeight");
assert_equals(frame.timestamp, 0, "timestamp");
frame.destroy();
});
},
error(e) {
t.step(() => {
// TODO(sandersd): Change to 'throw e' once e is defined.
throw "decode error";
});
}
});
decoder.configure({codec: vp9.codec});
decoder.decode(new EncodedVideoChunk('key', 0, view(buffer, vp9.frames[0])));
return decoder.flush().then(() => {
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";
});
}
});
decoder.close();
let fakeChunk = new EncodedVideoChunk('key', 0, Uint8Array.of(0));
assert_throws_dom("InvalidStateError",
() => decoder.configure({codec: vp9.codec}),
"configure");
assert_throws_dom("InvalidStateError",
() => decoder.decode(fakeChunk),
"reset");
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');
promise_test(t => {
let numErrors = 0;
let decoder = new VideoDecoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
numErrors++;
}
});
let fakeChunk = new EncodedVideoChunk('key', 0, Uint8Array.of(0));
decoder.decode(fakeChunk);
return decoder.flush().then(
() => { throw "flush succeeded unexpectedly"; },
() => { assert_equals(numErrors, 1, "errors"); });
}, 'Decode without configure');
promise_test(t => {
let numErrors = 0;
let decoder = new VideoDecoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
numErrors++;
}
});
decoder.configure({codec: vp9.codec});
let fakeChunk = new EncodedVideoChunk('key', 0, Uint8Array.of(0));
decoder.decode(fakeChunk);
return decoder.flush().then(
() => { throw "flush succeeded unexpectedly"; },
() => { assert_equals(numErrors, 1, "errors"); });
}, 'Decode corrupt VP9 frame');
promise_test(t => {
let numErrors = 0;
let decoder = new VideoDecoder({
output(frame) {
t.step(() => {
throw "unexpected output";
});
},
error(e) {
numErrors++;
}
});
decoder.configure({codec: vp9.codec});
let fakeChunk = new EncodedVideoChunk('key', 0, Uint8Array.of());
decoder.decode(fakeChunk);
return decoder.flush().then(
() => { throw "flush succeeded unexpectedly"; },
() => { assert_equals(numErrors, 1, "errors"); });
}, 'Decode empty VP9 frame');
</script>
</html>