summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.dev>2022-01-04 01:50:00 +0100
committerNiklas Haas <github-daiK1o@haasn.dev>2022-01-07 06:28:14 +0100
commitd09c73c7b2b0135cb24ab2173b3c4ee1c55840b0 (patch)
tree02b33ac09f5720cfa328c747d2481a6a82d7d09b
parentf3fccfc395ddb7a504ab2aae48452178fa92d907 (diff)
downloadmpv-d09c73c7b2b0135cb24ab2173b3c4ee1c55840b0.tar.bz2
mpv-d09c73c7b2b0135cb24ab2173b3c4ee1c55840b0.tar.xz
vo_gpu: add --tone-mapping-mode
This merges the old desaturation control options into a single enumeration, with the goal of both simplifying how these options work and also making this list more extensible (including, notably, new options only supported by vo_gpu_next). For the hybrid option, I decided to port the (slightly tweaked) values from libplacebo's pre-refactor defaults, rather than the old values we had in mpv, to more visually match the look of the vo_gpu_next hybrid.
-rw-r--r--DOCS/interface-changes.rst2
-rw-r--r--DOCS/man/options.rst43
-rw-r--r--video/out/gpu/video.c25
-rw-r--r--video/out/gpu/video.h11
-rw-r--r--video/out/gpu/video_shaders.c30
-rw-r--r--video/out/vo_gpu_next.c9
6 files changed, 80 insertions, 40 deletions
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst
index 75516627df..48c5b62881 100644
--- a/DOCS/interface-changes.rst
+++ b/DOCS/interface-changes.rst
@@ -36,6 +36,8 @@ Interface changes
- add `--tone-mapping` options `auto`, `spline` and `bt.2446a`
- add `--inverse-tone-mapping`
- add `--gamut-mapping-mode`, replacing `--gamut-clipping` and `--gamut-warning`
+ - add `--tone-mapping-mode`, replacing `--tone-mapping-desaturate` and
+ `--tone-mapping-desaturate-exponent`.
--- mpv 0.34.0 ---
- deprecate selecting by card number with `--drm-connector`, add
`--drm-device` which can be used instead
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index bd2b9be470..7b51b585e8 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -6385,6 +6385,28 @@ them.
it too high will make dark scenes appear unnaturally bright. (``-vo=gpu``
only)
+``--tone-mapping-mode``
+ Controls how the tone mapping function is applied to colors.
+
+ auto
+ Choose the best mode automatically. (Default)
+ rgb
+ Tone-map per-channel (RGB). Has a tendency to severely distort colors,
+ desaturate highlights, and is generally not very recommended. However,
+ this is the mode used in many displays and TVs (especially early ones),
+ and so sometimes it's needed to reproduce the artistic intent a film
+ was mastered with.
+ max
+ Tone-map on the brightest component in the video. Has a tendency to
+ lead to weirdly oversaturated colors, and loss of dark details.
+ hybrid
+ A hybrid approach that uses linear tone-mapping for midtones and
+ per-channel tone mapping for highlights.
+ luma
+ Luminance-based method from ITU-R BT.2446a, including fixed gamut
+ reductions to account for brightness-related perceptual nonuniformity.
+ (``--vo=gpu-next`` only)
+
``--gamut-mapping-mode``
Specifies the algorithm used for reducing the gamut of images for the
target display, after any tone mapping is done.
@@ -6445,27 +6467,6 @@ them.
aggressive, up to the limit of the high threshold (at which point the
filter becomes instant).
-``--tone-mapping-desaturate=<0.0..1.0>``
- Apply desaturation for highlights (default: 0.75). The parameter controls
- the strength of the desaturation curve. A value of 0.0 completely disables
- it, while a value of 1.0 means that overly bright colors will tend towards
- white. This is not always the case, especially not for highlights that are
- near primary colors. (``--vo=gpu`` only)
-
- Values in between apply progressively more/less aggressive desaturation.
- This setting helps prevent unnaturally oversaturated colors for
- super-highlights, by (smoothly) turning them into less saturated (per
- channel tone mapped) colors instead. This makes images feel more natural,
- at the cost of chromatic distortions for out-of-range colors. The default
- value of 0.75 provides a good balance. Setting this to 0.0 preserves the
- chromatic accuracy of the tone mapping process.
-
-``--tone-mapping-desaturate-exponent=<0.0..20.0>``
- This setting controls the exponent of the desaturation curve, which
- controls how bright a color needs to be in order to start being
- desaturated. The default of 1.5 provides a reasonable balance. Decreasing
- this exponent makes the curve more aggressive.
-
``--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
diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c
index 8236a7b43f..d0d0509792 100644
--- a/video/out/gpu/video.c
+++ b/video/out/gpu/video.c
@@ -329,8 +329,6 @@ static const struct gl_video_opts gl_video_opts_def = {
.decay_rate = 100.0,
.scene_threshold_low = 5.5,
.scene_threshold_high = 10.0,
- .desat = 0.75,
- .desat_exp = 1.5,
},
.early_flush = -1,
.hwdec_interop = "auto",
@@ -394,9 +392,12 @@ const struct m_sub_options gl_video_conf = {
M_RANGE(0.0, 0.3)},
{"tone-mapping-max-boost", OPT_FLOAT(tone_map.max_boost),
M_RANGE(1.0, 10.0)},
- {"tone-mapping-desaturate", OPT_FLOAT(tone_map.desat)},
- {"tone-mapping-desaturate-exponent", OPT_FLOAT(tone_map.desat_exp),
- M_RANGE(0.0, 20.0)},
+ {"tone-mapping-mode", OPT_CHOICE(tone_map.mode,
+ {"auto", TONE_MAP_MODE_AUTO},
+ {"rgb", TONE_MAP_MODE_RGB},
+ {"max", TONE_MAP_MODE_MAX},
+ {"hybrid", TONE_MAP_MODE_HYBRID},
+ {"luma", TONE_MAP_MODE_LUMA})},
{"gamut-mapping-mode", OPT_CHOICE(tone_map.gamut_mode,
{"auto", GAMUT_AUTO},
{"clip", GAMUT_CLIP},
@@ -479,6 +480,8 @@ const struct m_sub_options gl_video_conf = {
"--linear-downscaling")},
{"gamut-warning", OPT_REMOVED("Replaced by --gamut-mapping-mode=warn")},
{"gamut-clipping", OPT_REMOVED("Replaced by --gamut-mapping-mode=desaturate")},
+ {"tone-mapping-desaturate", OPT_REMOVED("Replaced by --tone-mapping-mode")},
+ {"tone-mapping-desaturate-exponent", OPT_REMOVED("Replaced by --tone-mapping-mode")},
{0}
},
.size = sizeof(struct gl_video_opts),
@@ -2644,6 +2647,18 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src,
break;
}
+ switch (p->opts.tone_map.mode) {
+ case TONE_MAP_MODE_AUTO:
+ case TONE_MAP_MODE_RGB:
+ case TONE_MAP_MODE_MAX:
+ case TONE_MAP_MODE_HYBRID:
+ break;
+ default:
+ MP_WARN(p, "Tone mapping mode unsupported by vo_gpu, falling back.\n");
+ p->opts.tone_map.mode = TONE_MAP_MODE_AUTO;
+ break;
+ }
+
switch (p->opts.tone_map.gamut_mode) {
case GAMUT_AUTO:
case GAMUT_WARN:
diff --git a/video/out/gpu/video.h b/video/out/gpu/video.h
index adeadaba65..0bb180e514 100644
--- a/video/out/gpu/video.h
+++ b/video/out/gpu/video.h
@@ -100,6 +100,14 @@ enum tone_mapping {
TONE_MAPPING_BT_2446A,
};
+enum tone_mapping_mode {
+ TONE_MAP_MODE_AUTO,
+ TONE_MAP_MODE_RGB,
+ TONE_MAP_MODE_MAX,
+ TONE_MAP_MODE_HYBRID,
+ TONE_MAP_MODE_LUMA,
+};
+
enum gamut_mode {
GAMUT_AUTO,
GAMUT_CLIP,
@@ -114,12 +122,11 @@ struct gl_tone_map_opts {
float max_boost;
int inverse;
float crosstalk;
+ int mode;
int compute_peak;
float decay_rate;
float scene_threshold_low;
float scene_threshold_high;
- float desat;
- float desat_exp;
int gamut_mode;
};
diff --git a/video/out/gpu/video_shaders.c b/video/out/gpu/video_shaders.c
index 6dcef77fa0..9628274b19 100644
--- a/video/out/gpu/video_shaders.c
+++ b/video/out/gpu/video_shaders.c
@@ -809,18 +809,24 @@ static void pass_tone_map(struct gl_shader_cache *sc,
abort();
}
- GLSL(vec3 sig_lin = color.rgb * (sig[sig_idx] / sig_orig);)
-
- // Mix between the per-channel tone mapped and the linear tone mapped
- // signal based on the desaturation strength
- if (opts->desat > 0) {
- float base = 0.18 * dst_scale;
- GLSLF("float coeff = max(sig[sig_idx] - %f, 1e-6) / "
- " max(sig[sig_idx], 1.0);\n", base);
- GLSLF("coeff = %f * pow(coeff, %f);\n", opts->desat, opts->desat_exp);
- GLSLF("color.rgb = mix(sig_lin, %f * sig, coeff);\n", dst_scale);
- } else {
- GLSL(color.rgb = sig_lin;)
+ switch (opts->mode) {
+ case TONE_MAP_MODE_RGB:
+ GLSL(color.rgb = sig;)
+ break;
+ case TONE_MAP_MODE_MAX:
+ GLSL(color.rgb *= sig[sig_idx] / sig_orig;)
+ break;
+ case TONE_MAP_MODE_AUTO:
+ case TONE_MAP_MODE_HYBRID:
+ GLSLF("float coeff = max(sig[sig_idx] - %f, 1e-6) / \n"
+ " max(sig[sig_idx], 1.0); \n"
+ "coeff = %f * pow(coeff / %f, %f); \n"
+ "color.rgb *= sig[sig_idx] / sig_orig; \n"
+ "color.rgb = mix(color.rgb, %f * sig, coeff); \n",
+ 0.18 / dst_scale, 0.90, dst_scale, 0.20, dst_scale);
+ break;
+ default:
+ abort();
}
}
diff --git a/video/out/vo_gpu_next.c b/video/out/vo_gpu_next.c
index 390852ff71..9bbb58101f 100644
--- a/video/out/vo_gpu_next.c
+++ b/video/out/vo_gpu_next.c
@@ -1406,12 +1406,21 @@ static void update_render_options(struct priv *p)
[GAMUT_DARKEN] = PL_GAMUT_DARKEN,
};
+ static const enum pl_tone_map_mode tone_map_modes[] = {
+ [TONE_MAP_MODE_AUTO] = PL_TONE_MAP_AUTO,
+ [TONE_MAP_MODE_RGB] = PL_TONE_MAP_RGB,
+ [TONE_MAP_MODE_MAX] = PL_TONE_MAP_MAX,
+ [TONE_MAP_MODE_HYBRID] = PL_TONE_MAP_HYBRID,
+ [TONE_MAP_MODE_LUMA] = PL_TONE_MAP_LUMA,
+ };
+
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];
p->color_map.tone_mapping_param = opts->tone_map.curve_param;
p->color_map.inverse_tone_mapping = opts->tone_map.inverse;
p->color_map.tone_mapping_crosstalk = opts->tone_map.crosstalk;
+ p->color_map.tone_mapping_mode = tone_map_modes[opts->tone_map.mode];
if (isnan(p->color_map.tone_mapping_param)) // vo_gpu compatibility
p->color_map.tone_mapping_param = 0.0;
if (opts->tone_map.gamut_mode != GAMUT_AUTO)