summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Haas <git@nand.wakku.to>2016-07-05 18:03:19 +0200
committerwm4 <wm4@nowhere>2016-07-05 19:16:49 +0200
commit329a7147d003f70a017ad6560a1b671b66ae2b62 (patch)
tree10827d1dcc0187f990e585eaec6c5cfffab24082
parent4f4eea6b440d8c45d2967eaaa7f099ca8899e03e (diff)
downloadmpv-329a7147d003f70a017ad6560a1b671b66ae2b62.tar.bz2
mpv-329a7147d003f70a017ad6560a1b671b66ae2b62.tar.xz
csp: document deviations from the references where they occur
These mostly happen in situations where the correct behavior is relatively new and not found in the wild (therefore not worth implementing) and/or extremely complicated (and thus not worth worrying about the potential edge cases and UI changes). Still, it's best to document these where they happen to guide the poor souls maintaining these files in the future.
-rw-r--r--video/csputils.c6
-rw-r--r--video/out/opengl/video_shaders.c24
2 files changed, 27 insertions, 3 deletions
diff --git a/video/csputils.c b/video/csputils.c
index 8ed3b289b1..ea55d4ddbe 100644
--- a/video/csputils.c
+++ b/video/csputils.c
@@ -545,7 +545,7 @@ static void mp_apply_chromatic_adaptation(struct mp_csp_col_xy src,
mp_mul_matrix3x3(m, tmp);
}
-// get the coefficients of the source -> bt2020 cms matrix
+// get the coefficients of the source -> dest cms matrix
void mp_get_cms_matrix(struct mp_csp_primaries src, struct mp_csp_primaries dest,
enum mp_render_intent intent, float m[3][3])
{
@@ -721,6 +721,10 @@ void mp_get_csp_matrix(struct mp_csp_params *params, struct mp_cmat *m)
// The values below are written in 0-255 scale - thus bring s into range.
double s =
mp_get_csp_mul(colorspace, params->input_bits, params->texture_bits) / 255;
+ // NOTE: The yuvfull ranges as presented here are arguably ambiguous,
+ // and conflict with at least the full-range YCbCr/ICtCp values as defined
+ // by ITU-R BT.2100. If somebody ever complains about full-range YUV looking
+ // different from their reference display, this comment is probably why.
struct yuvlevels { double ymin, ymax, cmin, cmid; }
yuvlim = { 16*s, 235*s, 16*s, 128*s },
yuvfull = { 0*s, 255*s, 1*s, 128*s }, // '1' for symmetry around 128
diff --git a/video/out/opengl/video_shaders.c b/video/out/opengl/video_shaders.c
index eded7d59c2..ff87b99b62 100644
--- a/video/out/opengl/video_shaders.c
+++ b/video/out/opengl/video_shaders.c
@@ -238,13 +238,20 @@ static const float VLOG_B = 0.00873,
VLOG_D = 0.598206,
VLOG_R = 46.085527; // nominal peak
-// Linearize (expand), given a TRC as input
+// Linearize (expand), given a TRC as input. This corresponds to the EOTF
+// in ITU-R terminology.
void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc)
{
if (trc == MP_CSP_TRC_LINEAR)
return;
+ // Note that this clamp may technically violate the definition of
+ // ITU-R BT.2100, which allows for sub-blacks and super-whites to be
+ // displayed on the display where such would be possible. That said, the
+ // problem is that not all gamma curves are well-defined on the values
+ // outside this range, so we ignore it and just clip anyway for sanity.
GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);)
+
switch (trc) {
case MP_CSP_TRC_SRGB:
GLSL(color.rgb = mix(color.rgb / vec3(12.92),
@@ -302,7 +309,8 @@ void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc)
}
}
-// Delinearize (compress), given a TRC as output
+// Delinearize (compress), given a TRC as output. This corresponds to the
+// inverse EOTF (not the OETF) in ITU-R terminology.
void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc)
{
if (trc == MP_CSP_TRC_LINEAR)
@@ -428,6 +436,18 @@ void pass_color_map(struct gl_shader_cache *sc,
if (need_gamma)
pass_linearize(sc, src.gamma);
+ // NOTE: When src.gamma = MP_CSP_TRC_ARIB_STD_B67, we would technically
+ // need to apply the reference OOTF as part of the EOTF (which is what we
+ // implement with pass_linearize), since HLG considers OOTF to be part of
+ // the display's EOTF (as opposed to the camera's OETF). But since this is
+ // stupid, complicated, arbitrary, and more importantly depends on the
+ // target display's signal peak (which is != the nom_peak in the case of
+ // HDR displays, and mpv already has enough target-specific display
+ // options), we just ignore its implementation entirely. (Plus, it doesn't
+ // even really make sense with tone mapping to begin with.) But just in
+ // case somebody ends up complaining about HLG looking different from a
+ // reference HLG display, this comment might be why.
+
// Stretch the signal value to renormalize to the dst nominal peak
if (src.nom_peak != dst.nom_peak)
GLSLF("color.rgb *= vec3(%f);\n", src.nom_peak / dst.nom_peak);