Libav
hevc_mc.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Anton Khirnov
3  *
4  * This file is part of Libav.
5  *
6  * Libav is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Libav is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with Libav; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include <string.h>
22 
23 #include "checkasm.h"
24 
25 #include "libavcodec/avcodec.h"
26 #include "libavcodec/hevcdsp.h"
27 
28 #include "libavutil/common.h"
29 #include "libavutil/intreadwrite.h"
30 
31 // max PU size + interpolation stencil
32 #define BUF_SIZE (FFALIGN(64 + 7, 16) * (64 + 7) * 2)
33 
34 #define PIXEL_SIZE(depth) ((depth + 7) / 8)
35 
36 #define randomize_buffers(buf, size, depth) \
37  do { \
38  uint32_t mask = pixel_mask[depth - 8]; \
39  int i; \
40  for (i = 0; i < size; i += 4) { \
41  uint32_t r = rnd() & mask; \
42  AV_WN32A(buf + i, r); \
43  } \
44  } while (0)
45 
46 static const uint32_t pixel_mask[3] = { 0xffffffff, 0x01ff01ff, 0x03ff03ff };
47 
48 static const int pred_heights[][7] = {
49  [2] = { 8, 4, 2, 0 },
50  [4] = { 16, 8, 4, 2, 0 },
51  [6] = { 8, 0 },
52  [8] = { 32, 16, 8, 4, 2, 0 },
53  [12] = { 16, 0 },
54  [16] = { 64, 32, 16, 12, 8, 4, 0 },
55  [24] = { 32, 0 },
56  [32] = { 64, 32, 24, 16, 8, 0 },
57  [48] = { 64, 0 },
58  [64] = { 64, 48, 32, 16, 0 },
59 };
60 
61 static const int pred_widths[] = { 4, 8, 12, 16, 24, 32, 48, 64 };
62 
63 static const char *interp_names[2][2] = { { "pixels", "h" }, { "v", "hv" } };
64 
65 #define UNWEIGHTED_PRED(dst0, dst1, src0, width, bit_depth) \
66 do { \
67  int i; \
68  for (i = 0; i < FF_ARRAY_ELEMS(pred_heights[i]); i++) { \
69  int height = pred_heights[width][i]; \
70  if (!height) \
71  break; \
72  call_ref(dst0, dststride, src0, srcstride, height); \
73  call_new(dst1, dststride, src0, srcstride, height); \
74  if (memcmp(dst0, dst1, dststride * height)) \
75  fail(); \
76  bench_new(dst1, dststride, src0, srcstride, height); \
77  } \
78 } while (0)
79 
80 #define UNWEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth) \
81 do { \
82  int i; \
83  for (i = 0; i < FF_ARRAY_ELEMS(pred_heights[i]); i++) { \
84  int height = pred_heights[width][i]; \
85  if (!height) \
86  break; \
87  call_ref(dst0, dststride, src0, src1, srcstride, height); \
88  call_new(dst1, dststride, src0, src1, srcstride, height); \
89  if (memcmp(dst0, dst1, dststride * height)) \
90  fail(); \
91  bench_new(dst1, dststride, src0, src1, srcstride, height); \
92  } \
93 } while (0)
94 
95 static void check_unweighted_pred(HEVCDSPContext *h, uint8_t *dst0, uint8_t *dst1,
96  int16_t *src0, int16_t *src1, int bit_depth)
97 {
98  int i;
99 
100  randomize_buffers(src0, BUF_SIZE, 8);
101  randomize_buffers(src1, BUF_SIZE, 8);
102 
103  memset(dst0, 0, BUF_SIZE * sizeof(*dst0));
104  memset(dst1, 0, BUF_SIZE * sizeof(*dst1));
105 
106  for (i = 0; i < FF_ARRAY_ELEMS(pred_widths); i++) {
107  const int width = pred_widths[i];
108  const int srcstride = FFALIGN(width, 16) * sizeof(*src0);
109  const int dststride = FFALIGN(width, 16) * PIXEL_SIZE(bit_depth);
110 
111  {
112  declare_func(void, uint8_t *dst, ptrdiff_t dststride, int16_t *src, ptrdiff_t srcstride, int height);
113  if (check_func(h->put_unweighted_pred[i], "put_unweighted_pred_%d_%d", width, bit_depth))
114  UNWEIGHTED_PRED(dst0, dst1, src0, width, bit_depth);
115  if (check_func(h->put_unweighted_pred_chroma[i], "put_unweighted_pred_%d_%d", width / 2, bit_depth))
116  UNWEIGHTED_PRED(dst0, dst1, src0, width, bit_depth);
117  }
118  {
119  declare_func(void, uint8_t *dst, ptrdiff_t dststride,
120  int16_t *src0, int16_t *src1, ptrdiff_t srcstride, int height);
121  if (check_func(h->put_unweighted_pred_avg[i], "put_unweighted_pred_avg_%d_%d", width, bit_depth))
122  UNWEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth);
123  if (check_func(h->put_unweighted_pred_avg_chroma[i], "put_unweighted_pred_avg_%d_%d", width / 2, bit_depth))
124  UNWEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth);
125  }
126  }
127 }
128 
129 #define WEIGHTED_PRED(dst0, dst1, src0, width, bit_depth) \
130 do { \
131  int i; \
132  for (i = 0; i < FF_ARRAY_ELEMS(pred_heights[i]); i++) { \
133  int height = pred_heights[width][i]; \
134  if (!height) \
135  break; \
136  call_ref(denom, weight0, offset0, dst0, dststride, src0, srcstride, height); \
137  call_new(denom, weight0, offset0, dst1, dststride, src0, srcstride, height); \
138  if (memcmp(dst0, dst1, dststride * height)) \
139  fail(); \
140  bench_new(denom, weight0, offset0, dst1, dststride, src0, srcstride, height); \
141  } \
142 } while (0)
143 
144 #define WEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth) \
145 do { \
146  int i; \
147  for (i = 0; i < FF_ARRAY_ELEMS(pred_heights[i]); i++) { \
148  int height = pred_heights[width][i]; \
149  if (!height) \
150  break; \
151  call_ref(denom, weight0, weight1, offset0, offset1, dst0, dststride, src0, src1, srcstride, height); \
152  call_new(denom, weight0, weight1, offset0, offset1, dst1, dststride, src0, src1, srcstride, height); \
153  if (memcmp(dst0, dst1, dststride * height)) \
154  fail(); \
155  bench_new(denom, weight0, weight1, offset0, offset1, dst1, dststride, src0, src1, srcstride, height); \
156  } \
157 } while (0)
158 
159 static void check_weighted_pred(HEVCDSPContext *h, uint8_t *dst0, uint8_t *dst1,
160  int16_t *src0, int16_t *src1, int bit_depth)
161 {
162  uint8_t denom;
163  int16_t weight0, weight1, offset0, offset1;
164  int i;
165 
166  randomize_buffers(src0, BUF_SIZE, 8);
167  randomize_buffers(src1, BUF_SIZE, 8);
168 
169  denom = rnd() & 7;
170  weight0 = denom + ((rnd() & 255) - 128);
171  weight1 = denom + ((rnd() & 255) - 128);
172  offset0 = (rnd() & 255) - 128;
173  offset1 = (rnd() & 255) - 128;
174 
175  memset(dst0, 0, BUF_SIZE * sizeof(*dst0));
176  memset(dst1, 0, BUF_SIZE * sizeof(*dst1));
177 
178  for (i = 0; i < FF_ARRAY_ELEMS(pred_widths); i++) {
179  const int width = pred_widths[i];
180  const int srcstride = FFALIGN(width, 16) * sizeof(*src0);
181  const int dststride = FFALIGN(width, 16) * PIXEL_SIZE(bit_depth);
182 
183  {
184  declare_func(void, uint8_t denom, int16_t weight, int16_t offset,
185  uint8_t *dst, ptrdiff_t dststride, int16_t *src, ptrdiff_t srcstride, int height);
186  if (check_func(h->weighted_pred[i], "weighted_pred_%d_%d", width, bit_depth))
187  WEIGHTED_PRED(dst0, dst1, src0, width, bit_depth);
188  if (check_func(h->weighted_pred_chroma[i], "weighted_pred_%d_%d", width / 2, bit_depth))
189  WEIGHTED_PRED(dst0, dst1, src0, width, bit_depth);
190  }
191  {
192  declare_func(void, uint8_t denom, int16_t weight0, int16_t weight1, int16_t offset0, int16_t offset1,
193  uint8_t *dst, ptrdiff_t dststride, int16_t *src0, int16_t *src1, ptrdiff_t srcstride, int height);
194  if (check_func(h->weighted_pred_avg[i], "weighted_pred_avg_%d_%d", width, bit_depth))
195  WEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth);
196  if (check_func(h->weighted_pred_avg_chroma[i], "weighted_pred_avg_%d_%d", width / 2, bit_depth))
197  WEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth);
198  }
199  }
200 }
201 
202 static void check_epel(HEVCDSPContext *h, int16_t *dst0, int16_t *dst1,
203  uint8_t *src, int16_t *mcbuffer, int bit_depth)
204 {
205  int i, j, k, l, mx, my;
206 
207  declare_func(void, int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
208  int height, int mx, int my, int16_t *mcbuffer);
209 
210  randomize_buffers(src, BUF_SIZE, bit_depth);
211 
212  memset(dst0, 0, BUF_SIZE * sizeof(*dst0));
213  memset(dst1, 0, BUF_SIZE * sizeof(*dst1));
214 
215  for (i = 0; i < 2; i++) {
216  for (j = 0; j < 2; j++) {
217  for (k = 0; k < FF_ARRAY_ELEMS(h->put_hevc_epel[i][j]); k++) {
218  int width = pred_widths[k] / 2;
219  int dststride = FFALIGN(width, 16) * sizeof(*dst0);
220  int srcstride = FFALIGN(width + 3, 8) * PIXEL_SIZE(bit_depth);
221 
222  if (!check_func(h->put_hevc_epel[i][j][k], "epel_%s_%d_%d", interp_names[i][j], width, bit_depth))
223  continue;
224 
225  for (l = 0; l < FF_ARRAY_ELEMS(pred_heights[0]); l++) {
226  int height = pred_heights[width][l];
227 
228  if (!height)
229  continue;
230 
231  for (my = i; my < (i ? 8 : 1); my++)
232  for (mx = j; mx < (j ? 8 : 1); mx++) {
233  call_ref(dst0, dststride, src + srcstride + PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
234  call_new(dst1, dststride, src + srcstride + PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
235 
236  if (memcmp(dst0, dst1, dststride * height * sizeof(*dst0)))
237  fail();
238 
239  bench_new(dst1, dststride, src + srcstride + PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
240  }
241  }
242  }
243  }
244  }
245 }
246 
247 static void check_qpel(HEVCDSPContext *h, int16_t *dst0, int16_t *dst1,
248  uint8_t *src, int16_t *mcbuffer, int bit_depth)
249 {
250  int i, j, k, l, mx, my;
251 
252  declare_func(void, int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
253  int height, int mx, int my, int16_t *mcbuffer);
254 
255  randomize_buffers(src, BUF_SIZE, bit_depth);
256 
257  memset(dst0, 0, BUF_SIZE * sizeof(*dst0));
258  memset(dst1, 0, BUF_SIZE * sizeof(*dst1));
259 
260  for (i = 0; i < 2; i++) {
261  for (j = 0; j < 2; j++) {
262  for (k = 0; k < FF_ARRAY_ELEMS(h->put_hevc_qpel[i][j]); k++) {
263  int width = pred_widths[k];
264  int dststride = FFALIGN(width, 16) * sizeof(*dst0);
265  int srcstride = FFALIGN(width + 7, 8) * PIXEL_SIZE(bit_depth);
266 
267  if (!check_func(h->put_hevc_qpel[i][j][k], "qpel_%s_%d_%d", interp_names[i][j], width, bit_depth))
268  continue;
269 
270  for (l = 0; l < FF_ARRAY_ELEMS(pred_heights[0]); l++) {
271  int height = pred_heights[width][l];
272 
273  if (!height)
274  continue;
275 
276  for (my = i; my < (i ? 2 : 1); my++)
277  for (mx = j; mx < (j ? 2 : 1); mx++) {
278  call_ref(dst0, dststride, src + 3 * srcstride + 3 * PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
279  call_new(dst1, dststride, src + 3 * srcstride + 3 * PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
280 
281  if (memcmp(dst0, dst1, dststride * height * sizeof(*dst0)))
282  fail();
283 
284  bench_new(dst1, dststride, src + 3 * srcstride + 3 * PIXEL_SIZE(bit_depth), srcstride, height, mx, my, mcbuffer);
285  }
286  }
287  }
288  }
289  }
290 }
291 
293 {
294  DECLARE_ALIGNED(16, uint8_t, buf8_0)[BUF_SIZE];
295  DECLARE_ALIGNED(16, uint8_t, buf8_1)[BUF_SIZE];
296 
297  DECLARE_ALIGNED(16, int16_t, buf16_0)[BUF_SIZE];
298  DECLARE_ALIGNED(16, int16_t, buf16_1)[BUF_SIZE];
299 
300  DECLARE_ALIGNED(16, int16_t, mcbuffer)[BUF_SIZE];
301 
302  HEVCDSPContext h;
303  int bit_depth;
304 
305  for (bit_depth = 8; bit_depth <= 10; bit_depth++) {
306  ff_hevc_dsp_init(&h, bit_depth);
307  check_qpel(&h, buf16_0, buf16_1, buf8_0, mcbuffer, bit_depth);
308  }
309  report("qpel");
310 
311  for (bit_depth = 8; bit_depth <= 10; bit_depth++) {
312  ff_hevc_dsp_init(&h, bit_depth);
313  check_epel(&h, buf16_0, buf16_1, buf8_0, mcbuffer, bit_depth);
314  }
315  report("epel");
316 
317  for (bit_depth = 8; bit_depth <= 10; bit_depth++) {
318  ff_hevc_dsp_init(&h, bit_depth);
319  check_unweighted_pred(&h, buf8_0, buf8_1, buf16_0, buf16_1, bit_depth);
320  }
321  report("unweighted_pred");
322 
323  for (bit_depth = 8; bit_depth <= 10; bit_depth++) {
324  ff_hevc_dsp_init(&h, bit_depth);
325  check_weighted_pred(&h, buf8_0, buf8_1, buf16_0, buf16_1, bit_depth);
326  }
327  report("weighted_pred");
328 }
#define WEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth)
Definition: hevc_mc.c:144
void(* put_unweighted_pred_avg[8])(uint8_t *dst, ptrdiff_t dststride, int16_t *src1, int16_t *src2, ptrdiff_t srcstride, int height)
Definition: hevcdsp.h:71
void(* put_hevc_epel[2][2][8])(int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, int height, int mx, int my, int16_t *mcbuffer)
Definition: hevcdsp.h:63
void(* put_unweighted_pred[8])(uint8_t *dst, ptrdiff_t dststride, int16_t *src, ptrdiff_t srcstride, int height)
Definition: hevcdsp.h:67
#define DECLARE_ALIGNED(n, t, v)
Definition: mem.h:58
#define FF_ARRAY_ELEMS(a)
#define report
Definition: checkasm.h:83
void(* weighted_pred_chroma[8])(uint8_t denom, int16_t wlxFlag, int16_t olxFlag, uint8_t *dst, ptrdiff_t dststride, int16_t *src, ptrdiff_t srcstride, int height)
Definition: hevcdsp.h:80
uint8_t
void(* weighted_pred_avg_chroma[8])(uint8_t denom, int16_t wl0Flag, int16_t wl1Flag, int16_t ol0Flag, int16_t ol1Flag, uint8_t *dst, ptrdiff_t dststride, int16_t *src1, int16_t *src2, ptrdiff_t srcstride, int height)
Definition: hevcdsp.h:87
void(* weighted_pred_avg[8])(uint8_t denom, int16_t wl0Flag, int16_t wl1Flag, int16_t ol0Flag, int16_t ol1Flag, uint8_t *dst, ptrdiff_t dststride, int16_t *src1, int16_t *src2, ptrdiff_t srcstride, int height)
Definition: hevcdsp.h:83
#define UNWEIGHTED_PRED_AVG(dst0, dst1, src0, src1, width, bit_depth)
Definition: hevc_mc.c:80
#define FFALIGN(x, a)
Definition: macros.h:48
void checkasm_check_hevc_mc(void)
Definition: hevc_mc.c:292
void(* put_unweighted_pred_chroma[8])(uint8_t *dst, ptrdiff_t dststride, int16_t *src, ptrdiff_t srcstride, int height)
Definition: hevcdsp.h:69
#define src
Definition: vp8dsp.c:254
static const char * interp_names[2][2]
Definition: hevc_mc.c:63
#define declare_func(ret,...)
Definition: checkasm.h:76
static void check_weighted_pred(HEVCDSPContext *h, uint8_t *dst0, uint8_t *dst1, int16_t *src0, int16_t *src1, int bit_depth)
Definition: hevc_mc.c:159
#define WEIGHTED_PRED(dst0, dst1, src0, width, bit_depth)
Definition: hevc_mc.c:129
#define fail()
Definition: checkasm.h:80
static const int pred_widths[]
Definition: hevc_mc.c:61
void(* put_hevc_qpel[2][2][8])(int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride, int height, int mx, int my, int16_t *mcbuffer)
Definition: hevcdsp.h:60
#define BUF_SIZE
Definition: hevc_mc.c:32
uint32_t i
Definition: intfloat.h:28
static void check_qpel(HEVCDSPContext *h, int16_t *dst0, int16_t *dst1, uint8_t *src, int16_t *mcbuffer, int bit_depth)
Definition: hevc_mc.c:247
#define UNWEIGHTED_PRED(dst0, dst1, src0, width, bit_depth)
Definition: hevc_mc.c:65
static const int pred_heights[][7]
Definition: hevc_mc.c:48
#define call_ref(...)
Definition: checkasm.h:86
void ff_hevc_dsp_init(HEVCDSPContext *hevcdsp, int bit_depth)
Definition: hevcdsp.c:136
static int width
Definition: utils.c:156
#define src1
Definition: h264pred.c:139
Libavcodec external API header.
static void check_epel(HEVCDSPContext *h, int16_t *dst0, int16_t *dst1, uint8_t *src, int16_t *mcbuffer, int bit_depth)
Definition: hevc_mc.c:202
void(* weighted_pred[8])(uint8_t denom, int16_t wlxFlag, int16_t olxFlag, uint8_t *dst, ptrdiff_t dststride, int16_t *src, ptrdiff_t srcstride, int height)
Definition: hevcdsp.h:77
#define check_func(func,...)
Definition: checkasm.h:72
#define src0
Definition: h264pred.c:138
#define PIXEL_SIZE(depth)
Definition: hevc_mc.c:34
static const uint32_t pixel_mask[3]
Definition: hevc_mc.c:46
int height
Definition: gxfenc.c:72
static void check_unweighted_pred(HEVCDSPContext *h, uint8_t *dst0, uint8_t *dst1, int16_t *src0, int16_t *src1, int bit_depth)
Definition: hevc_mc.c:95
common internal and external API header
void(* put_unweighted_pred_avg_chroma[8])(uint8_t *dst, ptrdiff_t dststride, int16_t *src1, int16_t *src2, ptrdiff_t srcstride, int height)
Definition: hevcdsp.h:74
#define rnd()
Definition: checkasm.h:65
#define randomize_buffers(buf, size, depth)
Definition: hevc_mc.c:36
#define bench_new(...)
Definition: checkasm.h:173
#define call_new(...)
Definition: checkasm.h:141