FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/tests/checkasm/mpeg4videodsp.c
Date: 2026-09-08 19:51:47
Exec Total Coverage
Lines: 53 58 91.4%
Functions: 5 5 100.0%
Branches: 21 66 31.8%

Line Branch Exec Source
1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include <assert.h>
20 #include <string.h>
21
22 #include "checkasm.h"
23 #include "libavcodec/mpeg4videodsp.h"
24 #include "libavutil/avassert.h"
25 #include "libavutil/intreadwrite.h"
26 #include "libavutil/mem_internal.h"
27
28 enum {
29 MAX_WIDTH = 1024,
30 MAX_HEIGHT = 64,
31 MAX_STRIDE = MAX_WIDTH,
32 MAX_BLOCK_HEIGHT = 16,
33 W = 8,
34 };
35
36 static_assert(MAX_WIDTH <= MAX_STRIDE, "stride needs to be >= width");
37
38 #define randomize_buffer(buf) \
39 do { \
40 static_assert(!(sizeof(buf) % 4), "Tail handling needed"); \
41 for (size_t k = 0; k < sizeof(buf); k += 4) { \
42 uint32_t r = rnd(); \
43 AV_WN32A(buf + k, r); \
44 } \
45 } while (0)
46
47 8 static int get_signed_rnd(int nb_bits)
48 {
49 8 int32_t r = rnd();
50 8 return r >> (32 - nb_bits);
51 }
52
53 8 static int get_mv_delta(int shift, int is_diag)
54 {
55 // The coordinates of the motion vector differences are fixed point numbers
56 // whose fractional part has 16+shift bits. We use 5+shift+4 bit mantissa
57 // for the deviation from the normal, so that the absolute value corresponds
58 // to < 2^(-7). For height 16, the maximum absolute deviation is < 1/8.
59 // Additionally, we always use zero for the four least significant bits,
60 // as the x86 implementation always falls back to the C one if it is not so.
61
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
8 return get_signed_rnd(6 + shift) * 16 + (is_diag ? (1 << (16 + shift)) : 0);
62 }
63
64 4 static int modify_fpel(int coordinate, int size, int block_size, int type)
65 {
66
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
4 switch (type) {
67 default: av_unreachable("impossible");
68 // fallthrough
69 case 2: return coordinate; // do nothing
70 // modify coordinate so that it requires pixel replication to the left/top
71 2 case 1: return coordinate % block_size - block_size;
72 // modify coordinate so that it requires pixel replication to the right/down
73 2 case 0: return coordinate + block_size + (size - (block_size + 1) - coordinate) / block_size * block_size;
74 }
75 }
76
77 2 static void checkasm_check_gmc(const Mpeg4VideoDSPContext *const mdsp)
78 {
79 DECLARE_ALIGNED_8(uint8_t, buf_new)[MAX_BLOCK_HEIGHT * MAX_STRIDE];
80 DECLARE_ALIGNED_8(uint8_t, buf_ref)[MAX_BLOCK_HEIGHT * MAX_STRIDE];
81 DECLARE_ALIGNED_4(uint8_t, srcbuf)[MAX_STRIDE * MAX_HEIGHT];
82
83 2 declare_func(void, uint8_t *dst, const uint8_t *src,
84 ptrdiff_t stride, int h, int ox, int oy,
85 int dxx, int dxy, int dyx, int dyy,
86 int shift, int r, int width, int height);
87
88
2/2
✓ Branch 1 taken 32768 times.
✓ Branch 2 taken 2 times.
32770 randomize_buffer(srcbuf);
89
2/2
✓ Branch 1 taken 8192 times.
✓ Branch 2 taken 2 times.
8194 randomize_buffer(buf_ref);
90 2 memcpy(buf_new, buf_ref, sizeof(buf_new));
91
92 2 int shift = 1 + rnd() % 4; // range 1..4
93
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 const int h = rnd() & 1 ? 16 : 8;
94 2 const int r = (1 << (2 * shift - 1)) - (rnd() & 1);
95 2 const int width = FFALIGN(W + rnd() % (MAX_WIDTH - W + 1), 16); // range 8..MAX_WIDTH
96 2 const int height = FFALIGN(h + rnd() % (MAX_HEIGHT - h + 1), 8); // range h..MAX_HEIGHT
97 2 ptrdiff_t stride = FFALIGN(width + rnd() % (MAX_STRIDE - width + 1), 8);
98 2 const uint8_t *src = srcbuf;
99 2 uint8_t *dst_new = buf_new, *dst_ref = buf_ref;
100
101
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rnd() & 1) { // negate stride
102 2 dst_new += stride * (h - 1);
103 2 dst_ref += stride * (h - 1);
104 2 src += stride * (height - 1);
105 2 stride *= -1;
106 }
107 // Get the fullpel component of the motion vector.
108 // Restrict the range so that a (W+1)x(h+1) buffer fits in srcbuf
109 // (if possible) in order to test the non-edge-emulation codepath.
110
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 int fpel_x = width == W ? 0 : rnd() % (width - W);
111
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 int fpel_y = height == h ? 0 : rnd() % (height - h);
112 2 int dxx = get_mv_delta(shift, 1), dxy = get_mv_delta(shift, 0);
113 2 int dyx = get_mv_delta(shift, 0), dyy = get_mv_delta(shift, 1);
114
115 2 int ox = fpel_x << (16 + shift) | rnd() & ((1 << (16 + shift)) - 1);
116 2 int oy = fpel_y << (16 + shift) | rnd() & ((1 << (16 + shift)) - 1);
117
118
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 call_ref(dst_ref, src, stride, h, ox, oy,
119 dxx, dxy, dyx, dyy, shift, r, width, height);
120 2 call_new(dst_new, src, stride, h, ox, oy,
121 dxx, dxy, dyx, dyy, shift, r, width, height);
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (memcmp(buf_new, buf_ref, sizeof(buf_new)))
123 fail();
124
125
1/18
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
2 bench_new(dst_new, src, stride, h, ox, oy,
126 dxx, dxy, dyx, dyy, shift, r, width, height);
127
128 // Now test the case of src being partially outside of the actual picture.
129
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (!check_func(mdsp->gmc, "gmc_edge_emulation"))
130 return; // shouldn't happen
131 2 int type = rnd() % 8;
132 2 fpel_x = modify_fpel(fpel_x, width, 8, type % 3);
133 2 fpel_y = modify_fpel(fpel_y, height, h, type / 3);
134 2 ox = fpel_x * (1 << (16 + shift)) | rnd() & ((1 << (16 + shift)) - 1);
135 2 oy = fpel_y * (1 << (16 + shift)) | rnd() & ((1 << (16 + shift)) - 1);
136
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 call_ref(dst_ref, src, stride, h, ox, oy,
137 dxx, dxy, dyx, dyy, shift, r, width, height);
138 2 call_new(dst_new, src, stride, h, ox, oy,
139 dxx, dxy, dyx, dyy, shift, r, width, height);
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (memcmp(buf_new, buf_ref, sizeof(buf_new)))
141 fail();
142
143
1/18
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✗ Branch 43 not taken.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
2 bench_new(dst_new, src, stride, h, ox, oy,
144 dxx, dxy, dyx, dyy, shift, r, width, height);
145 }
146
147 14 void checkasm_check_mpeg4videodsp(void)
148 {
149 Mpeg4VideoDSPContext mdsp;
150
151 14 ff_mpeg4videodsp_init(&mdsp);
152
153
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 12 times.
14 if (check_func(mdsp.gmc, "gmc")) {
154 2 checkasm_check_gmc(&mdsp);
155 2 report("gmc");
156 }
157 14 }
158