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

Git pushed a commit to branch master
in repository ffmpeg.

commit 338316f0a3c397dcb87cb7e77f74e7cab05648c0
Author:     Andreas Rheinhardt <[email protected]>
AuthorDate: Tue Mar 17 05:33:13 2026 +0100
Commit:     Andreas Rheinhardt <[email protected]>
CommitDate: Thu Mar 19 14:44:30 2026 +0100

    tests/checkasm: Add test for mpeg4videodsp
    
    It already uncovered a bug in the MMX version of gmc.
    
    Reviewed-by: Lynne <[email protected]>
    Signed-off-by: Andreas Rheinhardt <[email protected]>
---
 tests/checkasm/Makefile        |   1 +
 tests/checkasm/checkasm.c      |   3 +
 tests/checkasm/checkasm.h      |   1 +
 tests/checkasm/mpeg4videodsp.c | 156 +++++++++++++++++++++++++++++++++++++++++
 tests/fate/checkasm.mak        |   1 +
 5 files changed, 162 insertions(+)

diff --git a/tests/checkasm/Makefile b/tests/checkasm/Makefile
index 1e23587de9..6c525356aa 100644
--- a/tests/checkasm/Makefile
+++ b/tests/checkasm/Makefile
@@ -41,6 +41,7 @@ AVCODECOBJS-$(CONFIG_DIRAC_DECODER)     += diracdsp.o
 AVCODECOBJS-$(CONFIG_EXR_DECODER)       += exrdsp.o
 AVCODECOBJS-$(CONFIG_FLAC_DECODER)      += flacdsp.o
 AVCODECOBJS-$(CONFIG_JPEG2000_DECODER)  += jpeg2000dsp.o
+AVCODECOBJS-$(CONFIG_MPEG4_DECODER)     += mpeg4videodsp.o
 AVCODECOBJS-$(CONFIG_OPUS_DECODER)      += opusdsp.o
 AVCODECOBJS-$(CONFIG_PIXBLOCKDSP)       += pixblockdsp.o
 AVCODECOBJS-$(CONFIG_HEVC_DECODER)      += hevc_add_res.o hevc_deblock.o 
hevc_dequant.o hevc_idct.o hevc_sao.o hevc_pel.o
diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c
index 8b2f648b3d..b1504b14bb 100644
--- a/tests/checkasm/checkasm.c
+++ b/tests/checkasm/checkasm.c
@@ -222,6 +222,9 @@ static const struct {
     #if CONFIG_ME_CMP
         { "motion", checkasm_check_motion },
     #endif
+    #if CONFIG_MPEG4_DECODER
+        { "mpeg4videodsp", checkasm_check_mpeg4videodsp },
+    #endif
     #if CONFIG_MPEGVIDEO
         { "mpegvideo_unquantize", checkasm_check_mpegvideo_unquantize },
     #endif
diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h
index 25654b20ba..f653207363 100644
--- a/tests/checkasm/checkasm.h
+++ b/tests/checkasm/checkasm.h
@@ -126,6 +126,7 @@ void checkasm_check_llviddsp(void);
 void checkasm_check_llvidencdsp(void);
 void checkasm_check_lpc(void);
 void checkasm_check_motion(void);
+void checkasm_check_mpeg4videodsp(void);
 void checkasm_check_mpegvideo_unquantize(void);
 void checkasm_check_mpegvideoencdsp(void);
 void checkasm_check_nlmeans(void);
diff --git a/tests/checkasm/mpeg4videodsp.c b/tests/checkasm/mpeg4videodsp.c
new file mode 100644
index 0000000000..79a3ac5805
--- /dev/null
+++ b/tests/checkasm/mpeg4videodsp.c
@@ -0,0 +1,156 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <assert.h>
+
+#include "checkasm.h"
+#include "libavcodec/mpeg4videodsp.h"
+#include "libavutil/avassert.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mem_internal.h"
+
+enum {
+    MAX_WIDTH        = 1024,
+    MAX_HEIGHT       = 64,
+    MAX_STRIDE       = MAX_WIDTH,
+    MAX_BLOCK_HEIGHT = 16,
+    W                = 8,
+};
+
+static_assert(MAX_WIDTH <= MAX_STRIDE, "stride needs to be >= width");
+
+#define randomize_buffer(buf)                                      \
+    do {                                                           \
+        static_assert(!(sizeof(buf) % 4), "Tail handling needed"); \
+        for (size_t k = 0; k < sizeof(buf); k += 4) {              \
+            uint32_t r = rnd();                                    \
+            AV_WN32A(buf + k, r);                                  \
+        }                                                          \
+    } while (0)
+
+static int get_signed_rnd(int nb_bits)
+{
+    int32_t r = rnd();
+    return r >> (32 - nb_bits);
+}
+
+static int get_mv_delta(int shift, int is_diag)
+{
+    // The coordinates of the motion vector differences are fixed point numbers
+    // whose fractional part has 16+shift bits. We use 5+shift+4 bit mantissa
+    // for the deviation from the normal, so that the absolute value 
corresponds
+    // to < 2^(-7). For height 16, the maximum absolute deviation is < 1/8.
+    // Additionally, we always use zero for the four least significant bits,
+    // as the x86 implementation always falls back to the C one if it is not 
so.
+    return get_signed_rnd(6 + shift) * 16 + (is_diag ? (1 << (16 + shift)) : 
0);
+}
+
+static int modify_fpel(int coordinate, int size, int block_size, int type)
+{
+    switch (type) {
+    default: av_unreachable("impossible");
+    // fallthrough
+    case 2: return coordinate; // do nothing
+    // modify coordinate so that it requires pixel replication to the left/top
+    case 1: return coordinate % block_size - block_size;
+    // modify coordinate so that it requires pixel replication to the 
right/down
+    case 0: return coordinate + block_size + (size - (block_size + 1) - 
coordinate) / block_size * block_size;
+    }
+}
+
+static void checkasm_check_gmc(const Mpeg4VideoDSPContext *const mdsp)
+{
+    DECLARE_ALIGNED_8(uint8_t, buf_new)[MAX_BLOCK_HEIGHT * MAX_STRIDE];
+    DECLARE_ALIGNED_8(uint8_t, buf_ref)[MAX_BLOCK_HEIGHT * MAX_STRIDE];
+    DECLARE_ALIGNED_4(uint8_t, srcbuf)[MAX_STRIDE * MAX_HEIGHT];
+
+    declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, const uint8_t *src,
+                 int stride, int h, int ox, int oy,
+                 int dxx, int dxy, int dyx, int dyy,
+                 int shift, int r, int width, int height);
+
+    randomize_buffer(srcbuf);
+    randomize_buffer(buf_ref);
+    memcpy(buf_new, buf_ref, sizeof(buf_new));
+
+    int shift = 1 + rnd() % 4; // range 1..4
+    const int h = rnd() & 1 ? 16 : 8;
+    const int r = (1 << (2 * shift - 1)) - (rnd() & 1);
+    const int width  = FFALIGN(W + rnd() % (MAX_WIDTH - W + 1), 16);  // range 
8..MAX_WIDTH
+    const int height = FFALIGN(h + rnd() % (MAX_HEIGHT - h + 1), 8); // range 
h..MAX_HEIGHT
+    ptrdiff_t stride = FFALIGN(width + rnd() % (MAX_STRIDE - width + 1), 8);
+    const uint8_t *src = srcbuf;
+    uint8_t *dst_new = buf_new, *dst_ref = buf_ref;
+
+    if (rnd() & 1) { // negate stride
+        dst_new += stride * (h - 1);
+        dst_ref += stride * (h - 1);
+        src     += stride * (height - 1);
+        stride  *= -1;
+    }
+    // Get the fullpel component of the motion vector.
+    // Restrict the range so that a (W+1)x(h+1) buffer fits in srcbuf
+    // (if possible) in order to test the non-edge-emulation codepath.
+    int fpel_x = width  == W ? 0 : rnd() % (width  - W);
+    int fpel_y = height == h ? 0 : rnd() % (height - h);
+    int dxx = get_mv_delta(shift, 1), dxy = get_mv_delta(shift, 0);
+    int dyx = get_mv_delta(shift, 0), dyy = get_mv_delta(shift, 1);
+
+    int ox  = fpel_x << (16 + shift) | rnd() & ((1 << (16 + shift)) - 1);
+    int oy  = fpel_y << (16 + shift) | rnd() & ((1 << (16 + shift)) - 1);
+
+    call_ref(dst_ref, src, stride, h, ox, oy,
+             dxx, dxy, dyx, dyy, shift, r, width, height);
+    call_new(dst_new, src, stride, h, ox, oy,
+             dxx, dxy, dyx, dyy, shift, r, width, height);
+    if (memcmp(buf_new, buf_ref, sizeof(buf_new)))
+        fail();
+
+    bench_new(dst_new, src, stride, h, ox, oy,
+              dxx, dxy, dyx, dyy, shift, r, width, height);
+
+    // Now test the case of src being partially outside of the actual picture.
+    if (!check_func(mdsp->gmc, "gmc_edge_emulation"))
+        return; // shouldn't happen
+    int type = rnd() % 8;
+    fpel_x = modify_fpel(fpel_x, width,  8, type % 3);
+    fpel_y = modify_fpel(fpel_y, height, h, type / 3);
+    ox  = fpel_x * (1 << (16 + shift)) | rnd() & ((1 << (16 + shift)) - 1);
+    oy  = fpel_y * (1 << (16 + shift)) | rnd() & ((1 << (16 + shift)) - 1);
+    call_ref(dst_ref, src, stride, h, ox, oy,
+             dxx, dxy, dyx, dyy, shift, r, width, height);
+    call_new(dst_new, src, stride, h, ox, oy,
+             dxx, dxy, dyx, dyy, shift, r, width, height);
+    if (memcmp(buf_new, buf_ref, sizeof(buf_new)))
+        fail();
+
+    bench_new(dst_new, src, stride, h, ox, oy,
+              dxx, dxy, dyx, dyy, shift, r, width, height);
+}
+
+void checkasm_check_mpeg4videodsp(void)
+{
+    Mpeg4VideoDSPContext mdsp;
+
+    ff_mpeg4videodsp_init(&mdsp);
+
+    if (check_func(mdsp.gmc, "gmc")) {
+        checkasm_check_gmc(&mdsp);
+        report("gmc");
+    }
+}
diff --git a/tests/fate/checkasm.mak b/tests/fate/checkasm.mak
index bd44bfd536..8441bb3719 100644
--- a/tests/fate/checkasm.mak
+++ b/tests/fate/checkasm.mak
@@ -42,6 +42,7 @@ FATE_CHECKASM = fate-checkasm-aacencdsp                       
          \
                 fate-checkasm-llvidencdsp                               \
                 fate-checkasm-lpc                                       \
                 fate-checkasm-motion                                    \
+                fate-checkasm-mpeg4videodsp                             \
                 fate-checkasm-mpegvideo_unquantize                      \
                 fate-checkasm-mpegvideoencdsp                           \
                 fate-checkasm-opusdsp                                   \

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to