Loading...
Searching...
No Matches
ColorSpace.hpp
1#pragma once
2#include <Video/VideoInterface.hpp>
3
4// See softpixel.com/~cwright/programming/colorspace/yuv
5//
6// https://github.com/vlc-qt/vlc-qt/blob/master/src/qml/painter/GlPainter.cpp#L48
7//
8// All mat4 matrices are in column-major (GLSL) order.
9// Input: vec4(Y, Cb, Cr, 1.0) with values in [0, 1] normalized range.
10// The 4th column encodes the offset.
11//
12// Limited range matrices expect:
13// Y in [16/255, 235/255], Cb/Cr in [16/255, 240/255]
14// Y is scaled by 255/219, Cb/Cr by 255/224
15//
16// Full range matrices expect:
17// Y in [0, 1], Cb/Cr in [0, 1] (centered at 0.5)
18//
19// Kr/Kb coefficients used:
20// BT.601: Kr=0.299, Kb=0.114
21// BT.709: Kr=0.2126, Kb=0.0722
22// SMPTE 240M: Kr=0.2122, Kb=0.0865
23// FCC: Kr=0.30, Kb=0.11
24// BT.2020: Kr=0.2627, Kb=0.0593
25
26namespace score::gfx
27{
28
29// ============================================================
30// Identity (RGB passthrough)
31// ============================================================
32
33#define SCORE_GFX_RGB_MATRIX \
34 "mat4(\
35 1., 0., 0., 0.0,\n\
36 0., 1., 0., 0.0,\n\
37 0., 0., 1., 0.0,\n\
38 0., 0., 0., 1.0)\n"
39
40// ============================================================
41// BT.601 (Kr=0.299, Kb=0.114)
42// ============================================================
43
44#define SCORE_GFX_BT601_LIMITED_MATRIX \
45 "mat4(\n\
46 1.164383561643836, 1.164383561643836, 1.164383561643836, 0.0,\n\
47 0.000000000000000, -0.391762290094914, 2.017232142857143, 0.0,\n\
48 1.596026785714286, -0.812967647237771, 0.000000000000000, 0.0,\n\
49 -0.874202217873451, 0.531667823499146, -1.085630789302022, 1.0)\n"
50
51#define SCORE_GFX_BT601_FULL_MATRIX \
52 "mat4(\n\
53 1.000000000000000, 1.000000000000000, 1.000000000000000, 0.0,\n\
54 0.000000000000000, -0.344136286201022, 1.772000000000000, 0.0,\n\
55 1.402000000000000, -0.714136286201022, 0.000000000000000, 0.0,\n\
56 -0.701000000000000, 0.529136286201022, -0.886000000000000, 1.0)\n"
57
58// Backward compat aliases
59#define SCORE_GFX_BT601_MATRIX SCORE_GFX_BT601_LIMITED_MATRIX
60
61// ============================================================
62// BT.709 (Kr=0.2126, Kb=0.0722)
63// ============================================================
64
65#define SCORE_GFX_BT709_LIMITED_MATRIX \
66 "mat4(\n\
67 1.164383561643836, 1.164383561643836, 1.164383561643836, 0.0,\n\
68 0.000000000000000, -0.213248614273730, 2.112401785714286, 0.0,\n\
69 1.792741071428571, -0.532909328559444, 0.000000000000000, 0.0,\n\
70 -0.972945075016308, 0.301482665475862, -1.133402217873451, 1.0)\n"
71
72#define SCORE_GFX_BT709_FULL_MATRIX \
73 "mat4(\n\
74 1.000000000000000, 1.000000000000000, 1.000000000000000, 0.0,\n\
75 0.000000000000000, -0.187324272930649, 1.855600000000000, 0.0,\n\
76 1.574800000000000, -0.468124272930649, 0.000000000000000, 0.0,\n\
77 -0.787400000000000, 0.327724272930649, -0.927800000000000, 1.0)\n"
78
79// Backward compat aliases
80#define SCORE_GFX_BT709_MATRIX SCORE_GFX_BT709_LIMITED_MATRIX
81
82// ============================================================
83// SMPTE 240M (Kr=0.2122, Kb=0.0865)
84// ============================================================
85
86#define SCORE_GFX_SMPTE240M_LIMITED_MATRIX \
87 "mat4(\n\
88 1.164383561643836, 1.164383561643836, 1.164383561643836, 0.0,\n\
89 0.000000000000000, -0.256532845251675, 2.079843750000000, 0.0,\n\
90 1.793651785714286, -0.542724809537390, 0.000000000000000, 0.0,\n\
91 -0.973402217873451, 0.328136638536074, -1.117059360730594, 1.0)\n"
92
93#define SCORE_GFX_SMPTE240M_FULL_MATRIX \
94 "mat4(\n\
95 1.000000000000000, 1.000000000000000, 1.000000000000000, 0.0,\n\
96 0.000000000000000, -0.225346499358335, 1.827000000000000, 0.0,\n\
97 1.575600000000000, -0.476746499358335, 0.000000000000000, 0.0,\n\
98 -0.787800000000000, 0.351046499358335, -0.913500000000000, 1.0)\n"
99
100// ============================================================
101// FCC (Kr=0.30, Kb=0.11)
102// ============================================================
103
104#define SCORE_GFX_FCC_LIMITED_MATRIX \
105 "mat4(\n\
106 1.164383561643836, 1.164383561643836, 1.164383561643836, 0.0,\n\
107 0.000000000000000, -0.377792070217918, 2.026339285714286, 0.0,\n\
108 1.593750000000000, -0.810381355932203, 0.000000000000000, 0.0,\n\
109 -0.873059360730594, 0.523357104160448, -1.090202217873451, 1.0)\n"
110
111#define SCORE_GFX_FCC_FULL_MATRIX \
112 "mat4(\n\
113 1.000000000000000, 1.000000000000000, 1.000000000000000, 0.0,\n\
114 0.000000000000000, -0.331864406779661, 1.780000000000000, 0.0,\n\
115 1.400000000000000, -0.711864406779661, 0.000000000000000, 0.0,\n\
116 -0.700000000000000, 0.521864406779661, -0.890000000000000, 1.0)\n"
117
118// ============================================================
119// YCgCo
120// R = Y - Cg + Co, G = Y + Cg, B = Y - Cg - Co
121// (Cg and Co stored centered at 0.5)
122// ============================================================
123
124#define SCORE_GFX_YCGCO_LIMITED_MATRIX \
125 "mat4(\n\
126 1.164383561643836, 1.164383561643836, 1.164383561643836, 0.0,\n\
127 -1.138392857142857, 1.138392857142857, -1.138392857142857, 0.0,\n\
128 1.138392857142857, 0.000000000000000, -1.138392857142857, 0.0,\n\
129 -0.073059360730594, -0.644487932159165, 1.069797782126549, 1.0)\n"
130
131#define SCORE_GFX_YCGCO_FULL_MATRIX \
132 "mat4(\n\
133 1.0, 1.0, 1.0, 0.0,\n\
134 -1.0, 1.0, -1.0, 0.0,\n\
135 1.0, 0.0, -1.0, 0.0,\n\
136 0.0, -0.5, 0.5, 1.0)\n"
137
138// ============================================================
139// BT.2020 NCL (Kr=0.2627, Kb=0.0593)
140// Used by the BT.2020 HDR pipeline for the initial YUV->RGB step.
141// The full HDR path (EOTF, OOTF, OETF) is in bt2020shader().
142// ============================================================
143
144#define SCORE_GFX_BT2020_LIMITED_MATRIX \
145 "mat4(\n\
146 1.164383561643836, 1.164383561643836, 1.164383561643836, 0.0,\n\
147 0.000000000000000, -0.187326104219343, 2.141772321428571, 0.0,\n\
148 1.678674107142857, -0.650424318505057, 0.000000000000000, 0.0,\n\
149 -0.915687932159165, 0.347458498519301, -1.148145075016308, 1.0)\n"
150
151#define SCORE_GFX_BT2020_FULL_MATRIX \
152 "mat4(\n\
153 1.000000000000000, 1.000000000000000, 1.000000000000000, 0.0,\n\
154 0.000000000000000, -0.164553126843658, 1.881400000000000, 0.0,\n\
155 1.474600000000000, -0.571353126843658, 0.000000000000000, 0.0,\n\
156 -0.737300000000000, 0.367953126843658, -0.940700000000000, 1.0)\n"
157
158// ============================================================
159// Convenience macros for convert_to_rgb() function generation
160// ============================================================
161
162// --- BT.601 ---
163#define SCORE_GFX_CONVERT_BT601_LIMITED_TO_RGB \
164 "const mat4 conversion_matrix = " SCORE_GFX_BT601_LIMITED_MATRIX ";\n" \
165 "vec4 convert_to_rgb(vec4 tex) { return conversion_matrix * tex; }\n"
166
167#define SCORE_GFX_CONVERT_BT601_FULL_TO_RGB \
168 "const mat4 conversion_matrix = " SCORE_GFX_BT601_FULL_MATRIX ";\n" \
169 "vec4 convert_to_rgb(vec4 tex) { return conversion_matrix * tex; }\n"
170
171// --- BT.709 ---
172#define SCORE_GFX_CONVERT_BT709_LIMITED_TO_RGB \
173 "const mat4 conversion_matrix = " SCORE_GFX_BT709_LIMITED_MATRIX ";\n" \
174 "vec4 convert_to_rgb(vec4 tex) { return conversion_matrix * tex; }\n"
175
176#define SCORE_GFX_CONVERT_BT709_FULL_TO_RGB \
177 "const mat4 conversion_matrix = " SCORE_GFX_BT709_FULL_MATRIX ";\n" \
178 "vec4 convert_to_rgb(vec4 tex) { return conversion_matrix * tex; }\n"
179
180// --- SMPTE 240M ---
181#define SCORE_GFX_CONVERT_SMPTE240M_LIMITED_TO_RGB \
182 "const mat4 conversion_matrix = " SCORE_GFX_SMPTE240M_LIMITED_MATRIX ";\n"\
183 "vec4 convert_to_rgb(vec4 tex) { return conversion_matrix * tex; }\n"
184
185#define SCORE_GFX_CONVERT_SMPTE240M_FULL_TO_RGB \
186 "const mat4 conversion_matrix = " SCORE_GFX_SMPTE240M_FULL_MATRIX ";\n" \
187 "vec4 convert_to_rgb(vec4 tex) { return conversion_matrix * tex; }\n"
188
189// --- FCC ---
190#define SCORE_GFX_CONVERT_FCC_LIMITED_TO_RGB \
191 "const mat4 conversion_matrix = " SCORE_GFX_FCC_LIMITED_MATRIX ";\n" \
192 "vec4 convert_to_rgb(vec4 tex) { return conversion_matrix * tex; }\n"
193
194#define SCORE_GFX_CONVERT_FCC_FULL_TO_RGB \
195 "const mat4 conversion_matrix = " SCORE_GFX_FCC_FULL_MATRIX ";\n" \
196 "vec4 convert_to_rgb(vec4 tex) { return conversion_matrix * tex; }\n"
197
198// --- YCgCo ---
199#define SCORE_GFX_CONVERT_YCGCO_LIMITED_TO_RGB \
200 "const mat4 conversion_matrix = " SCORE_GFX_YCGCO_LIMITED_MATRIX ";\n" \
201 "vec4 convert_to_rgb(vec4 tex) { return conversion_matrix * tex; }\n"
202
203#define SCORE_GFX_CONVERT_YCGCO_FULL_TO_RGB \
204 "const mat4 conversion_matrix = " SCORE_GFX_YCGCO_FULL_MATRIX ";\n" \
205 "vec4 convert_to_rgb(vec4 tex) { return conversion_matrix * tex; }\n"
206
207// Backward compat aliases
208#define SCORE_GFX_CONVERT_BT601_TO_RGB SCORE_GFX_CONVERT_BT601_LIMITED_TO_RGB
209#define SCORE_GFX_CONVERT_BT709_TO_RGB SCORE_GFX_CONVERT_BT709_LIMITED_TO_RGB
210
211// ============================================================
212// BT.2020 gamut conversion matrix (for tone mapping pipeline)
213// ============================================================
214
215#define SCORE_GFX_BT2020_TO_709_MATRIX \
216 "mat4(\n\
217 1.660491, -0.587641, -0.072850, 0.000000,\n\
218 -0.124550, 1.132900, -0.008349, 0.000000,\n\
219 -0.018151, -0.100579, 1.118730, 0.000000,\n\
220 0.000000, 0.000000, 0.000000, 1.000000\n\
221 )\n"
222
223#define SCORE_GFX_BT2020_MATRIX SCORE_GFX_BT709_MATRIX
224
225// ============================================================
226// BT.2020 HDR pipeline (EOTF / OOTF / OETF)
227// ============================================================
228
229static constexpr auto SCORE_GFX_CONVERT_BT2020_TO_RGB_HEADER = R"_(
230const int COLOR_TRANSFER_LINEAR = 1;
231const int COLOR_TRANSFER_GAMMA_2_2 = 10;
232const int COLOR_TRANSFER_ST2084 = 6;
233const int COLOR_TRANSFER_HLG = 7;
234)_";
235
236static constexpr auto SCORE_GFX_CONVERT_BT2020_TO_RGB_HEADER_LIMITED_RANGE = R"_(
237const mat3 uYuvToRgbColorTransform = mat3(
238 1.1689f, 1.1689f, 1.1689f,
239 0.0000f, -0.1881f, 2.1502f,
240 1.6853f, -0.6530f, 0.0000f
241);
242)_";
243static constexpr auto SCORE_GFX_CONVERT_BT2020_TO_RGB_HEADER_FULL_RANGE = R"_(
244const mat3 uYuvToRgbColorTransform = mat3(
245 1.0000f, 1.0000f, 1.0000f,
246 0.0000f, -0.1646f, 1.8814f,
247 1.4746f, -0.5714f, 0.0000f
248);
249)_";
250static constexpr auto SCORE_GFX_CONVERT_BT2020_TO_RGB = R"_(
251
252const int uApplyHdrToSdrToneMapping = 1;
253
254
255// BT.2100 / BT.2020 HLG EOTF for one channel.
256float hlgEotfSingleChannel(float hlgChannel) {
257 const float a = 0.17883277;
258 const float b = 0.28466892;
259 const float c = 0.55991073;
260 return hlgChannel <= 0.5 ? hlgChannel * hlgChannel / 3.0
261 : (b + exp((hlgChannel - c) / a)) / 12.0;
262}
263
264// BT.2100 / BT.2020 HLG EOTF.
265vec3 hlgEotf(vec3 hlgColor) {
266 return vec3(hlgEotfSingleChannel(hlgColor.r),
267 hlgEotfSingleChannel(hlgColor.g),
268 hlgEotfSingleChannel(hlgColor.b));
269}
270
271// BT.2100 / BT.2020 PQ EOTF.
272vec3 pqEotf(vec3 pqColor) {
273 const float m1 = (2610.0 / 16384.0);
274 const float m2 = (2523.0 / 4096.0) * 128.0;
275 const float c1 = (3424.0 / 4096.0);
276 const float c2 = (2413.0 / 4096.0) * 32.0;
277 const float c3 = (2392.0 / 4096.0) * 32.0;
278
279 vec3 temp = pow(clamp(pqColor, 0.0, 1.0), 1.0 / vec3(m2));
280 temp = max(temp - c1, 0.0) / (c2 - c3 * temp);
281 return pow(temp, 1.0 / vec3(m1));
282}
283
284// Applies the appropriate EOTF to convert nonlinear electrical values to linear
285// optical values. Input and output are both normalized to [0, 1].
286vec3 applyEotf(vec3 electricalColor) {
287 if (uInputColorTransfer == COLOR_TRANSFER_ST2084) {
288 return pqEotf(electricalColor);
289 } else if (uInputColorTransfer == COLOR_TRANSFER_HLG) {
290 return hlgEotf(electricalColor);
291 } else {
292 // Output red as an obviously visible error.
293 return vec3(1.0, 0.0, 0.0);
294 }
295}
296
297// Apply the HLG BT2020 to BT709 OOTF.
298vec3 applyHlgBt2020ToBt709Ootf(vec3 linearRgbBt2020) {
299 const mat3 RGB_TO_XYZ_BT2020 =
300 mat3(0.63695805f, 0.26270021f, 0.00000000f, 0.14461690f, 0.67799807f,
301 0.02807269f, 0.16888098f, 0.05930172f, 1.06098506f);
302 const mat3 XYZ_TO_RGB_BT709 =
303 mat3(3.24096994f, -0.96924364f, 0.05563008f, -1.53738318f, 1.87596750f,
304 -0.20397696f, -0.49861076f, 0.04155506f, 1.05697151f);
305 const float hlgGamma = 1.0735674018211279;
306
307 vec3 linearXyzBt2020 = RGB_TO_XYZ_BT2020 * linearRgbBt2020;
308 vec3 linearXyzBt709 =
309 linearXyzBt2020 * pow(linearXyzBt2020[1], hlgGamma - 1.0);
310 vec3 linearRgbBt709 = clamp((XYZ_TO_RGB_BT709 * linearXyzBt709), 0.0, 1.0);
311 return linearRgbBt709;
312}
313
314// Apply the PQ BT2020 to BT709 OOTF.
315vec3 applyPqBt2020ToBt709Ootf(vec3 linearRgbBt2020) {
316 float pqPeakLuminance = 10000.0;
317 float sdrPeakLuminance = 500.0;
318
319 return linearRgbBt2020 * pqPeakLuminance / sdrPeakLuminance;
320}
321
322vec3 applyBt2020ToBt709Ootf(vec3 linearRgbBt2020) {
323 if (uInputColorTransfer == COLOR_TRANSFER_ST2084) {
324 return applyPqBt2020ToBt709Ootf(linearRgbBt2020);
325 } else if (uInputColorTransfer == COLOR_TRANSFER_HLG) {
326 return applyHlgBt2020ToBt709Ootf(linearRgbBt2020);
327 } else {
328 // Output green as an obviously visible error.
329 return vec3(0.0, 1.0, 0.0);
330 }
331}
332
333// BT.2100 / BT.2020 HLG OETF for one channel.
334float hlgOetfSingleChannel(float linearChannel) {
335 const float a = 0.17883277;
336 const float b = 0.28466892;
337 const float c = 0.55991073;
338
339 return linearChannel <= 1.0 / 12.0 ? sqrt(3.0 * linearChannel)
340 : a * log(12.0 * linearChannel - b) + c;
341}
342
343// BT.2100 / BT.2020 HLG OETF.
344vec3 hlgOetf(vec3 linearColor) {
345 return vec3(hlgOetfSingleChannel(linearColor.r),
346 hlgOetfSingleChannel(linearColor.g),
347 hlgOetfSingleChannel(linearColor.b));
348}
349
350// BT.2100 / BT.2020, PQ / ST2084 OETF.
351vec3 pqOetf(vec3 linearColor) {
352 const float m1 = (2610.0 / 16384.0);
353 const float m2 = (2523.0 / 4096.0) * 128.0;
354 const float c1 = (3424.0 / 4096.0);
355 const float c2 = (2413.0 / 4096.0) * 32.0;
356 const float c3 = (2392.0 / 4096.0) * 32.0;
357
358 vec3 temp = pow(linearColor, vec3(m1));
359 temp = (c1 + c2 * temp) / (1.0 + c3 * temp);
360 return pow(temp, vec3(m2));
361}
362
363// BT.709 gamma 2.2 OETF for one channel.
364float gamma22OetfSingleChannel(float linearChannel) {
365 return pow(linearChannel, (1.0 / 2.2));
366}
367
368// BT.709 gamma 2.2 OETF.
369vec3 gamma22Oetf(vec3 linearColor) {
370 return vec3(gamma22OetfSingleChannel(linearColor.r),
371 gamma22OetfSingleChannel(linearColor.g),
372 gamma22OetfSingleChannel(linearColor.b));
373}
374
375// Applies the appropriate OETF to convert linear optical signals to nonlinear
376// electrical signals. Input and output are both normalized to [0, 1].
377vec3 applyOetf(vec3 linearColor) {
378 if (uOutputColorTransfer == COLOR_TRANSFER_ST2084) {
379 return pqOetf(linearColor);
380 } else if (uOutputColorTransfer == COLOR_TRANSFER_HLG) {
381 return hlgOetf(linearColor);
382 } else if (uOutputColorTransfer == COLOR_TRANSFER_GAMMA_2_2) {
383 return gamma22Oetf(linearColor);
384 } else if (uOutputColorTransfer == COLOR_TRANSFER_LINEAR) {
385 return linearColor;
386 } else {
387 // Output blue as an obviously visible error.
388 return vec3(0.0, 0.0, 1.0);
389 }
390}
391
392vec3 yuvToRgb(vec3 yuv) {
393 const vec3 yuvOffset = vec3(0.0625, 0.5, 0.5);
394 return clamp(uYuvToRgbColorTransform * (yuv - yuvOffset), 0.0, 1.0);
395}
396
397vec4 convert_to_rgb(vec4 tex) {
398 vec3 srcYuv = tex.xyz;
399 vec3 opticalColorBt2020 = applyEotf(yuvToRgb(srcYuv));
400 vec4 opticalColor =
401 (uApplyHdrToSdrToneMapping == 1)
402 ? vec4(applyBt2020ToBt709Ootf(opticalColorBt2020), 1.0)
403 : vec4(opticalColorBt2020, 1.0);
404 vec4 transformedColors = opticalColor;
405 return vec4(applyOetf(transformedColors.rgb), 1.0);
406})_";
407
408static inline QString bt2020shader(const Video::ImageFormat& d)
409{
410 QString shader;
411 shader.reserve(8000);
412
413 shader += SCORE_GFX_CONVERT_BT2020_TO_RGB_HEADER;
414 if(d.color_range == AVCOL_RANGE_MPEG)
415 shader += SCORE_GFX_CONVERT_BT2020_TO_RGB_HEADER_LIMITED_RANGE;
416 else
417 shader += SCORE_GFX_CONVERT_BT2020_TO_RGB_HEADER_FULL_RANGE;
418
419 if(d.color_trc == AVCOL_TRC_SMPTE2084)
420 shader += "const int uInputColorTransfer = COLOR_TRANSFER_ST2084; \n";
421 else if(d.color_trc == AVCOL_TRC_GAMMA22)
422 shader += "const int uInputColorTransfer = COLOR_TRANSFER_GAMMA_2_2; \n";
423 else if(d.color_trc == AVCOL_TRC_LINEAR)
424 shader += "const int uInputColorTransfer = COLOR_TRANSFER_LINEAR; \n";
425 else if(d.color_trc == AVCOL_TRC_ARIB_STD_B67)
426 shader += "const int uInputColorTransfer = COLOR_TRANSFER_HLG; \n";
427 else
428 shader += "const int uInputColorTransfer = COLOR_TRANSFER_GAMMA_2_2; \n";
429
430 shader += "const int uOutputColorTransfer = COLOR_TRANSFER_GAMMA_2_2; \n";
431
432 shader += SCORE_GFX_CONVERT_BT2020_TO_RGB;
433
434 return shader;
435}
436
437// ============================================================
438// Helper to select limited vs full range conversion macro
439// ============================================================
440
441static inline QString colorMatrix(const Video::ImageFormat& d)
442{
443 const bool full_range = (d.color_range == AVCOL_RANGE_JPEG);
444
445 switch(d.color_space)
446 {
447 case AVCOL_SPC_RGB:
448 return "vec4 convert_to_rgb(vec4 tex) { return tex; }";
449
450 case AVCOL_SPC_BT709:
451 return full_range ? SCORE_GFX_CONVERT_BT709_FULL_TO_RGB
452 : SCORE_GFX_CONVERT_BT709_LIMITED_TO_RGB;
453
454 case AVCOL_SPC_FCC:
455 return full_range ? SCORE_GFX_CONVERT_FCC_FULL_TO_RGB
456 : SCORE_GFX_CONVERT_FCC_LIMITED_TO_RGB;
457
458 case AVCOL_SPC_BT470BG:
459 case AVCOL_SPC_SMPTE170M:
460 return full_range ? SCORE_GFX_CONVERT_BT601_FULL_TO_RGB
461 : SCORE_GFX_CONVERT_BT601_LIMITED_TO_RGB;
462
463 case AVCOL_SPC_SMPTE240M:
464 return full_range ? SCORE_GFX_CONVERT_SMPTE240M_FULL_TO_RGB
465 : SCORE_GFX_CONVERT_SMPTE240M_LIMITED_TO_RGB;
466
467 case AVCOL_SPC_YCGCO:
468 return full_range ? SCORE_GFX_CONVERT_YCGCO_FULL_TO_RGB
469 : SCORE_GFX_CONVERT_YCGCO_LIMITED_TO_RGB;
470
471 case AVCOL_SPC_BT2020_NCL:
472 return bt2020shader(d);
473 case AVCOL_SPC_BT2020_CL:
474 // NOTE: BT.2020 constant luminance requires a different decoding path.
475 // In practice CL content is extremely rare; treating as NCL is a
476 // reasonable approximation.
477 return bt2020shader(d);
478 case AVCOL_SPC_SMPTE2085:
479 return bt2020shader(d);
480 case AVCOL_SPC_CHROMA_DERIVED_NCL:
481 return bt2020shader(d);
482 case AVCOL_SPC_CHROMA_DERIVED_CL:
483 return bt2020shader(d);
484 case AVCOL_SPC_ICTCP:
485 return bt2020shader(d);
486
487 default:
488 case AVCOL_SPC_NB:
489 case AVCOL_SPC_UNSPECIFIED:
490 case AVCOL_SPC_RESERVED:
491 break;
492 }
493
494 // Fallback based on resolution; assume limited range if unspecified
495 if(d.width >= 1280)
496 return full_range ? SCORE_GFX_CONVERT_BT709_FULL_TO_RGB
497 : SCORE_GFX_CONVERT_BT709_LIMITED_TO_RGB;
498 else
499 return full_range ? SCORE_GFX_CONVERT_BT601_FULL_TO_RGB
500 : SCORE_GFX_CONVERT_BT601_LIMITED_TO_RGB;
501}
502}
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:12
Definition VideoInterface.hpp:18