blob: 66081add629c784d75e7511e0eab0b1ca07be139 [file] [edit]
<!DOCTYPE html>
<html>
<head>
<title>WebCodecs AV1 HDR decoding with colorSpace overrides</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<script>
const HDR_CODEC = "av01.0.04M.08";
let av1Data;
promise_test(async () => {
assert_implements(window.VideoDecoder, "VideoDecoder is supported");
const config = { codec: HDR_CODEC, codedWidth: 320, codedHeight: 240 };
const support = await VideoDecoder.isConfigSupported(config);
assert_true(support.supported, "AV1 (8-bit) is supported");
}, "AV1 isConfigSupported");
promise_test(async () => {
// AV1 main profile, level 4.0, Main tier, 8-bit. The bitstream itself carries BT709, video range.
const response = await fetch("av1-sdr.bin");
const buffer = await response.arrayBuffer();
// Need to strip the 32-byte IVF file header + 12-byte frame header.
av1Data = new Uint8Array(buffer).slice(44);
}, "Setup");
async function decodeWithOverride(colorSpace) {
const frames = [];
const decoder = new VideoDecoder({
output: f => frames.push(f),
error: e => assert_unreached(`decode error: ${e.message}`),
});
const config = { codec: HDR_CODEC, codedWidth: 320, codedHeight: 240 };
if (colorSpace)
config.colorSpace = colorSpace;
decoder.configure(config);
decoder.decode(new EncodedVideoChunk({ type: "key", timestamp: 0, data: av1Data }));
await decoder.flush();
assert_equals(frames.length, 1, "one frame decoded");
return frames[0];
}
promise_test(async () => {
const f = await decodeWithOverride();
assert_equals(f.colorSpace.primaries, "bt709", "primaries from bitstream");
assert_equals(f.colorSpace.matrix, "bt709", "matrix from bitstream");
assert_false(f.colorSpace.fullRange, "video range from bitstream");
f.close();
}, "AV1 (no override): bitstream colorSpace surfaces");
promise_test(async () => {
const f = await decodeWithOverride({ primaries: "smpte170m" });
assert_equals(f.colorSpace.primaries, "smpte170m", "primaries overridden");
assert_equals(f.colorSpace.matrix, "bt709", "matrix preserved from bitstream");
f.close();
}, "AV1 colorSpace override: primaries");
promise_test(async () => {
const f = await decodeWithOverride({ matrix: "bt470bg" });
assert_equals(f.colorSpace.primaries, "bt709", "primaries preserved from bitstream");
assert_equals(f.colorSpace.matrix, "bt470bg", "matrix overridden");
f.close();
}, "AV1 colorSpace override: matrix");
promise_test(async () => {
const f = await decodeWithOverride({ transfer: "pq" });
assert_equals(f.colorSpace.primaries, "bt709", "primaries preserved from bitstream");
assert_equals(f.colorSpace.matrix, "bt709", "matrix preserved from bitstream");
assert_equals(f.colorSpace.transfer, "pq", "transfer overridden to PQ");
f.close();
}, "AV1 colorSpace override: transfer (pq)");
promise_test(async () => {
const f = await decodeWithOverride({ fullRange: true });
assert_equals(f.colorSpace.primaries, "bt709", "primaries preserved from bitstream");
assert_equals(f.colorSpace.matrix, "bt709", "matrix preserved from bitstream");
assert_true(f.colorSpace.fullRange, "range overridden to full");
f.close();
}, "AV1 colorSpace override: fullRange (true)");
promise_test(async () => {
const f = await decodeWithOverride({ fullRange: false });
assert_equals(f.colorSpace.primaries, "bt709", "primaries preserved from bitstream");
assert_equals(f.colorSpace.matrix, "bt709", "matrix preserved from bitstream");
assert_false(f.colorSpace.fullRange, "range overridden to video");
f.close();
}, "AV1 colorSpace override: fullRange (false)");
promise_test(async () => {
const f = await decodeWithOverride({ fullRange: false, transfer: "pq", matrix: "bt470bg", primaries: "smpte170m" });
assert_equals(f.colorSpace.primaries, "smpte170m", "primaries overriden");
assert_equals(f.colorSpace.matrix, "bt470bg", "matrix overriden");
assert_equals(f.colorSpace.transfer, "pq", "transfer overriden");
assert_false(f.colorSpace.fullRange, "range overridden to video");
f.close();
}, "AV1 colorSpace full override");
</script>
</body>
</html>