FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/tests/checkasm/mpeg4videodsp.c
Date: 2026-05-03 03:13:14
Exec Total Coverage
Lines: 54 58 93.1%
Functions: 5 5 100.0%
Branches: 22 42 52.4%

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