diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index 23bcb229fd..eb1de6a17c 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -76,6 +76,7 @@ Interface changes save cache files for these features; explictly setting `--icc-cache-dir` and `--gpu-shader-cache` is no longer required - remove the `--tone-mapping-crosstalk` option + - add `--gamut-mapping-mode=perceptual|relative|saturation|absolute|linear` --- mpv 0.35.0 --- - add the `--vo=gpu-next` video output driver, as well as the options `--allow-delayed-peak-detect`, `--builtin-scalers`, diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index cbdd3ede1b..ed85c44eca 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -6565,16 +6565,36 @@ them. 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. + Hard-clip to the gamut (per-channel). Very low quality, but free. + perceptual + Performs a perceptually balanced gamut mapping using a soft knee + function to roll-off clipped regions, and a hue shifting function to + preserve saturation. (``--vo=gpu-next`` only) + relative + Performs relative colorimetric clipping, while maintaining an + exponential relationship between brightness and chromaticity. (``--vo=gpu-next`` only) + saturation + Performs simple RGB->RGB saturation mapping. The input R/G/B channels + are mapped directly onto the output R/G/B channels. Will never clip, + but will distort all hues and/or result in a faded look. + (``--vo=gpu-next`` only) + absolute + Performs absolute colorimetric clipping. Like ``relative``, but does + not adapt the white point. (``--vo=gpu-next`` only) + desaturate + Performs constant-luminance colorimetric clipping, desaturing colors + towards white until they're in-range. + darken + Uniformly darkens the input slightly to prevent clipping on blown-out + highlights, then clamps colorimetrically to the input gamut boundary, + biased slightly to preserve chromaticity over luminance. + (``--vo=gpu-next`` only) + warn + Performs no gamut mapping, but simply highlights out-of-gamut pixels. + linear + Linearly/uniformly desaturates the image in order to bring the entire + image into the target gamut. (``--vo=gpu-next`` only) ``--hdr-compute-peak=`` Compute the HDR peak and frame average brightness per-frame instead of diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c index b957f71258..4ca5428098 100644 --- a/video/out/gpu/video.c +++ b/video/out/gpu/video.c @@ -400,9 +400,14 @@ const struct m_sub_options gl_video_conf = { {"gamut-mapping-mode", OPT_CHOICE(tone_map.gamut_mode, {"auto", GAMUT_AUTO}, {"clip", GAMUT_CLIP}, - {"warn", GAMUT_WARN}, + {"perceptual", GAMUT_PERCEPTUAL}, + {"relative", GAMUT_RELATIVE}, + {"saturation", GAMUT_SATURATION}, + {"absolute", GAMUT_ABSOLUTE}, {"desaturate", GAMUT_DESATURATE}, - {"darken", GAMUT_DARKEN})}, + {"darken", GAMUT_DARKEN}, + {"warn", GAMUT_WARN}, + {"linear", GAMUT_LINEAR})}, {"hdr-compute-peak", OPT_CHOICE(tone_map.compute_peak, {"auto", 0}, {"yes", 1}, diff --git a/video/out/gpu/video.h b/video/out/gpu/video.h index 5952998fa5..de70a8f801 100644 --- a/video/out/gpu/video.h +++ b/video/out/gpu/video.h @@ -113,9 +113,14 @@ enum tone_mapping_mode { enum gamut_mode { GAMUT_AUTO, GAMUT_CLIP, - GAMUT_WARN, + GAMUT_PERCEPTUAL, + GAMUT_RELATIVE, + GAMUT_SATURATION, + GAMUT_ABSOLUTE, GAMUT_DESATURATE, GAMUT_DARKEN, + GAMUT_WARN, + GAMUT_LINEAR, }; struct gl_tone_map_opts { diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c index 9916cbc6be..825c93178b 100644 --- a/video/out/vo_gpu_next.c +++ b/video/out/vo_gpu_next.c @@ -1862,9 +1862,14 @@ static void update_render_options(struct vo *vo) #if PL_API_VER >= 269 const struct pl_gamut_map_function *gamut_modes[] = { [GAMUT_CLIP] = &pl_gamut_map_clip, - [GAMUT_WARN] = &pl_gamut_map_highlight, + [GAMUT_PERCEPTUAL] = &pl_gamut_map_perceptual, + [GAMUT_RELATIVE] = &pl_gamut_map_relative, + [GAMUT_SATURATION] = &pl_gamut_map_saturation, + [GAMUT_ABSOLUTE] = &pl_gamut_map_absolute, [GAMUT_DESATURATE] = &pl_gamut_map_desaturate, [GAMUT_DARKEN] = &pl_gamut_map_darken, + [GAMUT_WARN] = &pl_gamut_map_highlight, + [GAMUT_LINEAR] = &pl_gamut_map_linear, }; // Back-compat approximation, taken from libplacebo source code @@ -1880,6 +1885,12 @@ static void update_render_options(struct vo *vo) [GAMUT_WARN] = PL_GAMUT_WARN, [GAMUT_DESATURATE] = PL_GAMUT_DESATURATE, [GAMUT_DARKEN] = PL_GAMUT_DARKEN, + // Unsupported + [GAMUT_PERCEPTUAL] = PL_GAMUT_CLIP, + [GAMUT_RELATIVE] = PL_GAMUT_CLIP, + [GAMUT_SATURATION] = PL_GAMUT_CLIP, + [GAMUT_ABSOLUTE] = PL_GAMUT_CLIP, + [GAMUT_LINEAR] = PL_GAMUT_CLIP, }; static const enum pl_tone_map_mode tone_map_modes[] = {