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:
Niklas Haas 2017-07-06 05:43:00 +02:00
parent 6f77444f6c
commit 9e04018f92
No known key found for this signature in database
GPG Key ID: 9A09076581B27402
5 changed files with 29 additions and 6 deletions

View File

@ -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

View File

@ -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++)

View File

@ -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;

View File

@ -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) {

View File

@ -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);