On Sun, 21 May 2023 14:24:35 +0200 Niklas Haas <ffm...@haasn.xyz> wrote: > From: Niklas Haas <g...@haasn.dev> > > Upstream deprecated the old ad-hoc, enum/intent-based gamut mapping API > and added a new API based on colorimetrically accurate gamut mapping > functions. > > The relevant change for us is the addition of several new modes, as well > as deprecation of the old options. Update the documentation accordingly. > --- > doc/filters.texi | 47 ++++++++++---------- > libavfilter/vf_libplacebo.c | 86 +++++++++++++++++++++++++++++-------- > 2 files changed, 92 insertions(+), 41 deletions(-) > > diff --git a/doc/filters.texi b/doc/filters.texi > index ddc8529bbe9..97023d5f2e8 100644 > --- a/doc/filters.texi > +++ b/doc/filters.texi > @@ -16353,37 +16353,36 @@ gamut-mapping when dealing with mismatches between > wide-gamut or HDR content. > In general, libplacebo relies on accurate source tagging and mastering > display > gamut information to produce the best results. > @table @option > -@item intent > -Rendering intent to use when adapting between different primary color gamuts > -(after tone-mapping). > -@table @samp > -@item perceptual > -Perceptual gamut mapping. Currently equivalent to relative colorimetric. > -@item relative > -Relative colorimetric. This is the default. > -@item absolute > -Absolute colorimetric. > -@item saturation > -Saturation mapping. Forcibly stretches the source gamut to the target gamut. > -@end table > - > @item gamut_mode > How to handle out-of-gamut colors that can occur as a result of colorimetric > gamut mapping. > @table @samp > @item clip > -Do nothing, simply clip out-of-range colors to the RGB volume. This is the > -default. > -@item warn > -Highlight out-of-gamut pixels (by coloring them pink). > -@item darken > -Linearly reduces content brightness to preserves saturated details, followed > by > -clipping the remaining out-of-gamut colors. As the name implies, this makes > -everything darker, but provides a good balance between preserving details and > -colors. > +Do nothing, simply clip out-of-range colors to the RGB volume. Low quality > but > +extremely fast. > +@item perceptual > +Perceptually soft-clip colors to the gamut volume. This is the default. > +@item relative > +Relative colorimetric hard-clip. Similar to @code{perceptual} but without > +the soft knee. > +@item saturation > +Saturation mapping, maps primaries directly to primaries in RGB space. > +Not recommended except for artificial computer graphics for which a bright, > +saturated display is desired. > +@item absolute > +Absolute colorimetric hard-clip. Performs no adjustment of the white point. > @item desaturate > Hard-desaturates out-of-gamut colors towards white, while preserving the > -luminance. Has a tendency to shift colors. > +luminance. Has a tendency to distort the visual appearance of bright objects. > +@item darken > +Linearly reduces content brightness to preserves saturated details, followed > by > +clipping the remaining out-of-gamut colors. > +@item warn > +Highlight out-of-gamut pixels (by inverting/marking them). > +@item linear > +Linearly reduces chromaticity of the entire image to make it fit within the > +target color volume. Be careful when using this on BT.2020 sources without > +proper mastering metadata, as doing so will lead to excessive desaturation. > @end table > > @item tonemapping > diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c > index f26d0126beb..09bb3dfac86 100644 > --- a/libavfilter/vf_libplacebo.c > +++ b/libavfilter/vf_libplacebo.c > @@ -56,6 +56,19 @@ enum { > TONE_MAP_COUNT, > }; > > +enum { > + GAMUT_MAP_CLIP, > + GAMUT_MAP_PERCEPTUAL, > + GAMUT_MAP_RELATIVE, > + GAMUT_MAP_SATURATION, > + GAMUT_MAP_ABSOLUTE, > + GAMUT_MAP_DESATURATE, > + GAMUT_MAP_DARKEN, > + GAMUT_MAP_HIGHLIGHT, > + GAMUT_MAP_LINEAR, > + GAMUT_MAP_COUNT, > +}; > + > static const char *const var_names[] = { > "in_w", "iw", ///< width of the input video frame > "in_h", "ih", ///< height of the input video frame > @@ -186,7 +199,6 @@ typedef struct LibplaceboContext { > > /* pl_color_map_params */ > struct pl_color_map_params color_map_params; > - int intent; > int gamut_mode; > int tonemapping; > float tonemapping_param; > @@ -202,6 +214,7 @@ typedef struct LibplaceboContext { > int gamut_warning; > int gamut_clipping; > int force_icc_lut; > + int intent; > #endif > > /* pl_dither_params */ > @@ -272,6 +285,34 @@ static const struct pl_tone_map_function > *pl_get_tonemapping_func(int tm) { > } > } > > +static void set_gamut_mode(struct pl_color_map_params *p, int gamut_mode) > +{ > + switch (gamut_mode) { > +#if PL_API_VER >= 269 > + case GAMUT_MAP_CLIP: p->gamut_mapping = &pl_gamut_map_clip; return; > + case GAMUT_MAP_PERCEPTUAL: p->gamut_mapping = &pl_gamut_map_perceptual; > return; > + case GAMUT_MAP_RELATIVE: p->gamut_mapping = &pl_gamut_map_relative; > return; > + case GAMUT_MAP_SATURATION: p->gamut_mapping = &pl_gamut_map_saturation; > return; > + case GAMUT_MAP_ABSOLUTE: p->gamut_mapping = &pl_gamut_map_absolute; > return; > + case GAMUT_MAP_DESATURATE: p->gamut_mapping = &pl_gamut_map_desaturate; > return; > + case GAMUT_MAP_DARKEN: p->gamut_mapping = &pl_gamut_map_darken; > return; > + case GAMUT_MAP_HIGHLIGHT: p->gamut_mapping = &pl_gamut_map_highlight; > return; > + case GAMUT_MAP_LINEAR: p->gamut_mapping = &pl_gamut_map_linear; > return; > +#else > + case GAMUT_MAP_RELATIVE: p->intent = PL_INTENT_RELATIVE_COLORIMETRIC; > return; > + case GAMUT_MAP_SATURATION: p->intent = PL_INTENT_SATURATION; return; > + case GAMUT_MAP_ABSOLUTE: p->intent = PL_INTENT_ABSOLUTE_COLORIMETRIC; > return; > + case GAMUT_MAP_DESATURATE: p->gamut_mode = PL_GAMUT_DESATURATE; return; > + case GAMUT_MAP_DARKEN: p->gamut_mode = PL_GAMUT_DARKEN; return; > + case GAMUT_MAP_HIGHLIGHT: p->gamut_mode = PL_GAMUT_WARN; return; > + /* Use defaults for all other cases */ > + default: return; > +#endif > + } > + > + av_assert0(0); > +}; > + > static int parse_shader(AVFilterContext *avctx, const void *shader, size_t > len) > { > LibplaceboContext *s = avctx->priv; > @@ -317,7 +358,7 @@ static int update_settings(AVFilterContext *ctx) > int err = 0; > LibplaceboContext *s = ctx->priv; > enum pl_tone_map_mode tonemapping_mode = s->tonemapping_mode; > - enum pl_gamut_mode gamut_mode = s->gamut_mode; > + int gamut_mode = s->gamut_mode; > uint8_t color_rgba[4]; > > RET(av_parse_color(color_rgba, s->fillcolor, -1, s)); > @@ -336,10 +377,16 @@ static int update_settings(AVFilterContext *ctx) > } > } > > + switch (s->intent) { > + case PL_INTENT_SATURATION: gamut_mode = GAMUT_MAP_SATURATION; > break; > + case PL_INTENT_RELATIVE_COLORIMETRIC: gamut_mode = GAMUT_MAP_RELATIVE; > break; > + case PL_INTENT_ABSOLUTE_COLORIMETRIC: gamut_mode = GAMUT_MAP_ABSOLUTE; > break; > + } > + > if (s->gamut_warning) > - gamut_mode = PL_GAMUT_WARN; > + gamut_mode = GAMUT_MAP_HIGHLIGHT; > if (s->gamut_clipping) > - gamut_mode = PL_GAMUT_DESATURATE; > + gamut_mode = GAMUT_MAP_DESATURATE; > #endif > > s->deband_params = *pl_deband_params( > @@ -366,8 +413,6 @@ static int update_settings(AVFilterContext *ctx) > ); > > s->color_map_params = *pl_color_map_params( > - .intent = s->intent, > - .gamut_mode = gamut_mode, > .tone_mapping_function = pl_get_tonemapping_func(s->tonemapping), > .tone_mapping_param = s->tonemapping_param, > .tone_mapping_mode = tonemapping_mode, > @@ -376,6 +421,8 @@ static int update_settings(AVFilterContext *ctx) > .lut_size = s->tonemapping_lut_size, > ); > > + set_gamut_mode(&s->color_map_params, gamut_mode); > + > s->dither_params = *pl_dither_params( > .method = s->dithering, > .lut_size = s->dither_lut_size, > @@ -1143,16 +1190,16 @@ static const AVOption libplacebo_options[] = { > { "scene_threshold_high", "Scene change high threshold", > OFFSET(scene_high), AV_OPT_TYPE_FLOAT, {.dbl = 10.0}, -1.0, 100.0, DYNAMIC }, > { "overshoot", "Tone-mapping overshoot margin", OFFSET(overshoot), > AV_OPT_TYPE_FLOAT, {.dbl = 0.05}, 0.0, 1.0, DYNAMIC }, > > - { "intent", "Rendering intent", OFFSET(intent), AV_OPT_TYPE_INT, {.i64 = > PL_INTENT_RELATIVE_COLORIMETRIC}, 0, 3, DYNAMIC, "intent" }, > - { "perceptual", "Perceptual", 0, AV_OPT_TYPE_CONST, {.i64 = > PL_INTENT_PERCEPTUAL}, 0, 0, STATIC, "intent" }, > - { "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" }, > - { "gamut_mode", "Gamut-mapping mode", OFFSET(gamut_mode), > AV_OPT_TYPE_INT, {.i64 = PL_GAMUT_CLIP}, 0, PL_GAMUT_MODE_COUNT - 1, DYNAMIC, > "gamut_mode" }, > - { "clip", "Hard-clip gamut boundary", 0, AV_OPT_TYPE_CONST, {.i64 = > PL_GAMUT_CLIP}, 0, 0, STATIC, "gamut_mode" }, > - { "warn", "Highlight out-of-gamut colors", 0, AV_OPT_TYPE_CONST, > {.i64 = PL_GAMUT_WARN}, 0, 0, STATIC, "gamut_mode" }, > - { "darken", "Darken image to fit gamut", 0, AV_OPT_TYPE_CONST, {.i64 > = PL_GAMUT_DARKEN}, 0, 0, STATIC, "gamut_mode" }, > - { "desaturate", "Colorimetrically desaturate colors", 0, > AV_OPT_TYPE_CONST, {.i64 = PL_GAMUT_DESATURATE}, 0, 0, STATIC, "gamut_mode" }, > + { "gamut_mode", "Gamut-mapping mode", OFFSET(gamut_mode), > AV_OPT_TYPE_INT, {.i64 = GAMUT_MAP_PERCEPTUAL}, 0, GAMUT_MAP_COUNT - 1, > DYNAMIC, "gamut_mode" }, > + { "clip", "Hard-clip (RGB per-channel)", 0, AV_OPT_TYPE_CONST, {.i64 > = GAMUT_MAP_CLIP}, 0, 0, STATIC, "gamut_mode" }, > + { "perceptual", "Colorimetric soft clipping", 0, AV_OPT_TYPE_CONST, > {.i64 = GAMUT_MAP_PERCEPTUAL}, 0, 0, STATIC, "gamut_mode" }, > + { "relative", "Relative colorimetric clipping", 0, > AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_RELATIVE}, 0, 0, STATIC, "gamut_mode" }, > + { "saturation", "Saturation mapping (RGB -> RGB)", 0, > AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_SATURATION}, 0, 0, STATIC, "gamut_mode" > }, > + { "absolute", "Absolute colorimetric clipping", 0, > AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_ABSOLUTE}, 0, 0, STATIC, "gamut_mode" }, > + { "desaturate", "Colorimetrically desaturate colors towards white", > 0, AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_DESATURATE}, 0, 0, STATIC, > "gamut_mode" }, > + { "darken", "Colorimetric clip with bias towards darkening image to > fit gamut", 0, AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_DARKEN}, 0, 0, STATIC, > "gamut_mode" }, > + { "warn", "Highlight out-of-gamut colors", 0, AV_OPT_TYPE_CONST, > {.i64 = GAMUT_MAP_HIGHLIGHT}, 0, 0, STATIC, "gamut_mode" }, > + { "linear", "Linearly reduce chromaticity to fit gamut", 0, > AV_OPT_TYPE_CONST, {.i64 = GAMUT_MAP_LINEAR}, 0, 0, STATIC, "gamut_mode" }, > { "tonemapping", "Tone-mapping algorithm", OFFSET(tonemapping), > AV_OPT_TYPE_INT, {.i64 = TONE_MAP_AUTO}, 0, TONE_MAP_COUNT - 1, DYNAMIC, > "tonemap" }, > { "auto", "Automatic selection", 0, AV_OPT_TYPE_CONST, {.i64 = > TONE_MAP_AUTO}, 0, 0, STATIC, "tonemap" }, > { "clip", "No tone mapping (clip", 0, AV_OPT_TYPE_CONST, {.i64 = > TONE_MAP_CLIP}, 0, 0, STATIC, "tonemap" }, > @@ -1184,7 +1231,12 @@ static const AVOption libplacebo_options[] = { > { "desaturation_strength", "Desaturation strength", OFFSET(desat_str), > AV_OPT_TYPE_FLOAT, {.dbl = -1.0}, -1.0, 1.0, DYNAMIC | AV_OPT_FLAG_DEPRECATED > }, > { "desaturation_exponent", "Desaturation exponent", OFFSET(desat_exp), > AV_OPT_TYPE_FLOAT, {.dbl = -1.0}, -1.0, 10.0, DYNAMIC | > AV_OPT_FLAG_DEPRECATED }, > { "gamut_warning", "Highlight out-of-gamut colors", > OFFSET(gamut_warning), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC | > AV_OPT_FLAG_DEPRECATED }, > - { "gamut_clipping", "Enable colorimetric gamut clipping", > OFFSET(gamut_clipping), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC | > AV_OPT_FLAG_DEPRECATED }, > + { "gamut_clipping", "Enable desaturating colorimetric gamut clipping", > OFFSET(gamut_clipping), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DYNAMIC | > AV_OPT_FLAG_DEPRECATED }, > + { "intent", "Rendering intent", OFFSET(intent), AV_OPT_TYPE_INT, {.i64 = > PL_INTENT_PERCEPTUAL}, 0, 3, DYNAMIC | AV_OPT_FLAG_DEPRECATED, "intent" }, > + { "perceptual", "Perceptual", 0, AV_OPT_TYPE_CONST, {.i64 = > PL_INTENT_PERCEPTUAL}, 0, 0, STATIC, "intent" }, > + { "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" }, > #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 >
Merged as d637f20f057586a0a3...877ccaf776c92866e _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".