FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/tests/apv.c
Date: 2025-05-14 17:23:17
Exec Total Coverage
Lines: 184 222 82.9%
Functions: 8 9 88.9%
Branches: 82 108 75.9%

Line Branch Exec Source
1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (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 GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include "libavutil/lfg.h"
20 #include "libavutil/random_seed.h"
21
22 #include "libavcodec/apv_decode.h"
23 #include "libavcodec/apv_dsp.h"
24 #include "libavcodec/put_bits.h"
25
26
27 // Whole file included here to get internal symbols.
28 #include "libavcodec/apv_entropy.c"
29
30
31 // As defined in 7.1.4, for testing.
32 // Adds a check to limit loop after reading 16 zero bits to avoid
33 // getting stuck reading a stream of zeroes forever (this matches
34 // the behaviour of the faster version).
35
36 6291456 static unsigned int apv_read_vlc_spec(GetBitContext *gbc, int k_param)
37 {
38 6291456 unsigned int symbol_value = 0;
39 6291456 int parse_exp_golomb = 1;
40 6291456 int k = k_param;
41 6291456 int stop_loop = 0;
42
43
2/2
✓ Branch 1 taken 3145728 times.
✓ Branch 2 taken 3145728 times.
6291456 if(get_bits1(gbc) == 1) {
44 3145728 parse_exp_golomb = 0;
45 } else {
46
2/2
✓ Branch 1 taken 1572864 times.
✓ Branch 2 taken 1572864 times.
3145728 if (get_bits1(gbc) == 0) {
47 1572864 symbol_value += (1 << k);
48 1572864 parse_exp_golomb = 0;
49 } else {
50 1572864 symbol_value += (2 << k);
51 1572864 parse_exp_golomb = 1;
52 }
53 }
54
2/2
✓ Branch 0 taken 1572864 times.
✓ Branch 1 taken 4718592 times.
6291456 if (parse_exp_golomb) {
55 1572864 int read_limit = 0;
56 do {
57
2/2
✓ Branch 1 taken 1572840 times.
✓ Branch 2 taken 1572840 times.
3145680 if (get_bits1(gbc) == 1) {
58 1572840 stop_loop = 1;
59 } else {
60
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1572816 times.
1572840 if (++read_limit == 16)
61 24 break;
62 1572816 symbol_value += (1 << k);
63 1572816 k++;
64 }
65
2/2
✓ Branch 0 taken 1572816 times.
✓ Branch 1 taken 1572840 times.
3145656 } while (!stop_loop);
66 }
67
2/2
✓ Branch 0 taken 5373952 times.
✓ Branch 1 taken 917504 times.
6291456 if (k > 0)
68 5373952 symbol_value += get_bits(gbc, k);
69
70 6291456 return symbol_value;
71 }
72
73 // As defined in 7.2.4, for testing.
74
75 6493 static void apv_write_vlc_spec(PutBitContext *pbc,
76 unsigned int symbol_val, int k_param)
77 {
78 6493 int prefix_vlc_table[3][2] = {{1, 0}, {0, 0}, {0, 1}};
79
80 6493 unsigned int symbol_value = symbol_val;
81 6493 int val_prefix_vlc = av_clip(symbol_val >> k_param, 0, 2);
82 6493 int bit_count = 0;
83 6493 int k = k_param;
84
85
2/2
✓ Branch 0 taken 20596 times.
✓ Branch 1 taken 6493 times.
27089 while (symbol_value >= (1 << k)) {
86 20596 symbol_value -= (1 << k);
87
2/2
✓ Branch 0 taken 7131 times.
✓ Branch 1 taken 13465 times.
20596 if (bit_count < 2)
88 7131 put_bits(pbc, 1, prefix_vlc_table[val_prefix_vlc][bit_count]);
89 else
90 13465 put_bits(pbc, 1, 0);
91
2/2
✓ Branch 0 taken 13465 times.
✓ Branch 1 taken 7131 times.
20596 if (bit_count >= 2)
92 13465 ++k;
93 20596 ++bit_count;
94 }
95
96
2/2
✓ Branch 0 taken 3437 times.
✓ Branch 1 taken 3056 times.
6493 if(bit_count < 2)
97 3437 put_bits(pbc, 1, prefix_vlc_table[val_prefix_vlc][bit_count]);
98 else
99 3056 put_bits(pbc, 1, 1);
100
101
2/2
✓ Branch 0 taken 3755 times.
✓ Branch 1 taken 2738 times.
6493 if(k > 0)
102 3755 put_bits(pbc, k, symbol_value);
103 6493 }
104
105 // Old version of ff_apv_entropy_decode_block, for test comparison.
106
107 100 static int apv_entropy_decode_block(int16_t *restrict coeff,
108 GetBitContext *restrict gbc,
109 APVEntropyState *restrict state)
110 {
111 100 const APVVLCLUT *lut = state->decode_lut;
112
113 // DC coefficient.
114 {
115 int abs_dc_coeff_diff;
116 int sign_dc_coeff_diff;
117 int dc_coeff;
118
119 100 abs_dc_coeff_diff = apv_read_vlc(gbc, state->prev_k_dc, lut);
120
121
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 8 times.
100 if (abs_dc_coeff_diff > 0)
122 92 sign_dc_coeff_diff = get_bits1(gbc);
123 else
124 8 sign_dc_coeff_diff = 0;
125
126
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 49 times.
100 if (sign_dc_coeff_diff)
127 51 dc_coeff = state->prev_dc - abs_dc_coeff_diff;
128 else
129 49 dc_coeff = state->prev_dc + abs_dc_coeff_diff;
130
131
2/4
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 100 times.
100 if (dc_coeff < APV_MIN_TRANS_COEFF ||
132 dc_coeff > APV_MAX_TRANS_COEFF) {
133 av_log(state->log_ctx, AV_LOG_ERROR,
134 "Out-of-range DC coefficient value: %d "
135 "(from prev_dc %d abs_dc_coeff_diff %d sign_dc_coeff_diff %d)\n",
136 dc_coeff, state->prev_dc, abs_dc_coeff_diff, sign_dc_coeff_diff);
137 return AVERROR_INVALIDDATA;
138 }
139
140 100 coeff[0] = dc_coeff;
141
142 100 state->prev_dc = dc_coeff;
143 100 state->prev_k_dc = FFMIN(abs_dc_coeff_diff >> 1, 5);
144 }
145
146 // AC coefficients.
147 {
148 100 int scan_pos = 1;
149 100 int first_ac = 1;
150 100 int k_run = 0;
151 100 int k_level = state->prev_k_level;
152
153 do {
154 int coeff_zero_run;
155
156 3221 coeff_zero_run = apv_read_vlc(gbc, k_run, lut);
157
158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3221 times.
3221 if (coeff_zero_run > APV_BLK_COEFFS - scan_pos) {
159 av_log(state->log_ctx, AV_LOG_ERROR,
160 "Out-of-range zero-run value: %d (at scan pos %d)\n",
161 coeff_zero_run, scan_pos);
162 return AVERROR_INVALIDDATA;
163 }
164
165
2/2
✓ Branch 0 taken 3128 times.
✓ Branch 1 taken 3221 times.
6349 for (int i = 0; i < coeff_zero_run; i++) {
166 3128 coeff[ff_zigzag_direct[scan_pos]] = 0;
167 3128 ++scan_pos;
168 }
169 3221 k_run = FFMIN(coeff_zero_run >> 2, 2);
170
171
2/2
✓ Branch 0 taken 3172 times.
✓ Branch 1 taken 49 times.
3221 if (scan_pos < APV_BLK_COEFFS) {
172 int abs_ac_coeff_minus1;
173 int sign_ac_coeff;
174 int abs_level, level;
175
176 3172 abs_ac_coeff_minus1 = apv_read_vlc(gbc, k_level, lut);
177 3172 sign_ac_coeff = get_bits(gbc, 1);
178
179 3172 abs_level = abs_ac_coeff_minus1 + 1;
180
2/2
✓ Branch 0 taken 1562 times.
✓ Branch 1 taken 1610 times.
3172 if (sign_ac_coeff)
181 1562 level = -abs_level;
182 else
183 1610 level = abs_level;
184
185
2/4
✓ Branch 0 taken 3172 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3172 times.
3172 if (level < APV_MIN_TRANS_COEFF ||
186 level > APV_MAX_TRANS_COEFF) {
187 av_log(state->log_ctx, AV_LOG_ERROR,
188 "Out-of-range AC coefficient value: %d "
189 "(from k_param %d abs_ac_coeff_minus1 %d sign_ac_coeff %d)\n",
190 level, k_level, abs_ac_coeff_minus1, sign_ac_coeff);
191 }
192
193 3172 coeff[ff_zigzag_direct[scan_pos]] = level;
194
195 3172 k_level = FFMIN(abs_level >> 2, 4);
196
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 3072 times.
3172 if (first_ac) {
197 100 state->prev_k_level = k_level;
198 100 first_ac = 0;
199 }
200
201 3172 ++scan_pos;
202 }
203
204
2/2
✓ Branch 0 taken 3121 times.
✓ Branch 1 taken 100 times.
3221 } while (scan_pos < APV_BLK_COEFFS);
205 }
206
207 100 return 0;
208 }
209
210 static void binary(char *buf, uint32_t value, int bits)
211 {
212 for (int i = 0; i < bits; i++)
213 buf[i] = (value >> (bits - i - 1) & 1) ? '1' : '0';
214 buf[bits] = '\0';
215 }
216
217 1 static int test_apv_read_vlc(void)
218 {
219 APVVLCLUT lut;
220 1 int err = 0;
221
222 1 ff_apv_entropy_build_decode_lut(&lut);
223
224 // Generate all possible 20 bit sequences (padded with zeroes), then
225 // verify that spec and improved parsing functions get the same result
226 // and consume the same number of bits for each possible k_param.
227
228
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
7 for (int k = 0; k <= 5; k++) {
229
2/2
✓ Branch 0 taken 6291456 times.
✓ Branch 1 taken 6 times.
6291462 for (uint32_t b = 0; b < (1 << 20); b++) {
230 6291456 uint8_t buf[8] = {
231 6291456 b >> 12,
232 6291456 b >> 4,
233 6291456 b << 4,
234 0, 0, 0, 0, 0
235 };
236
237 GetBitContext gbc_test, gbc_spec;
238 unsigned int res_test, res_spec;
239 int con_test, con_spec;
240
241 6291456 init_get_bits8(&gbc_test, buf, 8);
242 6291456 init_get_bits8(&gbc_spec, buf, 8);
243
244 6291456 res_test = apv_read_vlc (&gbc_test, k, &lut);
245 6291456 res_spec = apv_read_vlc_spec(&gbc_spec, k);
246
247 6291456 con_test = get_bits_count(&gbc_test);
248 6291456 con_spec = get_bits_count(&gbc_spec);
249
250
2/4
✓ Branch 0 taken 6291456 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6291456 times.
6291456 if (res_test != res_spec ||
251 con_test != con_spec) {
252 char str[21];
253 binary(str, b, 20);
254 av_log(NULL, AV_LOG_ERROR,
255 "Mismatch reading %s (%d) with k=%d:\n", str, b, k);
256 av_log(NULL, AV_LOG_ERROR,
257 "Test function result %d consumed %d bits.\n",
258 res_test, con_test);
259 av_log(NULL, AV_LOG_ERROR,
260 "Spec function result %d consumed %d bits.\n",
261 res_spec, con_spec);
262 ++err;
263 if (err > 10)
264 return err;
265 }
266 }
267 }
268
269 1 return err;
270 }
271
272 3372 static int random_coeff(AVLFG *lfg)
273 {
274 // Geometric distribution of code lengths (1-14 bits),
275 // uniform distribution within codes of the length,
276 // equal probability of either sign.
277 3372 int length = (av_lfg_get(lfg) / (UINT_MAX / 14 + 1));
278 3372 int random = av_lfg_get(lfg);
279 3372 int value = (1 << length) + (random & (1 << length) - 1);
280
2/2
✓ Branch 0 taken 1718 times.
✓ Branch 1 taken 1654 times.
3372 if (random & (1 << length))
281 1718 return value;
282 else
283 1654 return -value;
284 }
285
286 3221 static int random_run(AVLFG *lfg)
287 {
288 // Expoenential distrbution of run lengths.
289 3221 unsigned int random = av_lfg_get(lfg);
290 6401 for (int len = 0;; len++) {
291
2/2
✓ Branch 0 taken 3221 times.
✓ Branch 1 taken 3180 times.
6401 if (random & (1 << len))
292 3221 return len;
293 }
294 // You rolled zero on a 2^32 sided die; well done!
295 return 64;
296 }
297
298 1 static int test_apv_entropy_decode_block(void)
299 {
300 // Generate random entropy blocks, code them, then ensure they
301 // decode to the same block with both implementations.
302
303 APVVLCLUT decode_lut;
304 AVLFG lfg;
305 1 unsigned int seed = av_get_random_seed();
306 1 av_lfg_init(&lfg, seed);
307
308 1 av_log(NULL, AV_LOG_INFO, "seed = %u\n", seed);
309
310 1 ff_apv_entropy_build_decode_lut(&decode_lut);
311
312
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 1 times.
101 for (int t = 0; t < 100; t++) {
313 APVEntropyState state, save_state;
314 int16_t block[64];
315 int16_t block_test1[64];
316 int16_t block_test2[64];
317 uint8_t buffer[1024];
318 PutBitContext pbc;
319 GetBitContext gbc;
320 int bits_written;
321 int pos, run, coeff, level, err;
322 int k_dc, k_run, k_level;
323
324 100 memset(block, 0, sizeof(block));
325 100 memset(buffer, 0, sizeof(buffer));
326 100 init_put_bits(&pbc, buffer, sizeof(buffer));
327
328 // Randomly-constructed state.
329 100 memset(&state, 0, sizeof(state));
330 100 state.decode_lut = &decode_lut;
331 100 state.prev_dc = random_coeff(&lfg);
332 100 state.prev_k_dc = av_lfg_get(&lfg) % 5;
333 100 state.prev_k_level = av_lfg_get(&lfg) % 4;
334 100 save_state = state;
335
336 100 k_dc = state.prev_k_dc;
337 100 k_run = 0;
338 100 k_level = state.prev_k_level;
339
340 100 coeff = random_coeff(&lfg) / 2;
341 100 block[ff_zigzag_direct[0]] = state.prev_dc + coeff;
342 100 apv_write_vlc_spec(&pbc, FFABS(coeff), k_dc);
343
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 8 times.
100 if (coeff != 0)
344 92 put_bits(&pbc, 1, coeff < 0);
345
346 100 pos = 1;
347
2/2
✓ Branch 0 taken 3221 times.
✓ Branch 1 taken 100 times.
3321 while (pos < 64) {
348 3221 run = random_run(&lfg);
349
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3196 times.
3221 if (pos + run > 64)
350 25 run = 64 - pos;
351 3221 apv_write_vlc_spec(&pbc, run, k_run);
352 3221 k_run = av_clip(run >> 2, 0, 2);
353 3221 pos += run;
354
2/2
✓ Branch 0 taken 3172 times.
✓ Branch 1 taken 49 times.
3221 if (pos < 64) {
355 3172 coeff = random_coeff(&lfg);
356 3172 level = FFABS(coeff) - 1;
357 3172 block[ff_zigzag_direct[pos]] = coeff;
358 3172 apv_write_vlc_spec(&pbc, level, k_level);
359 3172 put_bits(&pbc, 1, coeff < 0);
360 3172 k_level = av_clip((level + 1) >> 2, 0, 4);
361 3172 ++pos;
362 }
363 }
364 100 bits_written = put_bits_count(&pbc);
365 100 flush_put_bits(&pbc);
366
367 // Fill output block with a distinctive error value.
368
2/2
✓ Branch 0 taken 6400 times.
✓ Branch 1 taken 100 times.
6500 for (int i = 0; i < 64; i++)
369 6400 block_test1[i] = -9999;
370 100 init_get_bits8(&gbc, buffer, sizeof(buffer));
371
372 100 err = apv_entropy_decode_block(block_test1, &gbc, &state);
373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 if (err < 0) {
374 av_log(NULL, AV_LOG_ERROR, "Entropy decode returned error.\n");
375 return 1;
376 } else {
377 100 int bits_read = get_bits_count(&gbc);
378
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 if (bits_written != bits_read) {
379 av_log(NULL, AV_LOG_ERROR, "Wrote %d bits but read %d.\n",
380 bits_written, bits_read);
381 return 1;
382 } else {
383 100 err = 0;
384
2/2
✓ Branch 0 taken 6400 times.
✓ Branch 1 taken 100 times.
6500 for (int i = 0; i < 64; i++) {
385
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6400 times.
6400 if (block[i] != block_test1[i])
386 ++err;
387 }
388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 if (err > 0) {
389 av_log(NULL, AV_LOG_ERROR, "%d mismatches in output block.\n", err);
390 return err;
391 }
392 }
393 }
394
395 100 init_get_bits8(&gbc, buffer, sizeof(buffer));
396 100 memset(block_test2, 0, 64 * sizeof(int16_t));
397
398 100 err = ff_apv_entropy_decode_block(block_test2, &gbc, &save_state);
399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 if (err < 0) {
400 av_log(NULL, AV_LOG_ERROR, "Entropy decode returned error.\n");
401 return 1;
402 } else {
403 100 int bits_read = get_bits_count(&gbc);
404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 if (bits_written != bits_read) {
405 av_log(NULL, AV_LOG_ERROR, "Wrote %d bits but read %d.\n",
406 bits_written, bits_read);
407 return 1;
408 } else {
409 100 err = 0;
410
2/2
✓ Branch 0 taken 6400 times.
✓ Branch 1 taken 100 times.
6500 for (int i = 0; i < 64; i++) {
411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6400 times.
6400 if (block[i] != block_test2[i])
412 ++err;
413 }
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 if (err > 0) {
415 av_log(NULL, AV_LOG_ERROR, "%d mismatches in output block.\n", err);
416 return err;
417 }
418 }
419 }
420
421
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 if (state.prev_dc != save_state.prev_dc ||
422
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 state.prev_k_dc != save_state.prev_k_dc ||
423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 state.prev_k_level != save_state.prev_k_level) {
424 av_log(NULL, AV_LOG_ERROR, "Entropy state mismatch.\n");
425 return 1;
426 }
427 }
428
429 1 return 0;
430 }
431
432 1 int main(void)
433 {
434 int err;
435
436 1 err = test_apv_read_vlc();
437
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (err) {
438 av_log(NULL, AV_LOG_ERROR, "Read VLC test failed.\n");
439 return err;
440 }
441
442 1 err = test_apv_entropy_decode_block();
443
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (err) {
444 av_log(NULL, AV_LOG_ERROR, "Entropy decode block test failed.\n");
445 return err;
446 }
447
448 1 return 0;
449 }
450