This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 2be98b13b2d8012898f530dcb30f72f71dcfef72
Author:     Niklas Haas <[email protected]>
AuthorDate: Wed Sep 2 12:59:06 2026 +0200
Commit:     Niklas Haas <[email protected]>
CommitDate: Wed Sep 16 11:17:01 2026 +0000

    avfilter/vf_limiter: allow min/max=auto to infer TV signal range
    
    This is actually the only way currently of setting a different level for
    the Y and UV planes, which matters as this filter may requires a plane copy
    for passthrough planes.
    
    I'm tempted to just make "auto" the default, but it would possibly regress
    existing users, so I decided not to touch it for now.
    
    Only limit to MPEG range is the frame is definitely tagged as TV range,
    since otherwise an unspecified/unknown frame would be silently clipped,
    possibly affecting downstream filters like vf_colordetect.
    
    Sponsored-by: nxtedition AB
    Signed-off-by: Niklas Haas <[email protected]>
---
 doc/filters.texi         |  8 ++++++--
 libavfilter/vf_limiter.c | 27 +++++++++++++++++++++++----
 2 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index b7379d3060..6efaac71f6 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -17844,10 +17844,14 @@ The filter accepts the following options:
 
 @table @option
 @item min
-Lower bound. Defaults to the lowest allowed value for the input.
+Lower bound. Defaults to the lowest representable value for the input.
+Set to @var{auto} to use the minimum signal level for the input colorspace
+(only affects TV-range YUV signals).
 
 @item max
-Upper bound. Defaults to the highest allowed value for the input.
+Upper bound. Defaults to the highest representable value for the input.
+Set to @var{auto} to use the maximum signal level for the input colorspace
+(only affects TV-range YUV signals).
 
 @item planes
 Specify which planes will be processed. Defaults to all available.
diff --git a/libavfilter/vf_limiter.c b/libavfilter/vf_limiter.c
index 3730527bad..c5d671efa7 100644
--- a/libavfilter/vf_limiter.c
+++ b/libavfilter/vf_limiter.c
@@ -51,8 +51,9 @@ typedef struct LimiterContext {
 #define FLAGS 
AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
 
 static const AVOption limiter_options[] = {
-    { "min",    "set min value", OFFSET(min),    AV_OPT_TYPE_INT, {.i64=0},    
 0, 65535, .flags = FLAGS },
-    { "max",    "set max value", OFFSET(max),    AV_OPT_TYPE_INT, 
{.i64=65535}, 0, 65535, .flags = FLAGS },
+    { "min",    "set min value", OFFSET(min),    AV_OPT_TYPE_INT, {.i64=0},    
 -1, 65535, .flags = FLAGS, .unit = "value" },
+    { "max",    "set max value", OFFSET(max),    AV_OPT_TYPE_INT, 
{.i64=65535}, -1, 65535, .flags = FLAGS, .unit = "value" },
+        { "auto", "automatically use tagged signal range", 0, 
AV_OPT_TYPE_CONST, {.i64=-1}, .flags = FLAGS, .unit = "value" },
     { "planes", "set planes",    OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15},   
 0,    15, .flags = FLAGS },
     { NULL }
 };
@@ -63,7 +64,7 @@ static av_cold int init(AVFilterContext *ctx)
 {
     LimiterContext *s = ctx->priv;
 
-    if (s->min > s->max)
+    if (s->min >= 0 && s->max >= 0 && s->min > s->max)
         return AVERROR(EINVAL);
     return 0;
 }
@@ -158,10 +159,24 @@ static int filter_slice(AVFilterContext *ctx, void *arg, 
int jobnr, int nb_jobs)
     AVFrame *out = td->out;
     int p;
 
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(in->format);
+    const int depth = desc->comp[0].depth;
+    const int full_range = (1 << depth) - 1;
+    const int is_mpeg = in->color_range == AVCOL_RANGE_MPEG &&
+                        !(desc->flags & AV_PIX_FMT_FLAG_RGB);
+
     for (p = 0; p < s->nb_planes; p++) {
         const int h = s->height[p];
         const int slice_start = ff_slice_pos(h, jobnr, nb_jobs);
         const int slice_end = ff_slice_pos(h, jobnr + 1, nb_jobs);
+        const int mpeg_min = 16 << (depth - 8);
+        const int mpeg_max = (p ? 240 : 235) << (depth - 8);
+
+        int min = s->min, max = s->max;
+        if (min < 0)
+            min = (is_mpeg && p != 3) ? mpeg_min : 0;
+        if (max < 0)
+            max = (is_mpeg && p != 3) ? mpeg_max : full_range;
 
         if (!((1 << p) & s->planes)) {
             if (out != in)
@@ -173,11 +188,15 @@ static int filter_slice(AVFilterContext *ctx, void *arg, 
int jobnr, int nb_jobs)
             continue;
         }
 
+        /* check only after resolving no-op planes */
+        if (min > max)
+            return AVERROR(EINVAL);
+
         s->dsp.limiter(in->data[p] + slice_start * in->linesize[p],
                        out->data[p] + slice_start * out->linesize[p],
                        in->linesize[p], out->linesize[p],
                        s->width[p], slice_end - slice_start,
-                       s->min, s->max);
+                       min, max);
     }
 
     return 0;

-- 
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]

Reply via email to