From ef6bc8504a945eb6492b8ed46fd5a1afaaf32182 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Sun, 17 May 2020 03:17:28 +0200 Subject: 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. --- video/csputils.c | 2 +- video/csputils.h | 8 +++++--- video/out/gpu/video_shaders.c | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) (limited to 'video') diff --git a/video/csputils.c b/video/csputils.c index 6833f583fb..f9b6c98689 100644 --- a/video/csputils.c +++ b/video/csputils.c @@ -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; diff --git a/video/csputils.h b/video/csputils.h index 34e2894a28..965c313a02 100644 --- a/video/csputils.h +++ b/video/csputils.h @@ -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); diff --git a/video/out/gpu/video_shaders.c b/video/out/gpu/video_shaders.c index ff1660c85a..ba7caeaeec 100644 --- a/video/out/gpu/video_shaders.c +++ b/video/out/gpu/video_shaders.c @@ -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; -- cgit v1.2.3