mirror of https://github.com/mpv-player/mpv
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:
parent
c7fe4ae73a
commit
ef6bc8504a
|
@ -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::
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue