| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>WebCodecs VP9 HDR decoding with colorSpace overrides</title> | |
| <script src="../../resources/testharness.js"></script> | |
| <script src="../../resources/testharnessreport.js"></script> | |
| </head> | |
| <body> | |
| <script> | |
| const HDR_CODEC = "vp09.02.10.10.01.09.16.09.00"; | |
| let vp9Data; | |
| promise_test(async () => { | |
| // Profile 2, level 1.0, 10-bit, 4:2:0, BT.2020 video range. | |
| const response = await fetch("vp9-hdr.bin"); | |
| const buffer = await response.arrayBuffer(); | |
| // Strip 32-byte IVF file header + 12-byte frame header. | |
| vp9Data = new Uint8Array(buffer).slice(44); | |
| }, "Setup"); | |
| async function decodeWithOverride(colorSpace, hardwareAcceleration) { | |
| 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, hardwareAcceleration }; | |
| if (colorSpace) | |
| config.colorSpace = colorSpace; | |
| decoder.configure(config); | |
| decoder.decode(new EncodedVideoChunk({ type: "key", timestamp: 0, data: vp9Data })); | |
| await decoder.flush(); | |
| assert_equals(frames.length, 1, "one frame decoded"); | |
| return frames[0]; | |
| } | |
| for (const hardwareAcceleration of ["prefer-hardware", "prefer-software"]) { | |
| const tag = `[${hardwareAcceleration}]`; | |
| promise_test(async () => { | |
| assert_implements(window.VideoDecoder, "VideoDecoder is supported"); | |
| const config = { codec: HDR_CODEC, codedWidth: 320, codedHeight: 240, hardwareAcceleration }; | |
| const support = await VideoDecoder.isConfigSupported(config); | |
| assert_true(support.supported, "VP9 profile 2 (10-bit) is supported"); | |
| }, `VP9 profile 2 isConfigSupported ${tag}`); | |
| promise_test(async (t) => { | |
| const f = await decodeWithOverride(undefined, hardwareAcceleration); | |
| t.add_cleanup(() => f.close()); | |
| assert_equals(f.colorSpace.primaries, "bt2020", "primaries from bitstream"); | |
| assert_equals(f.colorSpace.matrix, "bt2020-ncl", "matrix from bitstream"); | |
| assert_false(f.colorSpace.fullRange, "video range from bitstream"); | |
| if (f.format !== "I420P10") { | |
| assert_equals(f.format, null); | |
| assert_true(!window.internals?.is10bitsVideoFrame || internals.is10bitsVideoFrame(f), "10 bits"); | |
| } | |
| }, `VP9 (no override) ${tag}: bitstream colorSpace surfaces`); | |
| promise_test(async (t) => { | |
| const f = await decodeWithOverride({ primaries: "bt709", matrix: "bt2020-ncl", transfer: "bt709" }, hardwareAcceleration); | |
| t.add_cleanup(() => f.close()); | |
| assert_equals(f.colorSpace.primaries, "bt709", "primaries overridden"); | |
| assert_equals(f.colorSpace.matrix, "bt2020-ncl", "matrix preserved from bitstream"); | |
| }, `VP9 colorSpace override ${tag}: primaries`); | |
| promise_test(async (t) => { | |
| const f = await decodeWithOverride({ matrix: "bt709" }, hardwareAcceleration); | |
| t.add_cleanup(() => f.close()); | |
| assert_equals(f.colorSpace.primaries, "bt2020", "primaries preserved from bitstream"); | |
| assert_equals(f.colorSpace.matrix, "bt709", "matrix overridden"); | |
| }, `VP9 colorSpace override ${tag}: matrix`); | |
| promise_test(async (t) => { | |
| const f = await decodeWithOverride({ transfer: "pq" }, hardwareAcceleration); | |
| t.add_cleanup(() => f.close()); | |
| assert_equals(f.colorSpace.primaries, "bt2020", "primaries preserved from bitstream"); | |
| assert_equals(f.colorSpace.matrix, "bt2020-ncl", "matrix preserved from bitstream"); | |
| assert_equals(f.colorSpace.transfer, "pq", "transfer overridden to PQ"); | |
| }, `VP9 colorSpace override ${tag}: transfer (pq)`); | |
| promise_test(async (t) => { | |
| const f = await decodeWithOverride({ fullRange: true }, hardwareAcceleration); | |
| t.add_cleanup(() => f.close()); | |
| assert_equals(f.colorSpace.primaries, "bt2020", "primaries preserved from bitstream"); | |
| assert_equals(f.colorSpace.matrix, "bt2020-ncl", "matrix preserved from bitstream"); | |
| assert_true(f.colorSpace.fullRange, "range overridden to full"); | |
| }, `VP9 colorSpace override ${tag}: fullRange (true)`); | |
| promise_test(async (t) => { | |
| const f = await decodeWithOverride({ fullRange: false }, hardwareAcceleration); | |
| t.add_cleanup(() => f.close()); | |
| assert_equals(f.colorSpace.primaries, "bt2020", "primaries preserved from bitstream"); | |
| assert_equals(f.colorSpace.matrix, "bt2020-ncl", "matrix preserved from bitstream"); | |
| assert_false(f.colorSpace.fullRange, "range overridden to video"); | |
| }, `VP9 colorSpace override ${tag}: fullRange (false)`); | |
| } | |
| </script> | |
| </body> | |
| </html> |