[FFmpeg-devel,PR,release/5.1] avfilter/vf_convolution: don't assume frame is multiple of 16 pixels wide (PR #24788)

Message ID 20260929192854.A0B9521F9D@ffbox0-bg.ffmpeg.org
State New
Headers
Series [FFmpeg-devel,PR,release/5.1] avfilter/vf_convolution: don't assume frame is multiple of 16 pixels wide (PR #24788) |

Commit Message

Niklas Haas Sept. 29, 2026, 7:28 p.m. UTC
PR #24788 opened by ffmpeg-devel
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24788
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24788.patch

**Backport:** https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24698

Use the actual size in the final column.
No other filter_column function uses the size parameter, so changing its
value is safe.

Fixes: #YWH-PGM40646-36


>From afc316b8781584ed4d088d6bbe9b95eaa06f59d0 Mon Sep 17 00:00:00 2001
From: Timo Rothenpieler <timo@rothenpieler.org>
Date: Fri, 25 Sep 2026 22:55:01 +0200
Subject: [PATCH] avfilter/vf_convolution: don't assume frame is multiple of 16
 pixels wide

Limit the 8-bit column filter to the pixels remaining in the current slice. Pass slice_end - y at all three call sites so both the 8-bit and high-bit-depth column filters receive the correct remaining width. This handles partial 16-pixel blocks at frame and thread-slice boundaries. The non-column callbacks do not use this argument.

Fixes: #YWH-PGM40646-36
(cherry picked from commit 8b9e02cc17126bf42416624e0fea329aa42126b0)
---
 libavfilter/vf_convolution.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)
  

Patch

diff --git a/libavfilter/vf_convolution.c b/libavfilter/vf_convolution.c
index 8d646c5427..9af4f4328a 100644
--- a/libavfilter/vf_convolution.c
+++ b/libavfilter/vf_convolution.c
@@ -533,16 +533,17 @@  static void filter_column(uint8_t *dst, int height,
                           int dstride, int stride, int size)
 {
     DECLARE_ALIGNED(64, unsigned, sum)[16];
+    const int width = FFMIN(16, size);
 
     for (int y = 0; y < height; y++) {
         memset(sum, 0, sizeof(sum));
 
         for (int i = 0; i < 2 * radius + 1; i++) {
-            for (int off16 = 0; off16 < 16; off16++)
+            for (int off16 = 0; off16 < width; off16++)
                 sum[off16] += (unsigned)c[i][0 + y * stride + off16] * matrix[i];
         }
 
-        for (int off16 = 0; off16 < 16; off16++) {
+        for (int off16 = 0; off16 < width; off16++) {
             dst[off16] = av_clip_uint8((int)sum[off16] * rdiv + bias + 0.5f);
         }
         dst += dstride;
@@ -667,12 +668,12 @@  static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
                 s->setup[plane](radius, c, src, stride, x, width, y, height, bpc);
                 s->filter[plane](dst + yoff + xoff, 1, rdiv,
                                  bias, matrix, c, s->max, radius,
-                                 dstride, stride, slice_end - step);
+                                 dstride, stride, slice_end - y);
             }
             s->setup[plane](radius, c, src, stride, left, width, y, height, bpc);
             s->filter[plane](dst + yoff + xoff, right - left,
                              rdiv, bias, matrix, c, s->max, radius,
-                             dstride, stride, slice_end - step);
+                             dstride, stride, slice_end - y);
             for (x = right; x < sizew; x++) {
                 const int xoff = mode == MATRIX_COLUMN ? (y - slice_start) * bpc : x * bpc;
                 const int yoff = mode == MATRIX_COLUMN ? x * dstride : 0;
@@ -680,7 +681,7 @@  static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
                 s->setup[plane](radius, c, src, stride, x, width, y, height, bpc);
                 s->filter[plane](dst + yoff + xoff, 1, rdiv,
                                  bias, matrix, c, s->max, radius,
-                                 dstride, stride, slice_end - step);
+                                 dstride, stride, slice_end - y);
             }
             if (mode != MATRIX_COLUMN)
                 dst += dstride;