mirror of https://github.com/mpv-player/mpv
vo_opengl: add --tone-mapping-desaturate
This helps prevent unnaturally, weirdly colorized blown out highlights for direct images of the sunlit sky and other way-too-bright HDR content. I was debating whether to set the default at 1.0 or 2.0, but went with the more conservative option that preserves more detail/color.
This commit is contained in:
parent
6f77444f6c
commit
9e04018f92
|
@ -4723,6 +4723,16 @@ The following video options are currently all specific to ``--vo=opengl`` and
|
||||||
linear
|
linear
|
||||||
Specifies the scale factor to use while stretching. Defaults to 1.0.
|
Specifies the scale factor to use while stretching. Defaults to 1.0.
|
||||||
|
|
||||||
|
``--tone-mapping-desaturate=<value>``
|
||||||
|
Apply desaturation for highlights that exceed this level of brightness. The
|
||||||
|
higher the parameter, the more color information will be preserved. This
|
||||||
|
setting helps prevent unnaturally blown-out colors for super-highlights, by
|
||||||
|
(smoothly) turning into white instead. This makes images feel more natural,
|
||||||
|
at the cost of reducing information about out-of-range colors.
|
||||||
|
|
||||||
|
The default of 2.0 is somewhat conservative and will mostly just apply to
|
||||||
|
skies or directly sunlit surfaces. A setting of 0.0 disables this option.
|
||||||
|
|
||||||
``--icc-profile=<file>``
|
``--icc-profile=<file>``
|
||||||
Load an ICC profile and use it to transform video RGB to screen output.
|
Load an ICC profile and use it to transform video RGB to screen output.
|
||||||
Needs LittleCMS 2 support compiled in. This option overrides the
|
Needs LittleCMS 2 support compiled in. This option overrides the
|
||||||
|
|
|
@ -311,6 +311,7 @@ static const struct gl_video_opts gl_video_opts_def = {
|
||||||
.gamma = 1.0f,
|
.gamma = 1.0f,
|
||||||
.hdr_tone_mapping = TONE_MAPPING_MOBIUS,
|
.hdr_tone_mapping = TONE_MAPPING_MOBIUS,
|
||||||
.tone_mapping_param = NAN,
|
.tone_mapping_param = NAN,
|
||||||
|
.tone_mapping_desat = 2.0,
|
||||||
.early_flush = -1,
|
.early_flush = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -352,6 +353,7 @@ const struct m_sub_options gl_video_conf = {
|
||||||
{"gamma", TONE_MAPPING_GAMMA},
|
{"gamma", TONE_MAPPING_GAMMA},
|
||||||
{"linear", TONE_MAPPING_LINEAR})),
|
{"linear", TONE_MAPPING_LINEAR})),
|
||||||
OPT_FLOAT("tone-mapping-param", tone_mapping_param, 0),
|
OPT_FLOAT("tone-mapping-param", tone_mapping_param, 0),
|
||||||
|
OPT_FLOAT("tone-mapping-desaturate", tone_mapping_desat, 0),
|
||||||
OPT_FLAG("opengl-pbo", pbo, 0),
|
OPT_FLAG("opengl-pbo", pbo, 0),
|
||||||
SCALER_OPTS("scale", SCALER_SCALE),
|
SCALER_OPTS("scale", SCALER_SCALE),
|
||||||
SCALER_OPTS("dscale", SCALER_DSCALE),
|
SCALER_OPTS("dscale", SCALER_DSCALE),
|
||||||
|
@ -2251,7 +2253,8 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, bool
|
||||||
|
|
||||||
// Adapt from src to dst as necessary
|
// Adapt from src to dst as necessary
|
||||||
pass_color_map(p->sc, src, dst, p->opts.hdr_tone_mapping,
|
pass_color_map(p->sc, src, dst, p->opts.hdr_tone_mapping,
|
||||||
p->opts.tone_mapping_param, p->use_linear && !osd);
|
p->opts.tone_mapping_param, p->opts.tone_mapping_desat,
|
||||||
|
p->use_linear && !osd);
|
||||||
|
|
||||||
if (p->use_lut_3d) {
|
if (p->use_lut_3d) {
|
||||||
gl_sc_uniform_tex(p->sc, "lut_3d", GL_TEXTURE_3D, p->lut_3d_texture);
|
gl_sc_uniform_tex(p->sc, "lut_3d", GL_TEXTURE_3D, p->lut_3d_texture);
|
||||||
|
@ -3201,6 +3204,7 @@ static void check_gl_features(struct gl_video *p)
|
||||||
.tex_pad_y = p->opts.tex_pad_y,
|
.tex_pad_y = p->opts.tex_pad_y,
|
||||||
.hdr_tone_mapping = p->opts.hdr_tone_mapping,
|
.hdr_tone_mapping = p->opts.hdr_tone_mapping,
|
||||||
.tone_mapping_param = p->opts.tone_mapping_param,
|
.tone_mapping_param = p->opts.tone_mapping_param,
|
||||||
|
.tone_mapping_desat = p->opts.tone_mapping_desat,
|
||||||
.early_flush = p->opts.early_flush,
|
.early_flush = p->opts.early_flush,
|
||||||
};
|
};
|
||||||
for (int n = 0; n < SCALER_COUNT; n++)
|
for (int n = 0; n < SCALER_COUNT; n++)
|
||||||
|
|
|
@ -110,6 +110,7 @@ struct gl_video_opts {
|
||||||
int target_brightness;
|
int target_brightness;
|
||||||
int hdr_tone_mapping;
|
int hdr_tone_mapping;
|
||||||
float tone_mapping_param;
|
float tone_mapping_param;
|
||||||
|
float tone_mapping_desat;
|
||||||
int linear_scaling;
|
int linear_scaling;
|
||||||
int correct_downscaling;
|
int correct_downscaling;
|
||||||
int sigmoid_upscaling;
|
int sigmoid_upscaling;
|
||||||
|
|
|
@ -522,7 +522,7 @@ void pass_inverse_ootf(struct gl_shader_cache *sc, enum mp_csp_light light, floa
|
||||||
|
|
||||||
// Tone map from a known peak brightness to the range [0,1]
|
// Tone map from a known peak brightness to the range [0,1]
|
||||||
static void pass_tone_map(struct gl_shader_cache *sc, float ref_peak,
|
static void pass_tone_map(struct gl_shader_cache *sc, float ref_peak,
|
||||||
enum tone_mapping algo, float param)
|
enum tone_mapping algo, float param, float desat)
|
||||||
{
|
{
|
||||||
GLSLF("// HDR tone mapping\n");
|
GLSLF("// HDR tone mapping\n");
|
||||||
|
|
||||||
|
@ -530,6 +530,12 @@ static void pass_tone_map(struct gl_shader_cache *sc, float ref_peak,
|
||||||
GLSL(float luma = dot(src_luma, color.rgb);)
|
GLSL(float luma = dot(src_luma, color.rgb);)
|
||||||
GLSL(float luma_orig = luma;)
|
GLSL(float luma_orig = luma;)
|
||||||
|
|
||||||
|
// Desaturate the color using a coefficient dependent on the brightness
|
||||||
|
if (desat > 0 && ref_peak > desat) {
|
||||||
|
GLSLF("float overbright = max(0.0, (luma - %f) / luma);\n", desat);
|
||||||
|
GLSL(color.rgb = mix(color.rgb, vec3(luma), overbright);)
|
||||||
|
}
|
||||||
|
|
||||||
switch (algo) {
|
switch (algo) {
|
||||||
case TONE_MAPPING_CLIP:
|
case TONE_MAPPING_CLIP:
|
||||||
GLSL(luma = clamp(luma, 0.0, 1.0);)
|
GLSL(luma = clamp(luma, 0.0, 1.0);)
|
||||||
|
@ -593,7 +599,7 @@ static void pass_tone_map(struct gl_shader_cache *sc, float ref_peak,
|
||||||
void pass_color_map(struct gl_shader_cache *sc,
|
void pass_color_map(struct gl_shader_cache *sc,
|
||||||
struct mp_colorspace src, struct mp_colorspace dst,
|
struct mp_colorspace src, struct mp_colorspace dst,
|
||||||
enum tone_mapping algo, float tone_mapping_param,
|
enum tone_mapping algo, float tone_mapping_param,
|
||||||
bool is_linear)
|
float tone_mapping_desat, bool is_linear)
|
||||||
{
|
{
|
||||||
GLSLF("// color mapping\n");
|
GLSLF("// color mapping\n");
|
||||||
|
|
||||||
|
@ -635,8 +641,10 @@ void pass_color_map(struct gl_shader_cache *sc,
|
||||||
|
|
||||||
// Tone map to prevent clipping when the source signal peak exceeds the
|
// Tone map to prevent clipping when the source signal peak exceeds the
|
||||||
// encodable range
|
// encodable range
|
||||||
if (src.sig_peak > dst_range)
|
if (src.sig_peak > dst_range) {
|
||||||
pass_tone_map(sc, src.sig_peak / dst_range, algo, tone_mapping_param);
|
pass_tone_map(sc, src.sig_peak / dst_range, algo, tone_mapping_param,
|
||||||
|
tone_mapping_desat);
|
||||||
|
}
|
||||||
|
|
||||||
// Adapt to the right colorspace if necessary
|
// Adapt to the right colorspace if necessary
|
||||||
if (src.primaries != dst.primaries) {
|
if (src.primaries != dst.primaries) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ void pass_inverse_ootf(struct gl_shader_cache *sc, enum mp_csp_light light, floa
|
||||||
void pass_color_map(struct gl_shader_cache *sc,
|
void pass_color_map(struct gl_shader_cache *sc,
|
||||||
struct mp_colorspace src, struct mp_colorspace dst,
|
struct mp_colorspace src, struct mp_colorspace dst,
|
||||||
enum tone_mapping algo, float tone_mapping_param,
|
enum tone_mapping algo, float tone_mapping_param,
|
||||||
bool skip_linearization);
|
float tone_mapping_desat, bool is_linear);
|
||||||
|
|
||||||
void pass_sample_deband(struct gl_shader_cache *sc, struct deband_opts *opts,
|
void pass_sample_deband(struct gl_shader_cache *sc, struct deband_opts *opts,
|
||||||
AVLFG *lfg);
|
AVLFG *lfg);
|
||||||
|
|
Loading…
Reference in New Issue