FFmpeg
Loading...
Searching...
No Matches
mpeg4videodsp.c
Go to the documentation of this file.
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"
24#include "libavutil/avassert.h"
27
28enum {
29 MAX_WIDTH = 1024,
33 W = 8,
34};
35
36static_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
47static int get_signed_rnd(int nb_bits)
48{
49 int32_t r = rnd();
50 return r >> (32 - nb_bits);
51}
52
53static 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 return get_signed_rnd(6 + shift) * 16 + (is_diag ? (1 << (16 + shift)) : 0);
62}
63
64static int modify_fpel(int coordinate, int size, int block_size, int type)
65{
66 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 case 1: return coordinate % block_size - block_size;
72 // modify coordinate so that it requires pixel replication to the right/down
73 case 0: return coordinate + block_size + (size - (block_size + 1) - coordinate) / block_size * block_size;
74 }
75}
76
77static void checkasm_check_gmc(const Mpeg4VideoDSPContext *const mdsp)
78{
81 DECLARE_ALIGNED_4(uint8_t, srcbuf)[MAX_STRIDE * MAX_HEIGHT];
82
83 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 randomize_buffer(srcbuf);
89 randomize_buffer(buf_ref);
90 memcpy(buf_new, buf_ref, sizeof(buf_new));
91
92 int shift = 1 + rnd() % 4; // range 1..4
93 const int h = rnd() & 1 ? 16 : 8;
94 const int r = (1 << (2 * shift - 1)) - (rnd() & 1);
95 const int width = FFALIGN(W + rnd() % (MAX_WIDTH - W + 1), 16); // range 8..MAX_WIDTH
96 const int height = FFALIGN(h + rnd() % (MAX_HEIGHT - h + 1), 8); // range h..MAX_HEIGHT
97 ptrdiff_t stride = FFALIGN(width + rnd() % (MAX_STRIDE - width + 1), 8);
98 const uint8_t *src = srcbuf;
99 uint8_t *dst_new = buf_new, *dst_ref = buf_ref;
100
101 if (rnd() & 1) { // negate stride
102 dst_new += stride * (h - 1);
103 dst_ref += stride * (h - 1);
104 src += stride * (height - 1);
105 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 int fpel_x = width == W ? 0 : rnd() % (width - W);
111 int fpel_y = height == h ? 0 : rnd() % (height - h);
112 int dxx = get_mv_delta(shift, 1), dxy = get_mv_delta(shift, 0);
113 int dyx = get_mv_delta(shift, 0), dyy = get_mv_delta(shift, 1);
114
115 int ox = fpel_x << (16 + shift) | rnd() & ((1 << (16 + shift)) - 1);
116 int oy = fpel_y << (16 + shift) | rnd() & ((1 << (16 + shift)) - 1);
117
118 call_ref(dst_ref, src, stride, h, ox, oy,
119 dxx, dxy, dyx, dyy, shift, r, width, height);
120 call_new(dst_new, src, stride, h, ox, oy,
121 dxx, dxy, dyx, dyy, shift, r, width, height);
122 if (memcmp(buf_new, buf_ref, sizeof(buf_new)))
123 fail();
124
125 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 if (!check_func(mdsp->gmc, "gmc_edge_emulation"))
130 return; // shouldn't happen
131 int type = rnd() % 8;
132 fpel_x = modify_fpel(fpel_x, width, 8, type % 3);
133 fpel_y = modify_fpel(fpel_y, height, h, type / 3);
134 ox = fpel_x * (1 << (16 + shift)) | rnd() & ((1 << (16 + shift)) - 1);
135 oy = fpel_y * (1 << (16 + shift)) | rnd() & ((1 << (16 + shift)) - 1);
136 call_ref(dst_ref, src, stride, h, ox, oy,
137 dxx, dxy, dyx, dyy, shift, r, width, height);
138 call_new(dst_new, src, stride, h, ox, oy,
139 dxx, dxy, dyx, dyy, shift, r, width, height);
140 if (memcmp(buf_new, buf_ref, sizeof(buf_new)))
141 fail();
142
143 bench_new(dst_new, src, stride, h, ox, oy,
144 dxx, dxy, dyx, dyy, shift, r, width, height);
145}
146
148{
150
152
153 if (check_func(mdsp.gmc, "gmc")) {
154 checkasm_check_gmc(&mdsp);
155 report("gmc");
156 }
157}
uint8_t ptrdiff_t const uint8_t ptrdiff_t int intptr_t intptr_t int int16_t * dst
Definition dsp.h:87
int32_t
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_unreachable(msg)
Asserts that are used as compiler optimization hints depending upon ASSERT_LEVEL and NBDEBUG.
Definition avassert.h:109
#define rnd
Definition checkasm.h:136
#define declare_func
Definition test.h:489
#define fail
Definition test.h:479
#define bench_new
Definition test.h:487
#define check_func
Definition test.h:481
#define call_new
Definition test.h:486
#define call_ref
Definition test.h:485
#define report
Definition test.h:480
cl_device_type type
#define r
Definition input.c:42
#define W(a, i, v)
Definition jpegls.h:119
static int shift(int a, int b)
Definition bonk.c:261
av_cold void ff_mpeg4videodsp_init(Mpeg4VideoDSPContext *c)
#define FFALIGN(x, a)
Definition macros.h:78
#define DECLARE_ALIGNED_4(t, v)
#define DECLARE_ALIGNED_8(t, v)
void(* gmc)(uint8_t *dst, const uint8_t *src, ptrdiff_t stride, int h, int ox, int oy, int dxx, int dxy, int dyx, int dyy, int shift, int r, int width, int height)
global motion compensation.
#define stride
#define MAX_HEIGHT
Definition hpeldsp.c:30
#define MAX_STRIDE
Definition hpeldsp.c:31
@ MAX_WIDTH
arbitrary limit used for the tests
Definition huffyuvdsp.c:32
static void checkasm_check_gmc(const Mpeg4VideoDSPContext *const mdsp)
@ MAX_BLOCK_HEIGHT
void checkasm_check_mpeg4videodsp(void)
static int get_signed_rnd(int nb_bits)
static int modify_fpel(int coordinate, int size, int block_size, int type)
#define randomize_buffer(buf)
static int get_mv_delta(int shift, int is_diag)
#define src
Definition vp8dsp.c:248
#define height
Definition dsp.h:89
#define width
Definition dsp.h:89
int size