Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Niklas Haas <ffmpeg@haasn.xyz>
To: ffmpeg-devel@ffmpeg.org
Cc: Niklas Haas <git@haasn.dev>
Subject: [FFmpeg-devel] [PATCH 2/4] lavfi/vf_libplacebo: update for new tone mapping API
Date: Sun, 21 May 2023 14:24:36 +0200
Message-ID: <20230521122438.78375-2-ffmpeg@haasn.xyz> (raw)
In-Reply-To: <20230521122438.78375-1-ffmpeg@haasn.xyz>

From: Niklas Haas <git@haasn.dev>

This algorithm has once again been refactored, this time leading to a
dropping of the old `tone_mapping_mode` field, to be replaced by a
single tunable hybrid mode with configurable strength.

We can approximately map the old modes onto the new API for backwards
compatibility. Replace deprecated enums by their integer equivalents to
safely preserve this API until the next bump.
---
 doc/filters.texi            | 34 +++++--------------------
 libavfilter/vf_libplacebo.c | 49 ++++++++++++++++++++-----------------
 2 files changed, 33 insertions(+), 50 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index 97023d5f2e8..eaa1a282209 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -16461,42 +16461,20 @@ For tunable tone mapping functions, this parameter can be used to fine-tune the
 curve behavior. Refer to the documentation of @code{tonemapping}. The default
 value of @code{0.0} is replaced by the curve's preferred default setting.
 
-@item tonemapping_mode
-This option determines how the tone mapping function specified by
-@code{tonemapping} is applied to the colors in a scene. Possible values are:
-@table @samp
-@item auto
-Automatic selection based on internal heuristics. This is the default.
-@item rgb
-Apply the function per-channel in the RGB colorspace.
-Per-channel tone-mapping in RGB. Guarantees no clipping and heavily desaturates
-the output, but distorts the colors quite significantly. Very similar to the
-"Hollywood" look and feel.
-@item max
-Tone-mapping is performed on the brightest component found in the signal. Good
-at preserving details in highlights, but has a tendency to crush blacks.
-@item hybrid
-Tone-map per-channel for highlights and linearly (luma-based) for
-midtones/shadows, based on a fixed gamma @code{2.4} coefficient curve.
-@item luma
-Tone-map linearly on the luma component (CIE Y), and adjust (desaturate) the
-chromaticities to compensate using a simple constant factor. This is
-essentially the mode used in ITU-R BT.2446 method A.
-@end table
-
 @item inverse_tonemapping
 If enabled, this filter will also attempt stretching SDR signals to fill HDR
 output color volumes. Disabled by default.
 
-@item tonemapping_crosstalk
-Extra tone-mapping crosstalk factor, between @code{0.0} and @code{0.3}. This
-can help reduce issues tone-mapping certain bright spectral colors. Defaults to
-@code{0.04}.
-
 @item tonemapping_lut_size
 Size of the tone-mapping LUT, between @code{2} and @code{1024}. Defaults to
 @code{256}. Note that this figure is squared when combined with
 @code{peak_detect}.
+
+@item hybrid_mix
+If nonzero, this much of the upper range of the tone-mapped result is smoothly
+mixed with a per-channel (LMS) tone-mapped version. Helps avoid unnatural
+blown-out highlights when tone-mapping very bright, strongly saturated colors.
+Defaults to @code{0.2}.
 @end table
 
 @subsubsection Dithering
diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
index 09bb3dfac86..b8b12f9c92d 100644
--- a/libavfilter/vf_libplacebo.c
+++ b/libavfilter/vf_libplacebo.c
@@ -202,10 +202,9 @@ typedef struct LibplaceboContext {
     int gamut_mode;
     int tonemapping;
     float tonemapping_param;
-    int tonemapping_mode;
     int inverse_tonemapping;
-    float crosstalk;
     int tonemapping_lut_size;
+    float hybrid_mix;
 
 #if FF_API_LIBPLACEBO_OPTS
     /* for backwards compatibility */
@@ -215,6 +214,8 @@ typedef struct LibplaceboContext {
     int gamut_clipping;
     int force_icc_lut;
     int intent;
+    int tonemapping_mode;
+    float crosstalk;
 #endif
 
     /* pl_dither_params */
@@ -357,24 +358,23 @@ static int update_settings(AVFilterContext *ctx)
 {
     int err = 0;
     LibplaceboContext *s = ctx->priv;
-    enum pl_tone_map_mode tonemapping_mode = s->tonemapping_mode;
     int gamut_mode = s->gamut_mode;
+    float hybrid_mix = s->hybrid_mix;
     uint8_t color_rgba[4];
 
     RET(av_parse_color(color_rgba, s->fillcolor, -1, s));
 
 #if FF_API_LIBPLACEBO_OPTS
     /* backwards compatibility with older API */
-    if (!tonemapping_mode && (s->desat_str >= 0.0f || s->desat_exp >= 0.0f)) {
-        float str = s->desat_str < 0.0f ? 0.9f : s->desat_str;
-        float exp = s->desat_exp < 0.0f ? 0.2f : s->desat_exp;
-        if (str >= 0.9f && exp <= 0.1f) {
-            tonemapping_mode = PL_TONE_MAP_RGB;
-        } else if (str > 0.1f) {
-            tonemapping_mode = PL_TONE_MAP_HYBRID;
-        } else {
-            tonemapping_mode = PL_TONE_MAP_LUMA;
-        }
+    switch (s->tonemapping_mode) {
+    case 0: /*PL_TONE_MAP_AUTO*/
+        if (s->desat_str >= 0.0f)
+            hybrid_mix = s->desat_str;
+        break;
+    case 1: /*PL_TONE_MAP_RGB*/     hybrid_mix = 1.0f; break;
+    case 2: /*PL_TONE_MAP_HYBRID*/  hybrid_mix = 0.2f; break;
+    case 3: /*PL_TONE_MAP_LUMA*/    hybrid_mix = 0.0f; break;
+    case 4: /*PL_TONE_MAP_MAX*/     hybrid_mix = 0.0f; break;
     }
 
     switch (s->intent) {
@@ -413,11 +413,15 @@ static int update_settings(AVFilterContext *ctx)
     );
 
     s->color_map_params = *pl_color_map_params(
+#if PL_API_VER >= 269
+        .hybrid_mix = hybrid_mix,
+#elif FF_API_LIBPLACEBO_OPTS
+        .tone_mapping_mode = s->tonemapping_mode,
+        .tone_mapping_crosstalk = s->crosstalk,
+#endif
         .tone_mapping_function = pl_get_tonemapping_func(s->tonemapping),
         .tone_mapping_param = s->tonemapping_param,
-        .tone_mapping_mode = tonemapping_mode,
         .inverse_tone_mapping = s->inverse_tonemapping,
-        .tone_mapping_crosstalk = s->crosstalk,
         .lut_size = s->tonemapping_lut_size,
     );
 
@@ -1216,15 +1220,9 @@ static const AVOption libplacebo_options[] = {
         { "gamma", "Gamma function with knee", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_GAMMA}, 0, 0, STATIC, "tonemap" },
         { "linear", "Perceptually linear stretch", 0, AV_OPT_TYPE_CONST, {.i64 = TONE_MAP_LINEAR}, 0, 0, STATIC, "tonemap" },
     { "tonemapping_param", "Tunable parameter for some tone-mapping functions", OFFSET(tonemapping_param), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 100.0, .flags = DYNAMIC },
-    { "tonemapping_mode", "Tone-mapping mode", OFFSET(tonemapping_mode), AV_OPT_TYPE_INT, {.i64 = PL_TONE_MAP_AUTO}, 0, PL_TONE_MAP_MODE_COUNT - 1, DYNAMIC, "tonemap_mode" },
-        { "auto", "Automatic selection", 0, AV_OPT_TYPE_CONST, {.i64 = PL_TONE_MAP_AUTO}, 0, 0, STATIC, "tonemap_mode" },
-        { "rgb", "Per-channel (RGB)", 0, AV_OPT_TYPE_CONST, {.i64 = PL_TONE_MAP_RGB}, 0, 0, STATIC, "tonemap_mode" },
-        { "max", "Maximum component", 0, AV_OPT_TYPE_CONST, {.i64 = PL_TONE_MAP_MAX}, 0, 0, STATIC, "tonemap_mode" },
-        { "hybrid", "Hybrid of Luma/RGB", 0, AV_OPT_TYPE_CONST, {.i64 = PL_TONE_MAP_HYBRID}, 0, 0, STATIC, "tonemap_mode" },
-        { "luma", "Luminance", 0, AV_OPT_TYPE_CONST, {.i64 = PL_TONE_MAP_LUMA}, 0, 0, STATIC, "tonemap_mode" },
     { "inverse_tonemapping", "Inverse tone mapping (range expansion)", OFFSET(inverse_tonemapping), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC },
-    { "tonemapping_crosstalk", "Crosstalk factor for tone-mapping", OFFSET(crosstalk), AV_OPT_TYPE_FLOAT, {.dbl = 0.04}, 0.0, 0.30, DYNAMIC },
     { "tonemapping_lut_size", "Tone-mapping LUT size", OFFSET(tonemapping_lut_size), AV_OPT_TYPE_INT, {.i64 = 256}, 2, 1024, DYNAMIC },
+    { "hybrid_mix", "Tone-mapping hybrid LMS mixing coefficient", OFFSET(hybrid_mix), AV_OPT_TYPE_FLOAT, {.dbl = 0.20}, 0.0, 1.00, DYNAMIC },
 
 #if FF_API_LIBPLACEBO_OPTS
     /* deprecated options for backwards compatibility, defaulting to -1 to not override the new defaults */
@@ -1237,6 +1235,13 @@ static const AVOption libplacebo_options[] = {
         { "relative", "Relative colorimetric", 0, AV_OPT_TYPE_CONST, {.i64 = PL_INTENT_RELATIVE_COLORIMETRIC}, 0, 0, STATIC, "intent" },
         { "absolute", "Absolute colorimetric", 0, AV_OPT_TYPE_CONST, {.i64 = PL_INTENT_ABSOLUTE_COLORIMETRIC}, 0, 0, STATIC, "intent" },
         { "saturation", "Saturation mapping", 0, AV_OPT_TYPE_CONST, {.i64 = PL_INTENT_SATURATION}, 0, 0, STATIC, "intent" },
+    { "tonemapping_mode", "Tone-mapping mode", OFFSET(tonemapping_mode), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4, DYNAMIC | AV_OPT_FLAG_DEPRECATED, "tonemap_mode" },
+        { "auto", "Automatic selection", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, STATIC, "tonemap_mode" },
+        { "rgb", "Per-channel (RGB)", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, STATIC, "tonemap_mode" },
+        { "max", "Maximum component", 0, AV_OPT_TYPE_CONST, {.i64 = 2}, 0, 0, STATIC, "tonemap_mode" },
+        { "hybrid", "Hybrid of Luma/RGB", 0, AV_OPT_TYPE_CONST, {.i64 = 3}, 0, 0, STATIC, "tonemap_mode" },
+        { "luma", "Luminance", 0, AV_OPT_TYPE_CONST, {.i64 = 4}, 0, 0, STATIC, "tonemap_mode" },
+    { "tonemapping_crosstalk", "Crosstalk factor for tone-mapping", OFFSET(crosstalk), AV_OPT_TYPE_FLOAT, {.dbl = 0.04}, 0.0, 0.30, DYNAMIC | AV_OPT_FLAG_DEPRECATED },
 #endif
 
     { "dithering", "Dither method to use", OFFSET(dithering), AV_OPT_TYPE_INT, {.i64 = PL_DITHER_BLUE_NOISE}, -1, PL_DITHER_METHOD_COUNT - 1, DYNAMIC, "dither" },
-- 
2.40.1

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

  reply	other threads:[~2023-05-21 12:25 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-21 12:24 [FFmpeg-devel] [PATCH 1/4] lavfi/vf_libplacebo: switch to new gamut " Niklas Haas
2023-05-21 12:24 ` Niklas Haas [this message]
2023-05-21 12:24 ` [FFmpeg-devel] [PATCH 3/4] lavfi/vf_libplacebo: update peak detection options Niklas Haas
2023-05-21 12:24 ` [FFmpeg-devel] [PATCH 4/4] lavfi/vf_libplacebo: don't intrude on pl_ namespace Niklas Haas
2023-05-22  8:35 ` [FFmpeg-devel] [PATCH 1/4] lavfi/vf_libplacebo: switch to new gamut mapping API Niklas Haas

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230521122438.78375-2-ffmpeg@haasn.xyz \
    --to=ffmpeg@haasn.xyz \
    --cc=ffmpeg-devel@ffmpeg.org \
    --cc=git@haasn.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git