This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 0dc120b360b604c3a1505644f0863fb23c35e08c Author: Niklas Haas <[email protected]> AuthorDate: Sat Aug 29 14:54:29 2026 +0200 Commit: Niklas Haas <[email protected]> CommitDate: Tue Sep 1 13:15:06 2026 +0200 avfilter/vf_colordetect: add threshold option This is useful to filter false positives due to encoding noise in lossily compressed sources. The reason this is limited to 0.05 (= 5%) is twofold: 1. Higher values would mostly defeat the purpose of this filter, since a deviation of >5% is enough to fully blur the distinction between JPEG and MPEG range, let alone premultiplied and straight alpha. There's no useful signal to extract with such a high tolerance for noise. 2. Higher values would overflow the `offset` value in the 8-bit SIMD. This could also be solved by clamping, but the first point is the salient one anyways. Sponsored-by: nxtedition AB Signed-off-by: Niklas Haas <[email protected]> --- doc/filters.texi | 4 ++++ libavfilter/vf_colordetect.c | 20 +++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index de1aca5257..4cd673eae0 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -9957,6 +9957,10 @@ premultiplied. Also detects if the alpha plane is fully opaque or not. Enable detection of all of the above properties. This is the default. @end table +@item threshold +Allow pixels to exceed the expected bounds by this fraction of the full scale +value range before treating it as evidence of (respectively) full range or +straight alpha. Value range is from 0 to 0.05. Defaults to 0.0. @end table @section colorize diff --git a/libavfilter/vf_colordetect.c b/libavfilter/vf_colordetect.c index b36ba34079..3750b7d86a 100644 --- a/libavfilter/vf_colordetect.c +++ b/libavfilter/vf_colordetect.c @@ -48,6 +48,7 @@ typedef struct ColorDetectContext { const AVClass *class; FFColorDetectDSPContext dsp; unsigned mode; + float threshold; const AVPixFmtDescriptor *desc; int nb_threads; @@ -75,6 +76,9 @@ static const AVOption colordetect_options[] = { { "color_range", "Detect (YUV) color range", 0, AV_OPT_TYPE_CONST, {.i64 = COLOR_DETECT_COLOR_RANGE}, 0, 0, FLAGS, .unit = "mode" }, { "alpha_mode", "Detect alpha mode", 0, AV_OPT_TYPE_CONST, {.i64 = COLOR_DETECT_ALPHA_MODE }, 0, 0, FLAGS, .unit = "mode" }, { "all", "Detect all supported properties", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, .unit = "mode" }, + + /* Note: threshold should not be increased past ~0.4 as it overflows 8-bit SIMD otherwise */ + { "threshold", "Detection threshold, as a fraction of the full range", OFFSET(threshold), AV_OPT_TYPE_FLOAT, {.dbl = 0.0}, 0.0, 0.05, FLAGS }, { NULL } }; @@ -106,6 +110,7 @@ static int config_input(AVFilterLink *inlink) const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); const int depth = desc->comp[0].depth; const int range = (1 << depth) - 1; + const int threshold = lrintf(s->threshold * range); const int mpeg_min = 16 << (depth - 8); const int mpeg_max = 235 << (depth - 8); if (depth > 16) /* not currently possible; prevent future bugs */ @@ -117,31 +122,32 @@ static int config_input(AVFilterLink *inlink) s->nb_threads = ff_filter_get_nb_threads(ctx); /* Color range detection: */ - s->mpeg_min = mpeg_min; - s->mpeg_max = mpeg_max; + s->mpeg_min = av_clip_uintp2(mpeg_min - threshold, depth); + s->mpeg_max = av_clip_uintp2(mpeg_max + threshold, depth); /** * Alpha mode detection: * * To check if a value is out of range, we need to compare the color value * against the maximum possible color for a given alpha value. - * x > ((mpeg_max - mpeg_min) / pixel_max) * a + mpeg_min + * x > ((mpeg_max - mpeg_min) / pixel_max) * a + mpeg_min + threshold * * This simplifies to: - * (x - mpeg_min) * pixel_max > (mpeg_max - mpeg_min) * a + * (x - mpeg_min - threshold) * pixel_max > (mpeg_max - mpeg_min) * a * = range * x - offset > mpeg_range * a in the below formula. * * We subtract an additional offset of (1 << (depth - 1)) to account for * rounding errors in the value of `x`. * - * For full range input this degenerates to `x > a`, so the offset is 0. + * For full range input this degenerates to `x > a + threshold`, so the + * threshold is passed through directly, without the `range` scaling. */ if (inlink->color_range == AVCOL_RANGE_JPEG) { s->mpeg_range = range; - s->offset = 0; + s->offset = threshold; } else { s->mpeg_range = mpeg_max - mpeg_min; - s->offset = range * mpeg_min + (1 << (s->depth - 1)); + s->offset = range * (mpeg_min + threshold) + (1 << (depth - 1)); } if (desc->flags & AV_PIX_FMT_FLAG_RGB) { -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
