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:
parent
1f881eca65
commit
441e384390
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user