1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-25 08:12:17 +00:00

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
This commit is contained in:
Niklas Haas 2018-02-14 16:10:51 +01:00 committed by Jan Ekström
parent 1f881eca65
commit 441e384390
4 changed files with 49 additions and 7 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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) {