vo_gpu: add --gamut-mapping-mode

Merge --gamut-clipping and --gamut-warning into a single option,
--gamut-mapping-mode, better corresponding to the new vo_gpu_next APIs
and allowing us to easily extend this option as new modes are added in
the future.
This commit is contained in:
Niklas Haas 2022-01-03 04:31:50 +01:00 committed by Niklas Haas
parent 2332445d8d
commit f3fccfc395
6 changed files with 60 additions and 32 deletions

View File

@ -35,6 +35,7 @@ Interface changes
- add `--tone-mapping-crosstalk`
- add `--tone-mapping` options `auto`, `spline` and `bt.2446a`
- add `--inverse-tone-mapping`
- add `--gamut-mapping-mode`, replacing `--gamut-clipping` and `--gamut-warning`
--- mpv 0.34.0 ---
- deprecate selecting by card number with `--drm-connector`, add
`--drm-device` which can be used instead

View File

@ -6385,6 +6385,24 @@ them.
it too high will make dark scenes appear unnaturally bright. (``-vo=gpu``
only)
``--gamut-mapping-mode``
Specifies the algorithm used for reducing the gamut of images for the
target display, after any tone mapping is done.
auto
Choose the best mode automatically. (Default)
clip
Hard-clip to the gamut (per-channel).
warn
Simply highlight out-of-gamut pixels.
desaturate
Chromatically desaturate out-of-gamut colors towards white.
darken
Linearly darken the entire image, then clip to the color volume. Unlike
``clip``, this does not destroy detail in saturated regions, but comes
at the cost of sometimes significantly lowering output brightness.
(``--vo=gpu-next`` only)
``--hdr-compute-peak=<auto|yes|no>``
Compute the HDR peak and frame average brightness per-frame instead of
relying on tagged metadata. These values are averaged over local regions as
@ -6448,25 +6466,6 @@ them.
desaturated. The default of 1.5 provides a reasonable balance. Decreasing
this exponent makes the curve more aggressive.
``--gamut-warning``
If enabled, mpv will mark all clipped/out-of-gamut pixels that exceed a
given threshold (currently hard-coded to 101%). The affected pixels will be
inverted to make them stand out. Note: This option applies after the
effects of all of mpv's color space transformation / tone mapping options,
so it's a good idea to combine this with ``--tone-mapping=clip`` and use
``--target-prim`` to set the gamut to simulate. For example,
``--target-prim=bt.709`` would make mpv highlight all pixels that exceed the
gamut of a standard gamut (sRGB) display. This option also does not work
well with ICC profiles, since the 3DLUTs are always generated against the
source color space and have chromatically-accurate clipping built in.
``--gamut-clipping``
If enabled (default: yes), mpv will colorimetrically clip out-of-gamut
colors by desaturating them (preserving luma), rather than hard-clipping
each component individually. This should make playback of wide gamut
content on typical (standard gamut) monitors look much more aesthetically
pleasing and less blown-out.
``--use-embedded-icc-profile``
Load the embedded ICC profile contained in media files such as PNG images.
(Default: yes). Note that this option only works when also using a display

View File

@ -331,7 +331,6 @@ static const struct gl_video_opts gl_video_opts_def = {
.scene_threshold_high = 10.0,
.desat = 0.75,
.desat_exp = 1.5,
.gamut_clipping = 1,
},
.early_flush = -1,
.hwdec_interop = "auto",
@ -398,8 +397,12 @@ const struct m_sub_options gl_video_conf = {
{"tone-mapping-desaturate", OPT_FLOAT(tone_map.desat)},
{"tone-mapping-desaturate-exponent", OPT_FLOAT(tone_map.desat_exp),
M_RANGE(0.0, 20.0)},
{"gamut-warning", OPT_FLAG(tone_map.gamut_warning)},
{"gamut-clipping", OPT_FLAG(tone_map.gamut_clipping)},
{"gamut-mapping-mode", OPT_CHOICE(tone_map.gamut_mode,
{"auto", GAMUT_AUTO},
{"clip", GAMUT_CLIP},
{"warn", GAMUT_WARN},
{"desaturate", GAMUT_DESATURATE},
{"darken", GAMUT_DARKEN})},
{"hdr-compute-peak", OPT_CHOICE(tone_map.compute_peak,
{"auto", 0},
{"yes", 1},
@ -474,6 +477,8 @@ const struct m_sub_options gl_video_conf = {
{"opengl-gamma", OPT_REPLACED("gamma-factor")},
{"linear-scaling", OPT_REMOVED("Split into --linear-upscaling and "
"--linear-downscaling")},
{"gamut-warning", OPT_REMOVED("Replaced by --gamut-mapping-mode=warn")},
{"gamut-clipping", OPT_REMOVED("Replaced by --gamut-mapping-mode=desaturate")},
{0}
},
.size = sizeof(struct gl_video_opts),
@ -2639,6 +2644,18 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src,
break;
}
switch (p->opts.tone_map.gamut_mode) {
case GAMUT_AUTO:
case GAMUT_WARN:
case GAMUT_CLIP:
case GAMUT_DESATURATE:
break;
default:
MP_WARN(p, "Gamut mapping mode unsupported by vo_gpu, falling back.\n");
p->opts.tone_map.gamut_mode = GAMUT_AUTO;
break;
}
struct gl_tone_map_opts tone_map = p->opts.tone_map;
bool detect_peak = tone_map.compute_peak >= 0 && mp_trc_is_hdr(src.gamma)
&& src.sig_peak > dst.sig_peak;

View File

@ -100,6 +100,14 @@ enum tone_mapping {
TONE_MAPPING_BT_2446A,
};
enum gamut_mode {
GAMUT_AUTO,
GAMUT_CLIP,
GAMUT_WARN,
GAMUT_DESATURATE,
GAMUT_DARKEN,
};
struct gl_tone_map_opts {
int curve;
float curve_param;
@ -112,8 +120,7 @@ struct gl_tone_map_opts {
float scene_threshold_high;
float desat;
float desat_exp;
int gamut_warning; // bool
int gamut_clipping; // bool
int gamut_mode;
};
struct gl_video_opts {

View File

@ -882,7 +882,7 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear,
gl_sc_uniform_mat3(sc, "cms_matrix", true, &m[0][0]);
GLSL(color.rgb = cms_matrix * color.rgb;)
if (opts->gamut_clipping) {
if (!opts->gamut_mode || opts->gamut_mode == GAMUT_DESATURATE) {
GLSL(float cmin = min(min(color.r, color.g), color.b);)
GLSL(if (cmin < 0.0) {
float luma = dot(dst_luma, color.rgb);
@ -907,8 +907,8 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear,
GLSLF("color.rgb *= vec3(%f);\n", 1.0 / dst_range);
// Warn for remaining out-of-gamut colors is enabled
if (opts->gamut_warning) {
// Warn for remaining out-of-gamut colors if enabled
if (opts->gamut_mode == GAMUT_WARN) {
GLSL(if (any(greaterThan(color.rgb, vec3(1.005))) ||
any(lessThan(color.rgb, vec3(-0.005)))))
GLSL(color.rgb = vec3(1.0) - color.rgb;) // invert

View File

@ -1399,6 +1399,13 @@ static void update_render_options(struct priv *p)
[TONE_MAPPING_BT_2446A] = &pl_tone_map_bt2446a,
};
static const enum pl_gamut_mode gamut_modes[] = {
[GAMUT_CLIP] = PL_GAMUT_CLIP,
[GAMUT_WARN] = PL_GAMUT_WARN,
[GAMUT_DESATURATE] = PL_GAMUT_DESATURATE,
[GAMUT_DARKEN] = PL_GAMUT_DARKEN,
};
p->color_map = pl_color_map_default_params;
p->color_map.intent = opts->icc_opts->intent;
p->color_map.tone_mapping_function = tone_map_funs[opts->tone_map.curve];
@ -1407,11 +1414,8 @@ static void update_render_options(struct priv *p)
p->color_map.tone_mapping_crosstalk = opts->tone_map.crosstalk;
if (isnan(p->color_map.tone_mapping_param)) // vo_gpu compatibility
p->color_map.tone_mapping_param = 0.0;
if (opts->tone_map.gamut_clipping) {
p->color_map.gamut_mode = PL_GAMUT_DESATURATE;
} else if (opts->tone_map.gamut_warning) {
p->color_map.gamut_mode = PL_GAMUT_WARN;
}
if (opts->tone_map.gamut_mode != GAMUT_AUTO)
p->color_map.gamut_mode = gamut_modes[opts->tone_map.gamut_mode];
switch (opts->dither_algo) {
case DITHER_ERROR_DIFFUSION: