| <!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> |