FFmpeg
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 
21 #include "checkasm.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,
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 static int get_signed_rnd(int nb_bits)
47 {
48  int32_t r = rnd();
49  return r >> (32 - nb_bits);
50 }
51 
52 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  return get_signed_rnd(6 + shift) * 16 + (is_diag ? (1 << (16 + shift)) : 0);
61 }
62 
63 static int modify_fpel(int coordinate, int size, int block_size, int type)
64 {
65  switch (type) {
66  default: av_unreachable("impossible");
67  // fallthrough
68  case 2: return coordinate; // do nothing
69  // modify coordinate so that it requires pixel replication to the left/top
70  case 1: return coordinate % block_size - block_size;
71  // modify coordinate so that it requires pixel replication to the right/down
72  case 0: return coordinate + block_size + (size - (block_size + 1) - coordinate) / block_size * block_size;
73  }
74 }
75 
76 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  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  randomize_buffer(srcbuf);
88  randomize_buffer(buf_ref);
89  memcpy(buf_new, buf_ref, sizeof(buf_new));
90 
91  int shift = 1 + rnd() % 4; // range 1..4
92  const int h = rnd() & 1 ? 16 : 8;
93  const int r = (1 << (2 * shift - 1)) - (rnd() & 1);
94  const int width = FFALIGN(W + rnd() % (MAX_WIDTH - W + 1), 16); // range 8..MAX_WIDTH
95  const int height = FFALIGN(h + rnd() % (MAX_HEIGHT - h + 1), 8); // range h..MAX_HEIGHT
96  ptrdiff_t stride = FFALIGN(width + rnd() % (MAX_STRIDE - width + 1), 8);
97  const uint8_t *src = srcbuf;
98  uint8_t *dst_new = buf_new, *dst_ref = buf_ref;
99 
100  if (rnd() & 1) { // negate stride
101  dst_new += stride * (h - 1);
102  dst_ref += stride * (h - 1);
103  src += stride * (height - 1);
104  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  int fpel_x = width == W ? 0 : rnd() % (width - W);
110  int fpel_y = height == h ? 0 : rnd() % (height - h);
111  int dxx = get_mv_delta(shift, 1), dxy = get_mv_delta(shift, 0);
112  int dyx = get_mv_delta(shift, 0), dyy = get_mv_delta(shift, 1);
113 
114  int ox = fpel_x << (16 + shift) | rnd() & ((1 << (16 + shift)) - 1);
115  int oy = fpel_y << (16 + shift) | rnd() & ((1 << (16 + shift)) - 1);
116 
117  call_ref(dst_ref, src, stride, h, ox, oy,
118  dxx, dxy, dyx, dyy, shift, r, width, height);
119  call_new(dst_new, src, stride, h, ox, oy,
120  dxx, dxy, dyx, dyy, shift, r, width, height);
121  if (memcmp(buf_new, buf_ref, sizeof(buf_new)))
122  fail();
123 
124  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  if (!check_func(mdsp->gmc, "gmc_edge_emulation"))
129  return; // shouldn't happen
130  int type = rnd() % 8;
131  fpel_x = modify_fpel(fpel_x, width, 8, type % 3);
132  fpel_y = modify_fpel(fpel_y, height, h, type / 3);
133  ox = fpel_x * (1 << (16 + shift)) | rnd() & ((1 << (16 + shift)) - 1);
134  oy = fpel_y * (1 << (16 + shift)) | rnd() & ((1 << (16 + shift)) - 1);
135  call_ref(dst_ref, src, stride, h, ox, oy,
136  dxx, dxy, dyx, dyy, shift, r, width, height);
137  call_new(dst_new, src, stride, h, ox, oy,
138  dxx, dxy, dyx, dyy, shift, r, width, height);
139  if (memcmp(buf_new, buf_ref, sizeof(buf_new)))
140  fail();
141 
142  bench_new(dst_new, src, stride, h, ox, oy,
143  dxx, dxy, dyx, dyy, shift, r, width, height);
144 }
145 
146 void checkasm_check_mpeg4videodsp(void)
147 {
148  Mpeg4VideoDSPContext mdsp;
149 
150  ff_mpeg4videodsp_init(&mdsp);
151 
152  if (check_func(mdsp.gmc, "gmc")) {
153  checkasm_check_gmc(&mdsp);
154  report("gmc");
155  }
156 }
mem_internal.h
MAX_WIDTH
@ MAX_WIDTH
Definition: mpeg4videodsp.c:28
checkasm.h
MAX_STRIDE
@ MAX_STRIDE
Definition: mpeg4videodsp.c:30
avassert.h
intreadwrite.h
needed
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is needed
Definition: filter_design.txt:212
mpeg4videodsp.h
MAX_HEIGHT
@ MAX_HEIGHT
Definition: mpeg4videodsp.c:29
MAX_BLOCK_HEIGHT
@ MAX_BLOCK_HEIGHT
Definition: mpeg4videodsp.c:31
width
#define width
Definition: dsp.h:89
W
@ W
Definition: mpeg4videodsp.c:32