summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.xyz>2020-05-17 03:17:28 +0200
committerNiklas Haas <git@haasn.xyz>2020-06-15 01:24:04 +0200
commitef6bc8504a945eb6492b8ed46fd5a1afaaf32182 (patch)
tree31a0beaa61c89e4e0dacec9e0cd52c559a9b84fc
parentc7fe4ae73ad5f073bbffe3e8a3460b728e7d0f46 (diff)
downloadmpv-ef6bc8504a945eb6492b8ed46fd5a1afaaf32182.tar.bz2
mpv-ef6bc8504a945eb6492b8ed46fd5a1afaaf32182.tar.xz
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.
-rw-r--r--DOCS/man/options.rst6
-rw-r--r--video/csputils.c2
-rw-r--r--video/csputils.h8
-rw-r--r--video/out/gpu/video_shaders.c6
4 files changed, 13 insertions, 9 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index 769db4d837..4850439a8a 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -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::
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;