Skip to content

Commit 5bc2af8

Browse files
committed
[WebCodecs] Add support for overriding color space for HW video decoders
rdar://178717498 https://bugs.webkit.org/show_bug.cgi?id=316301 Reviewed by Jean-Yves Avenard. The WebCodecs spec says VideoDecoderConfig.colorSpace takes precedence over in-band color signaling, but WebKit was ignoring it for VP9 and AV1. The bitstream's primaries/transfer/matrix/range surfaced unchanged on the decoded VideoFrame — leaving JS no way to retag e.g. a stream signaling BT.2020 SDR transfer as PQ for HDR rendering. We plumb the optional PlatformVideoColorSpace from the WebCodecs config all the way to the decoder for both SW and HW paths. For HW path, RemoteVideoCodecFactory takes config.colorSpace, LibWebRTCCodecs stores it on Decoder. The LibWebRTCCodecsProxy CreateDecoder IPC message carries it to the GPU process. The proxy hands it to WebRTCVideoDecoder::create, which forwards it to WebRTCVideoDecoderVTBVP9 / WebRTCVideoDecoderVTBAV1 constructors. Each decoder applies the override when building the CMVideoFormatDescription so the resulting CVPixelBuffer carries the overridden color tags. For SW, we update LibWebRTCVPXVideoDecoder to use a VideoInfo at parse time. This allows to compute the color space override properly. LibWebRTCVPXInternalVideoDecoder now reparses every frame to search for VPCC info, while in the past, it was only doing so if there was no config provided. This is more semantically correct as parameters come from the bitstream. createVP9FormatDescriptionFromRecord and createVideoInfoFromAV1Stream gain the optional override parameter. createVideoInfoFromVPCodecConfigurationRecord is exposed in VP9UtilitiesCocoa.h so the libwebrtc path can build a VideoInfo from a parsed record directly. Test: http/tests/webcodecs/av1-sdr.html * LayoutTests/http/tests/webcodecs/av1-sdr-expected.txt: Added. * LayoutTests/http/tests/webcodecs/av1-sdr.bin: Added. * LayoutTests/http/tests/webcodecs/av1-sdr.html: Added. * Source/WebCore/platform/graphics/AV1Utilities.cpp: (WebCore::createVideoInfoFromAV1CodecConfigurationRecord): (WebCore::createVideoInfoFromAV1Stream): * Source/WebCore/platform/graphics/AV1Utilities.h: * Source/WebCore/platform/graphics/cocoa/VP9UtilitiesCocoa.h: * Source/WebCore/platform/graphics/cocoa/VP9UtilitiesCocoa.mm: (WebCore::createVideoInfoFromVPCodecConfigurationRecord): (WebCore::createVP9FormatDescriptionFromRecord): * Source/WebCore/platform/libwebrtc/LibWebRTCVPXVideoDecoder.cpp: (WebCore::LibWebRTCVPXInternalVideoDecoder::decode): (WebCore::LibWebRTCVPXInternalVideoDecoder::LibWebRTCVPXInternalVideoDecoder): (WebCore::LibWebRTCVPXInternalVideoDecoder::Decoded): * Source/WebCore/platform/video-codecs/cocoa/WebRTCVideoDecoder.h: * Source/WebCore/platform/video-codecs/cocoa/WebRTCVideoDecoder.mm: (WebCore::WebRTCVideoDecoder::create): * Source/WebCore/platform/video-codecs/cocoa/WebRTCVideoDecoderVTBAV1.h: * Source/WebCore/platform/video-codecs/cocoa/WebRTCVideoDecoderVTBAV1.mm: (WebCore::computeAV1InputFormat): (WebCore::WebRTCVideoDecoderVTBAV1::WebRTCVideoDecoderVTBAV1): (WebCore::WebRTCVideoDecoderVTBAV1::decodeFrame): * Source/WebCore/platform/video-codecs/cocoa/WebRTCVideoDecoderVTBVP9.h: * Source/WebCore/platform/video-codecs/cocoa/WebRTCVideoDecoderVTBVP9.mm: (WebCore::createVP9FormatDescriptionFromData): (WebCore::WebRTCVideoDecoderVTBVP9::WebRTCVideoDecoderVTBVP9): (WebCore::WebRTCVideoDecoderVTBVP9::decodeFrame): Canonical link: https://commits.webkit.org/314887@main
1 parent e9b9453 commit 5bc2af8

28 files changed

Lines changed: 321 additions & 89 deletions
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
PASS AV1 isConfigSupported
3+
PASS Setup
4+
PASS AV1 (no override): bitstream colorSpace surfaces
5+
PASS AV1 colorSpace override: primaries
6+
PASS AV1 colorSpace override: matrix
7+
PASS AV1 colorSpace override: transfer (pq)
8+
PASS AV1 colorSpace override: fullRange (true)
9+
PASS AV1 colorSpace override: fullRange (false)
10+
PASS AV1 colorSpace full override
11+
1.02 KB
Binary file not shown.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>WebCodecs AV1 HDR decoding with colorSpace overrides</title>
5+
<script src="../../resources/testharness.js"></script>
6+
<script src="../../resources/testharnessreport.js"></script>
7+
</head>
8+
<body>
9+
<script>
10+
const HDR_CODEC = "av01.0.04M.08";
11+
let av1Data;
12+
13+
promise_test(async () => {
14+
assert_implements(window.VideoDecoder, "VideoDecoder is supported");
15+
const config = { codec: HDR_CODEC, codedWidth: 320, codedHeight: 240 };
16+
const support = await VideoDecoder.isConfigSupported(config);
17+
assert_true(support.supported, "AV1 (8-bit) is supported");
18+
}, "AV1 isConfigSupported");
19+
20+
promise_test(async () => {
21+
// AV1 main profile, level 4.0, Main tier, 8-bit. The bitstream itself carries BT709, video range.
22+
const response = await fetch("av1-sdr.bin");
23+
const buffer = await response.arrayBuffer();
24+
// Need to strip the 32-byte IVF file header + 12-byte frame header.
25+
av1Data = new Uint8Array(buffer).slice(44);
26+
}, "Setup");
27+
28+
async function decodeWithOverride(colorSpace) {
29+
const frames = [];
30+
const decoder = new VideoDecoder({
31+
output: f => frames.push(f),
32+
error: e => assert_unreached(`decode error: ${e.message}`),
33+
});
34+
const config = { codec: HDR_CODEC, codedWidth: 320, codedHeight: 240 };
35+
if (colorSpace)
36+
config.colorSpace = colorSpace;
37+
decoder.configure(config);
38+
decoder.decode(new EncodedVideoChunk({ type: "key", timestamp: 0, data: av1Data }));
39+
await decoder.flush();
40+
assert_equals(frames.length, 1, "one frame decoded");
41+
return frames[0];
42+
}
43+
44+
promise_test(async () => {
45+
const f = await decodeWithOverride();
46+
assert_equals(f.colorSpace.primaries, "bt709", "primaries from bitstream");
47+
assert_equals(f.colorSpace.matrix, "bt709", "matrix from bitstream");
48+
assert_false(f.colorSpace.fullRange, "video range from bitstream");
49+
f.close();
50+
}, "AV1 (no override): bitstream colorSpace surfaces");
51+
52+
promise_test(async () => {
53+
const f = await decodeWithOverride({ primaries: "smpte170m" });
54+
assert_equals(f.colorSpace.primaries, "smpte170m", "primaries overridden");
55+
assert_equals(f.colorSpace.matrix, "bt709", "matrix preserved from bitstream");
56+
f.close();
57+
}, "AV1 colorSpace override: primaries");
58+
59+
promise_test(async () => {
60+
const f = await decodeWithOverride({ matrix: "bt470bg" });
61+
assert_equals(f.colorSpace.primaries, "bt709", "primaries preserved from bitstream");
62+
assert_equals(f.colorSpace.matrix, "bt470bg", "matrix overridden");
63+
f.close();
64+
}, "AV1 colorSpace override: matrix");
65+
66+
promise_test(async () => {
67+
const f = await decodeWithOverride({ transfer: "pq" });
68+
assert_equals(f.colorSpace.primaries, "bt709", "primaries preserved from bitstream");
69+
assert_equals(f.colorSpace.matrix, "bt709", "matrix preserved from bitstream");
70+
assert_equals(f.colorSpace.transfer, "pq", "transfer overridden to PQ");
71+
f.close();
72+
}, "AV1 colorSpace override: transfer (pq)");
73+
74+
promise_test(async () => {
75+
const f = await decodeWithOverride({ fullRange: true });
76+
assert_equals(f.colorSpace.primaries, "bt709", "primaries preserved from bitstream");
77+
assert_equals(f.colorSpace.matrix, "bt709", "matrix preserved from bitstream");
78+
assert_true(f.colorSpace.fullRange, "range overridden to full");
79+
f.close();
80+
}, "AV1 colorSpace override: fullRange (true)");
81+
82+
promise_test(async () => {
83+
const f = await decodeWithOverride({ fullRange: false });
84+
assert_equals(f.colorSpace.primaries, "bt709", "primaries preserved from bitstream");
85+
assert_equals(f.colorSpace.matrix, "bt709", "matrix preserved from bitstream");
86+
assert_false(f.colorSpace.fullRange, "range overridden to video");
87+
f.close();
88+
}, "AV1 colorSpace override: fullRange (false)");
89+
90+
promise_test(async () => {
91+
const f = await decodeWithOverride({ fullRange: false, transfer: "pq", matrix: "bt470bg", primaries: "smpte170m" });
92+
assert_equals(f.colorSpace.primaries, "smpte170m", "primaries overriden");
93+
assert_equals(f.colorSpace.matrix, "bt470bg", "matrix overriden");
94+
assert_equals(f.colorSpace.transfer, "pq", "transfer overriden");
95+
assert_false(f.colorSpace.fullRange, "range overridden to video");
96+
f.close();
97+
}, "AV1 colorSpace full override");
98+
</script>
99+
</body>
100+
</html>
Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
11

2-
PASS VP9 profile 2 isConfigSupported
3-
PASS VP9 profile 2 decoded with WebCodecs has BT.2020 and is 10 bits
2+
PASS Setup
3+
PASS VP9 profile 2 isConfigSupported [prefer-hardware]
4+
PASS VP9 (no override) [prefer-hardware]: bitstream colorSpace surfaces
5+
PASS VP9 colorSpace override [prefer-hardware]: primaries
6+
PASS VP9 colorSpace override [prefer-hardware]: matrix
7+
PASS VP9 colorSpace override [prefer-hardware]: transfer (pq)
8+
PASS VP9 colorSpace override [prefer-hardware]: fullRange (true)
9+
PASS VP9 colorSpace override [prefer-hardware]: fullRange (false)
10+
PASS VP9 profile 2 isConfigSupported [prefer-software]
11+
PASS VP9 (no override) [prefer-software]: bitstream colorSpace surfaces
12+
PASS VP9 colorSpace override [prefer-software]: primaries
13+
PASS VP9 colorSpace override [prefer-software]: matrix
14+
PASS VP9 colorSpace override [prefer-software]: transfer (pq)
15+
PASS VP9 colorSpace override [prefer-software]: fullRange (true)
16+
PASS VP9 colorSpace override [prefer-software]: fullRange (false)
417

Lines changed: 77 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,100 @@
11
<!DOCTYPE html>
22
<html>
33
<head>
4-
<title>WebCodecs VP9 HDR decoding</title>
4+
<title>WebCodecs VP9 HDR decoding with colorSpace overrides</title>
55
<script src="../../resources/testharness.js"></script>
66
<script src="../../resources/testharnessreport.js"></script>
77
</head>
88
<body>
99
<script>
1010
const HDR_CODEC = "vp09.02.10.10.01.09.16.09.00";
11-
promise_test(async () => {
12-
assert_implements(window.VideoDecoder, "VideoDecoder is supported");
13-
const config = { codec: HDR_CODEC, codedWidth: 320, codedHeight: 240 };
14-
const support = await VideoDecoder.isConfigSupported(config);
15-
assert_true(support.supported, "VP9 profile 2 (10-bit) is supported");
16-
}, "VP9 profile 2 isConfigSupported");
11+
let vp9Data;
1712

1813
promise_test(async () => {
14+
// Profile 2, level 1.0, 10-bit, 4:2:0, BT.2020 video range.
15+
const response = await fetch("vp9-hdr.bin");
16+
const buffer = await response.arrayBuffer();
17+
// Strip 32-byte IVF file header + 12-byte frame header.
18+
vp9Data = new Uint8Array(buffer).slice(44);
19+
}, "Setup");
20+
21+
async function decodeWithOverride(colorSpace, hardwareAcceleration) {
1922
const frames = [];
2023
const decoder = new VideoDecoder({
21-
output: frame => frames.push(frame),
24+
output: f => frames.push(f),
2225
error: e => assert_unreached(`decode error: ${e.message}`),
2326
});
24-
decoder.configure({
25-
codec: HDR_CODEC,
26-
codedWidth: 320,
27-
codedHeight: 240,
28-
});
29-
30-
// Content generated by ffmpeg, we need to strip the IVF header (32 bytes) and frame header (12 bytes).
31-
const response = await fetch("vp9-hdr.bin");
32-
const buffer = await response.arrayBuffer();
33-
const vp9Data = new Uint8Array(buffer).slice(44);
34-
decoder.decode(new EncodedVideoChunk({
35-
type: "key",
36-
timestamp: 0,
37-
data: vp9Data,
38-
}));
27+
const config = { codec: HDR_CODEC, codedWidth: 320, codedHeight: 240, hardwareAcceleration };
28+
if (colorSpace)
29+
config.colorSpace = colorSpace;
30+
decoder.configure(config);
31+
decoder.decode(new EncodedVideoChunk({ type: "key", timestamp: 0, data: vp9Data }));
3932
await decoder.flush();
40-
4133
assert_equals(frames.length, 1, "one frame decoded");
42-
const frame = frames[0];
34+
return frames[0];
35+
}
36+
37+
for (const hardwareAcceleration of ["prefer-hardware", "prefer-software"]) {
38+
const tag = `[${hardwareAcceleration}]`;
39+
40+
promise_test(async () => {
41+
assert_implements(window.VideoDecoder, "VideoDecoder is supported");
42+
const config = { codec: HDR_CODEC, codedWidth: 320, codedHeight: 240, hardwareAcceleration };
43+
const support = await VideoDecoder.isConfigSupported(config);
44+
assert_true(support.supported, "VP9 profile 2 (10-bit) is supported");
45+
}, `VP9 profile 2 isConfigSupported ${tag}`);
46+
47+
promise_test(async (t) => {
48+
const f = await decodeWithOverride(undefined, hardwareAcceleration);
49+
t.add_cleanup(() => f.close());
50+
assert_equals(f.colorSpace.primaries, "bt2020", "primaries from bitstream");
51+
assert_equals(f.colorSpace.matrix, "bt2020-ncl", "matrix from bitstream");
52+
assert_false(f.colorSpace.fullRange, "video range from bitstream");
53+
54+
if (f.format !== "I420P10") {
55+
assert_equals(f.format, null);
56+
assert_true(!window.internals?.is10bitsVideoFrame || internals.is10bitsVideoFrame(f), "10 bits");
57+
}
58+
}, `VP9 (no override) ${tag}: bitstream colorSpace surfaces`);
59+
60+
promise_test(async (t) => {
61+
const f = await decodeWithOverride({ primaries: "bt709", matrix: "bt2020-ncl", transfer: "bt709" }, hardwareAcceleration);
62+
t.add_cleanup(() => f.close());
63+
assert_equals(f.colorSpace.primaries, "bt709", "primaries overridden");
64+
assert_equals(f.colorSpace.matrix, "bt2020-ncl", "matrix preserved from bitstream");
65+
}, `VP9 colorSpace override ${tag}: primaries`);
66+
67+
promise_test(async (t) => {
68+
const f = await decodeWithOverride({ matrix: "bt709" }, hardwareAcceleration);
69+
t.add_cleanup(() => f.close());
70+
assert_equals(f.colorSpace.primaries, "bt2020", "primaries preserved from bitstream");
71+
assert_equals(f.colorSpace.matrix, "bt709", "matrix overridden");
72+
}, `VP9 colorSpace override ${tag}: matrix`);
4373

44-
assert_equals(frame.colorSpace.primaries, "bt2020", "primaries");
45-
assert_equals(frame.colorSpace.matrix, "bt2020-ncl", "matrix");
46-
assert_false(frame.colorSpace.fullRange, "video range");
74+
promise_test(async (t) => {
75+
const f = await decodeWithOverride({ transfer: "pq" }, hardwareAcceleration);
76+
t.add_cleanup(() => f.close());
77+
assert_equals(f.colorSpace.primaries, "bt2020", "primaries preserved from bitstream");
78+
assert_equals(f.colorSpace.matrix, "bt2020-ncl", "matrix preserved from bitstream");
79+
assert_equals(f.colorSpace.transfer, "pq", "transfer overridden to PQ");
80+
}, `VP9 colorSpace override ${tag}: transfer (pq)`);
4781

48-
if (frame.format !== "I420P10") {
49-
assert_equals(frame.format, null);
50-
assert_true(!window.internals?.is10bitsVideoFrame || internals.is10bitsVideoFrame(frame), "10 bits");
51-
}
82+
promise_test(async (t) => {
83+
const f = await decodeWithOverride({ fullRange: true }, hardwareAcceleration);
84+
t.add_cleanup(() => f.close());
85+
assert_equals(f.colorSpace.primaries, "bt2020", "primaries preserved from bitstream");
86+
assert_equals(f.colorSpace.matrix, "bt2020-ncl", "matrix preserved from bitstream");
87+
assert_true(f.colorSpace.fullRange, "range overridden to full");
88+
}, `VP9 colorSpace override ${tag}: fullRange (true)`);
5289

53-
frame.close();
54-
}, "VP9 profile 2 decoded with WebCodecs has BT.2020 and is 10 bits");
90+
promise_test(async (t) => {
91+
const f = await decodeWithOverride({ fullRange: false }, hardwareAcceleration);
92+
t.add_cleanup(() => f.close());
93+
assert_equals(f.colorSpace.primaries, "bt2020", "primaries preserved from bitstream");
94+
assert_equals(f.colorSpace.matrix, "bt2020-ncl", "matrix preserved from bitstream");
95+
assert_false(f.colorSpace.fullRange, "range overridden to video");
96+
}, `VP9 colorSpace override ${tag}: fullRange (false)`);
97+
}
5598
</script>
5699
</body>
57100
</html>

LayoutTests/platform/glib/TestExpectations

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1911,6 +1911,7 @@ imported/w3c/web-platform-tests/webcodecs/full-cycle-test.https.any.html?av1_444
19111911
imported/w3c/web-platform-tests/webcodecs/full-cycle-test.https.any.worker.html?av1_444_high [ Pass ]
19121912

19131913
http/tests/webcodecs/vp9-hdr.html [ Failure ]
1914+
http/tests/webcodecs/av1-sdr.html [ Failure ]
19141915

19151916
# Test decoding a corrupt frame after reset in a flush callback assert_unreached: Should have rejected: undefined Reached unreachable code
19161917
imported/w3c/web-platform-tests/webcodecs/videoDecoder-codec-specific.https.any.html?av1 [ Failure ]

Source/WebCore/platform/graphics/AV1Utilities.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,7 +1261,7 @@ PlatformVideoColorSpace createPlatformVideoColorSpaceFromAV1CodecConfigurationRe
12611261
return colorSpace;
12621262
}
12631263

1264-
static Ref<VideoInfo> createVideoInfoFromAV1CodecConfigurationRecord(const AV1CodecConfigurationRecord& record, std::span<const uint8_t> fullOBUHeader, std::optional<FloatSize> displaySize)
1264+
static Ref<VideoInfo> createVideoInfoFromAV1CodecConfigurationRecord(const AV1CodecConfigurationRecord& record, std::span<const uint8_t> fullOBUHeader, std::optional<FloatSize> displaySize, const std::optional<PlatformVideoColorSpace>& colorSpaceOverride = std::nullopt)
12651265
{
12661266
// Build AV1 codec configuration record (av1C) for extensionAtoms
12671267
// Format: marker(1) | version(7) | seq_profile(3) | seq_level_idx_0(5) |
@@ -1287,6 +1287,9 @@ static Ref<VideoInfo> createVideoInfoFromAV1CodecConfigurationRecord(const AV1Co
12871287
// unsigned int(8) configOBUs[];
12881288
memcpySpan(av1CBytes.mutableSpan().subspan(4), fullOBUHeader);
12891289

1290+
auto colorSpace = createPlatformVideoColorSpaceFromAV1CodecConfigurationRecord(record);
1291+
overrideVideoColorSpaceAsNeeded(colorSpace, colorSpaceOverride);
1292+
12901293
return VideoInfo::create({
12911294
{
12921295
.codecName = { "av01" },
@@ -1295,7 +1298,7 @@ static Ref<VideoInfo> createVideoInfoFromAV1CodecConfigurationRecord(const AV1Co
12951298
.size = FloatSize(record.width, record.height),
12961299
.displaySize = displaySize.value_or(FloatSize(record.width, record.height)),
12971300
.bitDepth = record.bitDepth,
1298-
.colorSpace = createPlatformVideoColorSpaceFromAV1CodecConfigurationRecord(record),
1301+
.colorSpace = WTF::move(colorSpace),
12991302
.extensionAtoms = { FillWith { }, 1, TrackInfo::AtomData { { "av1C" }, SharedBuffer::create(WTF::move(av1CBytes)) } }
13001303
}
13011304
});
@@ -1354,7 +1357,7 @@ static std::optional<std::pair<std::span<const uint8_t>, std::span<const uint8_t
13541357
return std::nullopt;
13551358
}
13561359

1357-
RefPtr<VideoInfo> createVideoInfoFromAV1Stream(std::span<const uint8_t> data, std::optional<FloatSize> displaySize)
1360+
RefPtr<VideoInfo> createVideoInfoFromAV1Stream(std::span<const uint8_t> data, std::optional<FloatSize> displaySize, const std::optional<PlatformVideoColorSpace>& colorSpaceOverride)
13581361
{
13591362
auto sequenceHeaderData = getSequenceHeaderOBU(data);
13601363
if (!sequenceHeaderData)
@@ -1364,7 +1367,7 @@ RefPtr<VideoInfo> createVideoInfoFromAV1Stream(std::span<const uint8_t> data, st
13641367
if (!record)
13651368
return { };
13661369

1367-
return createVideoInfoFromAV1CodecConfigurationRecord(*record, sequenceHeaderData->first, displaySize);
1370+
return createVideoInfoFromAV1CodecConfigurationRecord(*record, sequenceHeaderData->first, displaySize, colorSpaceOverride);
13681371
}
13691372

13701373
}

Source/WebCore/platform/graphics/AV1Utilities.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ WEBCORE_EXPORT bool validateAV1PerLevelConstraints(const AV1CodecConfigurationRe
186186
std::optional<AV1CodecConfigurationRecord> parseAV1DecoderConfigurationRecord(std::span<const uint8_t>);
187187
std::optional<AV1CodecConfigurationRecord> parseSequenceHeaderOBU(std::span<const uint8_t>);
188188
WEBCORE_EXPORT PlatformVideoColorSpace createPlatformVideoColorSpaceFromAV1CodecConfigurationRecord(const AV1CodecConfigurationRecord&);
189-
WEBCORE_EXPORT RefPtr<VideoInfo> createVideoInfoFromAV1Stream(std::span<const uint8_t>, std::optional<FloatSize> = std::nullopt);
189+
WEBCORE_EXPORT RefPtr<VideoInfo> createVideoInfoFromAV1Stream(std::span<const uint8_t>, std::optional<FloatSize> = std::nullopt, const std::optional<PlatformVideoColorSpace>& colorSpaceOverride = std::nullopt);
190190

191191
template<typename E>
192192
std::optional<E> parseEnumFromStringView(StringView stringView)

Source/WebCore/platform/graphics/PlatformVideoColorSpace.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,18 @@ WTF::TextStream& operator<<(WTF::TextStream& ts, PlatformVideoColorSpace colorSp
179179
return ts;
180180
}
181181

182+
void overrideVideoColorSpaceAsNeeded(PlatformVideoColorSpace& colorSpace, const std::optional<PlatformVideoColorSpace>& colorSpaceOverride)
183+
{
184+
if (!colorSpaceOverride)
185+
return;
186+
if (colorSpaceOverride->primaries)
187+
colorSpace.primaries = colorSpaceOverride->primaries;
188+
if (colorSpaceOverride->transfer)
189+
colorSpace.transfer = colorSpaceOverride->transfer;
190+
if (colorSpaceOverride->matrix)
191+
colorSpace.matrix = colorSpaceOverride->matrix;
192+
if (colorSpaceOverride->fullRange)
193+
colorSpace.fullRange = colorSpaceOverride->fullRange;
194+
}
195+
182196
}

Source/WebCore/platform/graphics/PlatformVideoColorSpace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ struct PlatformVideoColorSpace {
4444
friend bool operator==(const PlatformVideoColorSpace&, const PlatformVideoColorSpace&) = default;
4545
};
4646

47+
void overrideVideoColorSpaceAsNeeded(PlatformVideoColorSpace&, const std::optional<PlatformVideoColorSpace>&);
48+
4749
WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, PlatformVideoColorSpace);
4850

4951
}

0 commit comments

Comments
 (0)