vo_gpu: reinterpret SDR white levels based on ITU-R BT.2408

This standard says we should use a value of 203 nits instead of 100 for
mapping between SDR and HDR.

Code copied from https://code.videolan.org/videolan/libplacebo/-/commit/9d9164773

In particular, that commit also includes a test case to make sure the
implementation doesn't break roundtrips.

Relevant to #4248 and #7357.
This commit is contained in:
Niklas Haas 2020-05-17 03:17:28 +02:00
parent c7fe4ae73a
commit ef6bc8504a
4 changed files with 13 additions and 9 deletions

View File

@ -6005,12 +6005,12 @@ The following video options are currently all specific to ``--vo=gpu`` and
additional effect of parametrizing the inverse OOTF, in order to get
colorimetrically consistent results with the mastering display. For SDR, or
when using an ICC (profile (``--icc-profile``), setting this to a value
above 100 essentially causes the display to be treated as if it were an HDR
above 203 essentially causes the display to be treated as if it were an HDR
display in disguise. (See the note below)
In ``auto`` mode (the default), the chosen peak is an appropriate value
based on the TRC in use. For SDR curves, it uses 100. For HDR curves, it
uses 100 * the transfer function's nominal peak.
based on the TRC in use. For SDR curves, it uses 203. For HDR curves, it
uses 203 * the transfer function's nominal peak.
.. note::

View File

@ -481,7 +481,7 @@ float mp_trc_nom_peak(enum mp_csp_trc trc)
{
switch (trc) {
case MP_CSP_TRC_PQ: return 10000.0 / MP_REF_WHITE;
case MP_CSP_TRC_HLG: return 12.0;
case MP_CSP_TRC_HLG: return 12.0 / MP_REF_WHITE_HLG;
case MP_CSP_TRC_V_LOG: return 46.0855;
case MP_CSP_TRC_S_LOG1: return 6.52;
case MP_CSP_TRC_S_LOG2: return 9.212;

View File

@ -145,9 +145,11 @@ struct mp_colorspace {
// For many colorspace conversions, in particular those involving HDR, an
// implicit reference white level is needed. Since this magic constant shows up
// a lot, give it an explicit name. The value of 100 cd/m² comes from ITU-R
// documents such as ITU-R BT.2100
#define MP_REF_WHITE 100.0
// a lot, give it an explicit name. The value of 203 cd/m² comes from ITU-R
// Report BT.2408, and the value for HLG comes from the cited HLG 75% level
// (transferred to scene space).
#define MP_REF_WHITE 203.0
#define MP_REF_WHITE_HLG 3.17955
// Replaces unknown values in the first struct by those of the second struct
void mp_colorspace_merge(struct mp_colorspace *orig, struct mp_colorspace *new);

View File

@ -399,6 +399,7 @@ void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc)
" exp((color.rgb - vec3(%f)) * vec3(1.0/%f)) + vec3(%f),\n"
" lessThan(vec3(0.5), color.rgb));\n",
HLG_C, HLG_A, HLG_B);
GLSLF("color.rgb *= vec3(1.0/%f);\n", MP_REF_WHITE_HLG);
break;
case MP_CSP_TRC_V_LOG:
GLSLF("color.rgb = mix((color.rgb - vec3(0.125)) * vec3(1.0/5.6), \n"
@ -483,6 +484,7 @@ void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc)
GLSLF("color.rgb = pow(color.rgb, vec3(%f));\n", PQ_M2);
break;
case MP_CSP_TRC_HLG:
GLSLF("color.rgb *= vec3(%f);\n", MP_REF_WHITE_HLG);
GLSLF("color.rgb = mix(vec3(0.5) * sqrt(color.rgb),\n"
" vec3(%f) * log(color.rgb - vec3(%f)) + vec3(%f),\n"
" lessThan(vec3(1.0), color.rgb));\n",
@ -528,7 +530,7 @@ static void pass_ootf(struct gl_shader_cache *sc, enum mp_csp_light light,
// HLG OOTF from BT.2100, scaled to the chosen display peak
float gamma = MPMAX(1.0, 1.2 + 0.42 * log10(peak * MP_REF_WHITE / 1000.0));
GLSLF("color.rgb *= vec3(%f * pow(dot(src_luma, color.rgb), %f));\n",
peak / pow(12, gamma), gamma - 1.0);
peak / pow(12.0 / MP_REF_WHITE_HLG, gamma), gamma - 1.0);
break;
}
case MP_CSP_LIGHT_SCENE_709_1886:
@ -561,7 +563,7 @@ static void pass_inverse_ootf(struct gl_shader_cache *sc, enum mp_csp_light ligh
{
case MP_CSP_LIGHT_SCENE_HLG: {
float gamma = MPMAX(1.0, 1.2 + 0.42 * log10(peak * MP_REF_WHITE / 1000.0));
GLSLF("color.rgb *= vec3(1.0/%f);\n", peak / pow(12, gamma));
GLSLF("color.rgb *= vec3(1.0/%f);\n", peak / pow(12.0 / MP_REF_WHITE_HLG, gamma));
GLSLF("color.rgb /= vec3(max(1e-6, pow(dot(src_luma, color.rgb), %f)));\n",
(gamma - 1.0) / gamma);
break;