summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.xyz>2018-02-14 16:10:51 +0100
committerJan Ekström <jeebjp@gmail.com>2018-02-20 22:02:51 +0200
commit441e384390f1cd1b1b1c159cb797429432a09493 (patch)
tree1c6cefb9d64c3298a461723da0fc4f148fe10deb
parent1f881eca656127d5235d44acf1562091864e07c7 (diff)
downloadmpv-441e384390f1cd1b1b1c159cb797429432a09493.tar.bz2
mpv-441e384390f1cd1b1b1c159cb797429432a09493.tar.xz
vo_gpu: introduce --target-peak
This solves a number of problems simultaneously: 1. When outputting HLG, this allows tuning the OOTF based on the display characteristics. 2. When outputting PQ or other HDR curves, this allows soft-limiting the output brightness using the tone mapping algorithm. 3. When outputting SDR, this allows HDR-in-SDR style output, by controlling the output brightness directly. Closes #5521
-rw-r--r--DOCS/man/options.rst33
-rw-r--r--video/out/gpu/video.c11
-rw-r--r--video/out/gpu/video.h2
-rw-r--r--video/out/gpu/video_shaders.c10
4 files changed, 49 insertions, 7 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index e51f564490..1a5af8121a 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -5054,6 +5054,39 @@ The following video options are currently all specific to ``--vo=gpu`` and
The user should independently guarantee this before using these signal
formats for display.
+``--target-peak=<nits>``
+ Specifies the measured peak brightness of the output display, in cd/m^2
+ (AKA nits). The interpretation of this brightness depends on the configured
+ ``--target-trc``. In all cases, it imposes a limit on the signal values
+ that will be sent to the display. If the source exceeds this brightness
+ level, a tone mapping filter will be inserted. For HLG, it has the
+ 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
+ display in disguise. (See the note below)
+
+ By default, the chosen peak defaults to an appropriate value based on the
+ TRC in use. For SDR curves, it defaults to 100. For HDR curves, it
+ defaults to 100 * the transfer function's nominal peak.
+
+ .. note::
+
+ When using an SDR transfer function, this is normally not needed, and
+ setting it may lead to very unexpected results. The one time it *is*
+ useful is if you want to calibrate a HDR display using traditional
+ transfer functions and calibration equipment. In such cases, you can
+ set your HDR display to a high brightness such as 800 cd/m^2, and then
+ calibrate it to a standard curve like gamma2.8. Setting this value to
+ 800 would then instruct mpv to essentially treat it as an HDR display
+ with the given peak. This may be a good alternative in environments
+ where PQ or HLG input to the display is not possible, and makes it
+ possible to use HDR displays with mpv regardless of operating system
+ support for HDMI HDR metadata.
+
+ In such a configuration, we highly recommend setting ``--tone-mapping``
+ to ``mobius`` or even ``clip``.
+
``--tone-mapping=<value>``
Specifies the algorithm used for tone-mapping images onto the target
display. This is relevant for both HDR->SDR conversion as well as gamut
diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c
index fdefc0044f..4e9f6d5e27 100644
--- a/video/out/gpu/video.c
+++ b/video/out/gpu/video.c
@@ -351,6 +351,7 @@ const struct m_sub_options gl_video_conf = {
OPT_FLAG("gamma-auto", gamma_auto, 0),
OPT_CHOICE_C("target-prim", target_prim, 0, mp_csp_prim_names),
OPT_CHOICE_C("target-trc", target_trc, 0, mp_csp_trc_names),
+ OPT_INTRANGE("target-peak", target_peak, 0, 10, 10000),
OPT_CHOICE("tone-mapping", tone_mapping, 0,
({"clip", TONE_MAPPING_CLIP},
{"mobius", TONE_MAPPING_MOBIUS},
@@ -548,6 +549,7 @@ struct mp_colorspace gl_video_get_output_colorspace(struct gl_video *p)
return (struct mp_colorspace) {
.primaries = p->opts.target_prim,
.gamma = p->opts.target_trc,
+ .sig_peak = p->opts.target_peak / MP_REF_WHITE,
};
}
@@ -2392,6 +2394,7 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, bool
.gamma = p->opts.target_trc,
.primaries = p->opts.target_prim,
.light = MP_CSP_LIGHT_DISPLAY,
+ .sig_peak = p->opts.target_peak / MP_REF_WHITE,
};
if (p->use_lut_3d) {
@@ -2446,10 +2449,10 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, bool
dst.gamma = MP_CSP_TRC_GAMMA22;
}
- // For now, just infer the dst sig peak from the gamma function always.
- // In theory, we could allow users to configure this or detect it from the
- // ICC profile, but avoid the complexity for now.
- dst.sig_peak = mp_trc_nom_peak(dst.gamma);
+ // If there's no specific signal peak known for the output display, infer
+ // it from the chosen transfer function
+ if (!dst.sig_peak)
+ dst.sig_peak = mp_trc_nom_peak(dst.gamma);
bool detect_peak = p->opts.compute_hdr_peak >= 0 && mp_trc_is_hdr(src.gamma);
if (detect_peak && !p->hdr_peak_ssbo) {
diff --git a/video/out/gpu/video.h b/video/out/gpu/video.h
index 80f31c2934..f385661e47 100644
--- a/video/out/gpu/video.h
+++ b/video/out/gpu/video.h
@@ -106,7 +106,7 @@ struct gl_video_opts {
int gamma_auto;
int target_prim;
int target_trc;
- int target_brightness;
+ int target_peak;
int tone_mapping;
int compute_hdr_peak;
float tone_mapping_param;
diff --git a/video/out/gpu/video_shaders.c b/video/out/gpu/video_shaders.c
index d8a26542b0..b588b8e500 100644
--- a/video/out/gpu/video_shaders.c
+++ b/video/out/gpu/video_shaders.c
@@ -812,8 +812,14 @@ void pass_color_map(struct gl_shader_cache *sc,
if (need_ootf)
pass_inverse_ootf(sc, dst.light, dst.sig_peak);
- // Post-scale the outgoing values from absolute scale to normalized
- GLSLF("color.rgb *= vec3(%f);\n", 1.0 / mp_trc_nom_peak(dst.gamma));
+ // Post-scale the outgoing values from absolute scale to normalized.
+ // For SDR, we normalize to the chosen signal peak. For HDR, we normalize
+ // to the encoding range of the transfer function.
+ float dst_range = dst.sig_peak;
+ if (mp_trc_is_hdr(dst.gamma))
+ dst_range = mp_trc_nom_peak(dst.gamma);
+
+ GLSLF("color.rgb *= vec3(%f);\n", 1.0 / dst_range);
// Warn for remaining out-of-gamut colors is enabled
if (gamut_warning) {