diff options
-rw-r--r-- | DOCS/interface-changes.rst | 1 | ||||
-rw-r--r-- | DOCS/man/options.rst | 16 | ||||
-rw-r--r-- | video/out/opengl/video.c | 9 | ||||
-rw-r--r-- | video/out/opengl/video.h | 2 | ||||
-rw-r--r-- | video/out/opengl/video_shaders.c | 29 |
5 files changed, 33 insertions, 24 deletions
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index a9a6664461..ea4545bdc3 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -26,6 +26,7 @@ Interface changes "audio-file", "external-file" (these cases used to log a deprecation warning) - drop deprecated --video-aspect-method=hybrid option choice + - rename --hdr-tone-mapping to --tone-mapping (and generalize it) --- mpv 0.26.0 --- - remove remaining deprecated audio device options, like --alsa-device Some of them were removed in earlier releases. diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index e824e04e0f..814f6fe2d9 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -4765,9 +4765,11 @@ The following video options are currently all specific to ``--vo=opengl`` and The user should independently guarantee this before using these signal formats for display. -``--hdr-tone-mapping=<value>`` - Specifies the algorithm used for tone-mapping HDR images onto the target - display. Valid values are: +``--tone-mapping=<value>`` + Specifies the algorithm used for tone-mapping images onto the target + display. This is relevant for both HDR->SDR conversion as well as gamut + reduction (e.g. playing back BT.2020 content on a standard gamut display). + Valid values are: clip Hard-clip any out-of-range values. Use this when you care about @@ -4786,10 +4788,10 @@ The following video options are currently all specific to ``--vo=opengl`` and results in flattening of details and degradation in color accuracy. hable Similar to ``reinhard`` but preserves both dark and bright details - better (slightly sigmoidal), at the cost of slightly darkening - everything. Developed by John Hable for use in video games. Use this - when you care about detail preservation more than color/brightness - accuracy. This is roughly equivalent to + better (slightly sigmoidal), at the cost of slightly darkening / + desaturating everything. Developed by John Hable for use in video + games. Use this when you care about detail preservation more than + color/brightness accuracy. This is roughly equivalent to ``--hdr-tone-mapping=reinhard --tone-mapping-param=0.24``. gamma Fits a logarithmic transfer between the tone curves. diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index 5ecf80b450..0cd7ef3688 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -326,7 +326,7 @@ static const struct gl_video_opts gl_video_opts_def = { .alpha_mode = ALPHA_BLEND_TILES, .background = {0, 0, 0, 255}, .gamma = 1.0f, - .hdr_tone_mapping = TONE_MAPPING_MOBIUS, + .tone_mapping = TONE_MAPPING_MOBIUS, .tone_mapping_param = NAN, .tone_mapping_desat = 2.0, .early_flush = -1, @@ -363,7 +363,7 @@ const struct m_sub_options gl_video_conf = { OPT_FLAG("gamma-auto", gamma_auto, 0), OPT_CHOICE_C("target-prim", target_prim, 0, mp_csp_prim_names), OPT_CHOICE_C("target-trc", target_trc, 0, mp_csp_trc_names), - OPT_CHOICE("hdr-tone-mapping", hdr_tone_mapping, 0, + OPT_CHOICE("tone-mapping", tone_mapping, 0, ({"clip", TONE_MAPPING_CLIP}, {"mobius", TONE_MAPPING_MOBIUS}, {"reinhard", TONE_MAPPING_REINHARD}, @@ -431,6 +431,7 @@ const struct m_sub_options gl_video_conf = { OPT_CHOICE("opengl-early-flush", early_flush, 0, ({"no", 0}, {"yes", 1}, {"auto", -1})), OPT_STRING("opengl-shader-cache-dir", shader_cache_dir, 0), + OPT_REPLACED("hdr-tone-mapping", "tone-mapping"), {0} }, .size = sizeof(struct gl_video_opts), @@ -2537,7 +2538,7 @@ 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, + pass_color_map(p->sc, src, dst, p->opts.tone_mapping, p->opts.tone_mapping_param, p->opts.tone_mapping_desat, detect_peak, p->use_linear && !osd); @@ -3499,7 +3500,7 @@ static void check_gl_features(struct gl_video *p) .temporal_dither_period = p->opts.temporal_dither_period, .tex_pad_x = p->opts.tex_pad_x, .tex_pad_y = p->opts.tex_pad_y, - .hdr_tone_mapping = p->opts.hdr_tone_mapping, + .tone_mapping = p->opts.tone_mapping, .tone_mapping_param = p->opts.tone_mapping_param, .tone_mapping_desat = p->opts.tone_mapping_desat, .early_flush = p->opts.early_flush, diff --git a/video/out/opengl/video.h b/video/out/opengl/video.h index 5b50cdd3f2..d74f3cf576 100644 --- a/video/out/opengl/video.h +++ b/video/out/opengl/video.h @@ -110,7 +110,7 @@ struct gl_video_opts { int target_prim; int target_trc; int target_brightness; - int hdr_tone_mapping; + int tone_mapping; int compute_hdr_peak; float tone_mapping_param; float tone_mapping_desat; diff --git a/video/out/opengl/video_shaders.c b/video/out/opengl/video_shaders.c index 4708187580..a8170c10d1 100644 --- a/video/out/opengl/video_shaders.c +++ b/video/out/opengl/video_shaders.c @@ -577,7 +577,7 @@ static void pass_tone_map(struct gl_shader_cache *sc, float ref_peak, GLSLF("// HDR tone mapping\n"); // Desaturate the color using a coefficient dependent on the luminance - GLSL(float luma = dot(src_luma, color.rgb);) + GLSL(float luma = dot(dst_luma, color.rgb);) if (desat > 0) { GLSLF("float overbright = max(luma - %f, 1e-6) / max(luma, 1e-6);\n", desat); GLSL(color.rgb = mix(color.rgb, vec3(luma), overbright);) @@ -699,13 +699,15 @@ void pass_color_map(struct gl_shader_cache *sc, // Compute the highest encodable level float src_range = mp_trc_nom_peak(src.gamma), dst_range = mp_trc_nom_peak(dst.gamma); + float ref_peak = src.sig_peak / dst_range; - // Some operations need access to the video's luma coefficients (src - // colorspace), so make it available - struct mp_csp_primaries prim = mp_get_csp_primaries(src.primaries); + // Some operations need access to the video's luma coefficients, so make + // them available float rgb2xyz[3][3]; - mp_get_rgb2xyz_matrix(prim, rgb2xyz); + mp_get_rgb2xyz_matrix(mp_get_csp_primaries(src.primaries), rgb2xyz); gl_sc_uniform_vec3(sc, "src_luma", rgb2xyz[1]); + mp_get_rgb2xyz_matrix(mp_get_csp_primaries(dst.primaries), rgb2xyz); + gl_sc_uniform_vec3(sc, "dst_luma", rgb2xyz[1]); // All operations from here on require linear light as a starting point, // so we linearize even if src.gamma == dst.gamma when one of the other @@ -732,13 +734,6 @@ void pass_color_map(struct gl_shader_cache *sc, GLSLF("color.rgb *= vec3(%f);\n", src_range / dst_range); } - // Tone map to prevent clipping when the source signal peak exceeds the - // encodable range - if (src.sig_peak > dst_range) { - float ref_peak = detect_peak ? 0 : src.sig_peak / dst_range; - pass_tone_map(sc, ref_peak, algo, tone_mapping_param, tone_mapping_desat); - } - // Adapt to the right colorspace if necessary if (src.primaries != dst.primaries) { struct mp_csp_primaries csp_src = mp_get_csp_primaries(src.primaries), @@ -747,6 +742,16 @@ void pass_color_map(struct gl_shader_cache *sc, mp_get_cms_matrix(csp_src, csp_dst, MP_INTENT_RELATIVE_COLORIMETRIC, m); gl_sc_uniform_mat3(sc, "cms_matrix", true, &m[0][0]); GLSL(color.rgb = cms_matrix * color.rgb;) + // Since this can reduce the gamut, figure out by how much + for (int c = 0; c < 3; c++) + ref_peak = MPMAX(ref_peak, m[c][c]); + } + + // Tone map to prevent clipping when the source signal peak exceeds the + // encodable range or we've reduced the gamut + if (ref_peak > 1) { + pass_tone_map(sc, detect_peak ? 0 : ref_peak, algo, + tone_mapping_param, tone_mapping_desat); } if (src.light != dst.light) |