From 9e04018f920c6c8eed46a779af00f9543e6539d6 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Thu, 6 Jul 2017 05:43:00 +0200 Subject: 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. --- DOCS/man/options.rst | 10 ++++++++++ video/out/opengl/video.c | 6 +++++- video/out/opengl/video.h | 1 + video/out/opengl/video_shaders.c | 16 ++++++++++++---- video/out/opengl/video_shaders.h | 2 +- 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 896a6f3dad..7e6199b5e3 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -4723,6 +4723,16 @@ The following video options are currently all specific to ``--vo=opengl`` and linear Specifies the scale factor to use while stretching. Defaults to 1.0. +``--tone-mapping-desaturate=`` + 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=`` Load an ICC profile and use it to transform video RGB to screen output. Needs LittleCMS 2 support compiled in. This option overrides the diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index bc218792fd..f2f5260c74 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -311,6 +311,7 @@ static const struct gl_video_opts gl_video_opts_def = { .gamma = 1.0f, .hdr_tone_mapping = TONE_MAPPING_MOBIUS, .tone_mapping_param = NAN, + .tone_mapping_desat = 2.0, .early_flush = -1, }; @@ -352,6 +353,7 @@ const struct m_sub_options gl_video_conf = { {"gamma", TONE_MAPPING_GAMMA}, {"linear", TONE_MAPPING_LINEAR})), OPT_FLOAT("tone-mapping-param", tone_mapping_param, 0), + OPT_FLOAT("tone-mapping-desaturate", tone_mapping_desat, 0), OPT_FLAG("opengl-pbo", pbo, 0), SCALER_OPTS("scale", SCALER_SCALE), 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 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) { 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, .hdr_tone_mapping = p->opts.hdr_tone_mapping, .tone_mapping_param = p->opts.tone_mapping_param, + .tone_mapping_desat = p->opts.tone_mapping_desat, .early_flush = p->opts.early_flush, }; for (int n = 0; n < SCALER_COUNT; n++) diff --git a/video/out/opengl/video.h b/video/out/opengl/video.h index 4a51d421ad..b4f91b802f 100644 --- a/video/out/opengl/video.h +++ b/video/out/opengl/video.h @@ -110,6 +110,7 @@ struct gl_video_opts { int target_brightness; int hdr_tone_mapping; float tone_mapping_param; + float tone_mapping_desat; int linear_scaling; int correct_downscaling; int sigmoid_upscaling; diff --git a/video/out/opengl/video_shaders.c b/video/out/opengl/video_shaders.c index cbd566ff0c..995fbd2a1a 100644 --- a/video/out/opengl/video_shaders.c +++ b/video/out/opengl/video_shaders.c @@ -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] 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"); @@ -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_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) { case TONE_MAPPING_CLIP: 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, struct mp_colorspace src, struct mp_colorspace dst, enum tone_mapping algo, float tone_mapping_param, - bool is_linear) + float tone_mapping_desat, bool is_linear) { 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 // encodable range - if (src.sig_peak > dst_range) - pass_tone_map(sc, src.sig_peak / dst_range, algo, tone_mapping_param); + if (src.sig_peak > dst_range) { + pass_tone_map(sc, src.sig_peak / dst_range, algo, tone_mapping_param, + tone_mapping_desat); + } // Adapt to the right colorspace if necessary if (src.primaries != dst.primaries) { diff --git a/video/out/opengl/video_shaders.h b/video/out/opengl/video_shaders.h index 6498033ad1..b0b8b4214e 100644 --- a/video/out/opengl/video_shaders.h +++ b/video/out/opengl/video_shaders.h @@ -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, struct mp_colorspace src, struct mp_colorspace dst, 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, AVLFG *lfg); -- cgit v1.2.3