| 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 |