FFmpeg
vc1dsp.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2022 Ben Avison
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg 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  * FFmpeg 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 FFmpeg; 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/vc1dsp.h"
26 
27 #include "libavutil/common.h"
28 #include "libavutil/internal.h"
29 #include "libavutil/intreadwrite.h"
30 #include "libavutil/mem.h"
31 #include "libavutil/mem_internal.h"
32 
33 #define VC1DSP_TEST(func) { #func, offsetof(VC1DSPContext, func) },
34 #define VC1DSP_SIZED_TEST(func, width, height) { #func, offsetof(VC1DSPContext, func), width, height },
35 
36 typedef struct {
37  const char *name;
38  size_t offset;
39  int width;
40  int height;
41 } test;
42 
43 typedef struct matrix {
44  size_t width;
45  size_t height;
46  float d[];
47 } matrix;
48 
49 static const matrix T8 = { 8, 8, {
50  12, 12, 12, 12, 12, 12, 12, 12,
51  16, 15, 9, 4, -4, -9, -15, -16,
52  16, 6, -6, -16, -16, -6, 6, 16,
53  15, -4, -16, -9, 9, 16, 4, -15,
54  12, -12, -12, 12, 12, -12, -12, 12,
55  9, -16, 4, 15, -15, -4, 16, -9,
56  6, -16, 16, -6, -6, 16, -16, 6,
57  4, -9, 15, -16, 16, -15, 9, -4
58 } };
59 
60 static const matrix T4 = { 4, 4, {
61  17, 17, 17, 17,
62  22, 10, -10, -22,
63  17, -17, -17, 17,
64  10, -22, 22, -10
65 } };
66 
67 static const matrix T8t = { 8, 8, {
68  12, 16, 16, 15, 12, 9, 6, 4,
69  12, 15, 6, -4, -12, -16, -16, -9,
70  12, 9, -6, -16, -12, 4, 16, 15,
71  12, 4, -16, -9, 12, 15, -6, -16,
72  12, -4, -16, 9, 12, -15, -6, 16,
73  12, -9, -6, 16, -12, -4, 16, -15,
74  12, -15, 6, 4, -12, 16, -16, 9,
75  12, -16, 16, -15, 12, -9, 6, -4
76 } };
77 
78 static const matrix T4t = { 4, 4, {
79  17, 22, 17, 10,
80  17, 10, -17, -22,
81  17, -10, -17, 22,
82  17, -22, 17, -10
83 } };
84 
85 static matrix *new_matrix(size_t width, size_t height)
86 {
87  matrix *out = av_mallocz(sizeof (matrix) + height * width * sizeof (float));
88  if (out == NULL) {
89  fprintf(stderr, "Memory allocation failure\n");
90  exit(EXIT_FAILURE);
91  }
92  out->width = width;
93  out->height = height;
94  return out;
95 }
96 
97 static matrix *multiply(const matrix *a, const matrix *b)
98 {
99  matrix *out;
100  if (a->width != b->height) {
101  fprintf(stderr, "Incompatible multiplication\n");
102  exit(EXIT_FAILURE);
103  }
104  out = new_matrix(b->width, a->height);
105  for (int j = 0; j < out->height; ++j)
106  for (int i = 0; i < out->width; ++i) {
107  float sum = 0;
108  for (int k = 0; k < a->width; ++k)
109  sum += a->d[j * a->width + k] * b->d[k * b->width + i];
110  out->d[j * out->width + i] = sum;
111  }
112  return out;
113 }
114 
115 static void normalise(matrix *a)
116 {
117  for (int j = 0; j < a->height; ++j)
118  for (int i = 0; i < a->width; ++i) {
119  float *p = a->d + j * a->width + i;
120  *p *= 64;
121  if (a->height == 4)
122  *p /= (const unsigned[]) { 289, 292, 289, 292 } [j];
123  else
124  *p /= (const unsigned[]) { 288, 289, 292, 289, 288, 289, 292, 289 } [j];
125  if (a->width == 4)
126  *p /= (const unsigned[]) { 289, 292, 289, 292 } [i];
127  else
128  *p /= (const unsigned[]) { 288, 289, 292, 289, 288, 289, 292, 289 } [i];
129  }
130 }
131 
132 static void divide_and_round_nearest(matrix *a, float by)
133 {
134  for (int j = 0; j < a->height; ++j)
135  for (int i = 0; i < a->width; ++i) {
136  float *p = a->d + j * a->width + i;
137  *p = rintf(*p / by);
138  }
139 }
140 
141 static void tweak(matrix *a)
142 {
143  for (int j = 4; j < a->height; ++j)
144  for (int i = 0; i < a->width; ++i) {
145  float *p = a->d + j * a->width + i;
146  *p += 1;
147  }
148 }
149 
150 /* The VC-1 spec places restrictions on the values permitted at three
151  * different stages:
152  * - D: the input coefficients in frequency domain
153  * - E: the intermediate coefficients, inverse-transformed only horizontally
154  * - R: the fully inverse-transformed coefficients
155  *
156  * To fully cater for the ranges specified requires various intermediate
157  * values to be held to 17-bit precision; yet these conditions do not appear
158  * to be utilised in real-world streams. At least some assembly
159  * implementations have chosen to restrict these values to 16-bit precision,
160  * to accelerate the decoding of real-world streams at the cost of strict
161  * adherence to the spec. To avoid our test marking these as failures,
162  * reduce our random inputs.
163  */
164 #define ATTENUATION 4
165 
167 {
168  matrix *raw, *tmp, *D, *E, *R;
169  raw = new_matrix(width, height);
170  for (int i = 0; i < width * height; ++i)
171  raw->d[i] = (int) (rnd() % (1024/ATTENUATION)) - 512/ATTENUATION;
172  tmp = multiply(height == 8 ? &T8 : &T4, raw);
173  D = multiply(tmp, width == 8 ? &T8t : &T4t);
174  normalise(D);
176  for (int i = 0; i < width * height; ++i) {
177  if (D->d[i] < -2048/ATTENUATION || D->d[i] > 2048/ATTENUATION-1) {
178  /* Rare, so simply try again */
179  av_free(raw);
180  av_free(tmp);
181  av_free(D);
183  }
184  }
185  E = multiply(D, width == 8 ? &T8 : &T4);
187  for (int i = 0; i < width * height; ++i)
188  if (E->d[i] < -4096/ATTENUATION || E->d[i] > 4096/ATTENUATION-1) {
189  /* Rare, so simply try again */
190  av_free(raw);
191  av_free(tmp);
192  av_free(D);
193  av_free(E);
195  }
196  R = multiply(height == 8 ? &T8t : &T4t, E);
197  tweak(R);
199  for (int i = 0; i < width * height; ++i)
200  if (R->d[i] < -512/ATTENUATION || R->d[i] > 512/ATTENUATION-1) {
201  /* Rare, so simply try again */
202  av_free(raw);
203  av_free(tmp);
204  av_free(D);
205  av_free(E);
206  av_free(R);
208  }
209  av_free(raw);
210  av_free(tmp);
211  av_free(E);
212  av_free(R);
213  return D;
214 }
215 
216 #define RANDOMIZE_BUFFER16(name, size) \
217  do { \
218  int i; \
219  for (i = 0; i < size; ++i) { \
220  uint16_t r = rnd(); \
221  AV_WN16A(name##0 + i, r); \
222  AV_WN16A(name##1 + i, r); \
223  } \
224  } while (0)
225 
226 #define RANDOMIZE_BUFFER8(name, size) \
227  do { \
228  int i; \
229  for (i = 0; i < size; ++i) { \
230  uint8_t r = rnd(); \
231  name##0[i] = r; \
232  name##1[i] = r; \
233  } \
234  } while (0)
235 
236 #define RANDOMIZE_BUFFER8_MID_WEIGHTED(name, size) \
237  do { \
238  uint8_t *p##0 = name##0, *p##1 = name##1; \
239  int i = (size); \
240  while (i-- > 0) { \
241  int x = 0x80 | (rnd() & 0x7F); \
242  x >>= rnd() % 9; \
243  if (rnd() & 1) \
244  x = -x; \
245  *p##1++ = *p##0++ = 0x80 + x; \
246  } \
247  } while (0)
248 
249 static void check_inv_trans_inplace(void)
250 {
251  /* Inverse transform input coefficients are stored in a 16-bit buffer
252  * with row stride of 8 coefficients irrespective of transform size.
253  * vc1_inv_trans_8x8 differs from the others in two ways: coefficients
254  * are stored in column-major order, and the outputs are written back
255  * to the input buffer, so we oversize it slightly to catch overruns. */
256  LOCAL_ALIGNED_16(int16_t, inv_trans_in0, [10 * 8]);
257  LOCAL_ALIGNED_16(int16_t, inv_trans_in1, [10 * 8]);
258 
260 
261  ff_vc1dsp_init(&h);
262 
263  if (check_func(h.vc1_inv_trans_8x8, "vc1dsp.vc1_inv_trans_8x8")) {
264  matrix *coeffs;
265  declare_func(void, int16_t *);
266  RANDOMIZE_BUFFER16(inv_trans_in, 10 * 8);
268  for (int j = 0; j < 8; ++j)
269  for (int i = 0; i < 8; ++i) {
270  int idx = 8 + i * 8 + j;
271  inv_trans_in1[idx] = inv_trans_in0[idx] = coeffs->d[j * 8 + i];
272  }
273  call_ref(inv_trans_in0 + 8);
274  call_new(inv_trans_in1 + 8);
275  if (memcmp(inv_trans_in0, inv_trans_in1, 10 * 8 * sizeof (int16_t)))
276  fail();
277  bench_new(inv_trans_in1 + 8);
278  av_free(coeffs);
279  }
280 }
281 
282 static void check_inv_trans_adding(void)
283 {
284  /* Inverse transform input coefficients are stored in a 16-bit buffer
285  * with row stride of 8 coefficients irrespective of transform size. */
286  LOCAL_ALIGNED_16(int16_t, inv_trans_in0, [8 * 8]);
287  LOCAL_ALIGNED_16(int16_t, inv_trans_in1, [8 * 8]);
288 
289  /* For all but vc1_inv_trans_8x8, the inverse transform is narrowed and
290  * added with saturation to an array of unsigned 8-bit values. Oversize
291  * this by 8 samples left and right and one row above and below. */
292  LOCAL_ALIGNED_8(uint8_t, inv_trans_out0, [10 * 24]);
293  LOCAL_ALIGNED_8(uint8_t, inv_trans_out1, [10 * 24]);
294 
296 
297  const test tests[] = {
298  VC1DSP_SIZED_TEST(vc1_inv_trans_8x4, 8, 4)
299  VC1DSP_SIZED_TEST(vc1_inv_trans_4x8, 4, 8)
300  VC1DSP_SIZED_TEST(vc1_inv_trans_4x4, 4, 4)
301  VC1DSP_SIZED_TEST(vc1_inv_trans_8x8_dc, 8, 8)
302  VC1DSP_SIZED_TEST(vc1_inv_trans_8x4_dc, 8, 4)
303  VC1DSP_SIZED_TEST(vc1_inv_trans_4x8_dc, 4, 8)
304  VC1DSP_SIZED_TEST(vc1_inv_trans_4x4_dc, 4, 4)
305  };
306 
307  ff_vc1dsp_init(&h);
308 
309  for (size_t t = 0; t < FF_ARRAY_ELEMS(tests); ++t) {
310  void (*func)(uint8_t *, ptrdiff_t, int16_t *) = *(void **)((intptr_t) &h + tests[t].offset);
311  if (check_func(func, "vc1dsp.%s", tests[t].name)) {
312  matrix *coeffs;
313  declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *, ptrdiff_t, int16_t *);
314  RANDOMIZE_BUFFER16(inv_trans_in, 8 * 8);
315  RANDOMIZE_BUFFER8(inv_trans_out, 10 * 24);
317  for (int j = 0; j < tests[t].height; ++j)
318  for (int i = 0; i < tests[t].width; ++i) {
319  int idx = j * 8 + i;
320  inv_trans_in1[idx] = inv_trans_in0[idx] = coeffs->d[j * tests[t].width + i];
321  }
322  call_ref(inv_trans_out0 + 24 + 8, 24, inv_trans_in0);
323  call_new(inv_trans_out1 + 24 + 8, 24, inv_trans_in1);
324  if (memcmp(inv_trans_out0, inv_trans_out1, 10 * 24))
325  fail();
326  bench_new(inv_trans_out1 + 24 + 8, 24, inv_trans_in1 + 8);
327  av_free(coeffs);
328  }
329  }
330 }
331 
332 static void check_loop_filter(void)
333 {
334  /* Deblocking filter buffers are big enough to hold a 16x16 block,
335  * plus 16 columns left and 4 rows above to hold filter inputs
336  * (depending on whether v or h neighbouring block edge, oversized
337  * horizontally to maintain 16-byte alignment) plus 16 columns and
338  * 4 rows below to catch write overflows */
339  LOCAL_ALIGNED_16(uint8_t, filter_buf0, [24 * 48]);
340  LOCAL_ALIGNED_16(uint8_t, filter_buf1, [24 * 48]);
341 
343 
344  const test tests[] = {
345  VC1DSP_TEST(vc1_v_loop_filter4)
346  VC1DSP_TEST(vc1_h_loop_filter4)
347  VC1DSP_TEST(vc1_v_loop_filter8)
348  VC1DSP_TEST(vc1_h_loop_filter8)
349  VC1DSP_TEST(vc1_v_loop_filter16)
350  VC1DSP_TEST(vc1_h_loop_filter16)
351  };
352 
353  ff_vc1dsp_init(&h);
354 
355  for (size_t t = 0; t < FF_ARRAY_ELEMS(tests); ++t) {
356  void (*func)(uint8_t *, ptrdiff_t, int) = *(void **)((intptr_t) &h + tests[t].offset);
357  declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *, ptrdiff_t, int);
358  if (check_func(func, "vc1dsp.%s", tests[t].name)) {
359  for (int count = 1000; count > 0; --count) {
360  int pq = rnd() % 31 + 1;
361  RANDOMIZE_BUFFER8_MID_WEIGHTED(filter_buf, 24 * 48);
362  call_ref(filter_buf0 + 4 * 48 + 16, 48, pq);
363  call_new(filter_buf1 + 4 * 48 + 16, 48, pq);
364  if (memcmp(filter_buf0, filter_buf1, 24 * 48))
365  fail();
366  }
367  }
368  for (int j = 0; j < 24; ++j)
369  for (int i = 0; i < 48; ++i)
370  filter_buf1[j * 48 + i] = 0x60 + 0x40 * (i >= 16 && j >= 4);
371  if (check_func(func, "vc1dsp.%s_bestcase", tests[t].name))
372  bench_new(filter_buf1 + 4 * 48 + 16, 48, 1);
373  if (check_func(func, "vc1dsp.%s_worstcase", tests[t].name))
374  bench_new(filter_buf1 + 4 * 48 + 16, 48, 31);
375  }
376 }
377 
378 #define TEST_UNESCAPE \
379  do { \
380  for (int count = 100; count > 0; --count) { \
381  escaped_offset = rnd() & 7; \
382  unescaped_offset = rnd() & 7; \
383  escaped_len = (1u << (rnd() % 8) + 3) - (rnd() & 7); \
384  RANDOMIZE_BUFFER8(unescaped, UNESCAPE_BUF_SIZE); \
385  len0 = call_ref(escaped0 + escaped_offset, escaped_len, unescaped0 + unescaped_offset); \
386  len1 = call_new(escaped1 + escaped_offset, escaped_len, unescaped1 + unescaped_offset); \
387  if (len0 != len1 || memcmp(unescaped0, unescaped1, UNESCAPE_BUF_SIZE)) \
388  fail(); \
389  } \
390  } while (0)
391 
392 static void check_unescape(void)
393 {
394  /* This appears to be a typical length of buffer in use */
395 #define LOG2_UNESCAPE_BUF_SIZE 17
396 #define UNESCAPE_BUF_SIZE (1u<<LOG2_UNESCAPE_BUF_SIZE)
397  LOCAL_ALIGNED_8(uint8_t, escaped0, [UNESCAPE_BUF_SIZE]);
398  LOCAL_ALIGNED_8(uint8_t, escaped1, [UNESCAPE_BUF_SIZE]);
399  LOCAL_ALIGNED_8(uint8_t, unescaped0, [UNESCAPE_BUF_SIZE]);
400  LOCAL_ALIGNED_8(uint8_t, unescaped1, [UNESCAPE_BUF_SIZE]);
401 
403 
404  ff_vc1dsp_init(&h);
405 
406  if (check_func(h.vc1_unescape_buffer, "vc1dsp.vc1_unescape_buffer")) {
407  int len0, len1, escaped_offset, unescaped_offset, escaped_len;
408  declare_func(int, const uint8_t *, int, uint8_t *);
409 
410  /* Test data which consists of escapes sequences packed as tightly as possible */
411  for (int x = 0; x < UNESCAPE_BUF_SIZE; ++x)
412  escaped1[x] = escaped0[x] = 3 * (x % 3 == 0);
414 
415  /* Test random data */
418 
419  /* Test data with escape sequences at random intervals */
420  for (int x = 0; x <= UNESCAPE_BUF_SIZE - 4;) {
421  int gap, gap_msb;
422  escaped1[x+0] = escaped0[x+0] = 0;
423  escaped1[x+1] = escaped0[x+1] = 0;
424  escaped1[x+2] = escaped0[x+2] = 3;
425  escaped1[x+3] = escaped0[x+3] = rnd() & 3;
426  gap_msb = 2u << (rnd() % 8);
427  gap = (rnd() &~ -gap_msb) | gap_msb;
428  x += gap;
429  }
431 
432  /* Test data which is known to contain no escape sequences */
433  memset(escaped0, 0xFF, UNESCAPE_BUF_SIZE);
434  memset(escaped1, 0xFF, UNESCAPE_BUF_SIZE);
436 
437  /* Benchmark the no-escape-sequences case */
438  bench_new(escaped1, UNESCAPE_BUF_SIZE, unescaped1);
439  }
440 }
441 
443 {
446  report("inv_trans");
447 
449  report("loop_filter");
450 
451  check_unescape();
452  report("unescape_buffer");
453 }
T8
static const matrix T8
Definition: vc1dsp.c:49
RANDOMIZE_BUFFER16
#define RANDOMIZE_BUFFER16(name, size)
Definition: vc1dsp.c:216
func
int(* func)(AVBPrint *dst, const char *in, const char *arg)
Definition: jacosubdec.c:68
declare_func_emms
#define declare_func_emms(cpu_flags, ret,...)
Definition: checkasm.h:176
T8t
static const matrix T8t
Definition: vc1dsp.c:67
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
mem_internal.h
out
FILE * out
Definition: movenc.c:55
T4
static const matrix T4
Definition: vc1dsp.c:60
u
#define u(width, name, range_min, range_max)
Definition: cbs_h2645.c:251
vc1dsp.h
matrix
Definition: vc1dsp.c:43
ATTENUATION
#define ATTENUATION
Definition: vc1dsp.c:164
test::height
int height
Definition: vc1dsp.c:40
tmp
static uint8_t tmp[11]
Definition: aes_ctr.c:28
check_func
#define check_func(func,...)
Definition: checkasm.h:170
b
#define b
Definition: input.c:41
R
#define R
Definition: huffyuv.h:44
test
Definition: idctdsp.c:35
check_loop_filter
static void check_loop_filter(void)
Definition: vc1dsp.c:332
divide_and_round_nearest
static void divide_and_round_nearest(matrix *a, float by)
Definition: vc1dsp.c:132
call_ref
#define call_ref(...)
Definition: checkasm.h:185
D
D(D(float, sse)
Definition: rematrix_init.c:30
T4t
static const matrix T4t
Definition: vc1dsp.c:78
fail
#define fail()
Definition: checkasm.h:179
checkasm.h
rnd
#define rnd()
Definition: checkasm.h:163
tweak
static void tweak(matrix *a)
Definition: vc1dsp.c:141
FF_ARRAY_ELEMS
#define FF_ARRAY_ELEMS(a)
Definition: sinewin_tablegen.c:29
generate_inverse_quantized_transform_coefficients
static matrix * generate_inverse_quantized_transform_coefficients(size_t width, size_t height)
Definition: vc1dsp.c:166
width
#define width
intreadwrite.h
matrix::width
size_t width
Definition: vc1dsp.c:44
LOCAL_ALIGNED_16
#define LOCAL_ALIGNED_16(t, v,...)
Definition: mem_internal.h:150
E
#define E
Definition: avdct.c:33
matrix::height
size_t height
Definition: vc1dsp.c:45
LOCAL_ALIGNED_8
#define LOCAL_ALIGNED_8(t, v,...)
Definition: mem_internal.h:144
call_new
#define call_new(...)
Definition: checkasm.h:288
NULL
#define NULL
Definition: coverity.c:32
TEST_UNESCAPE
#define TEST_UNESCAPE
Definition: vc1dsp.c:378
check_unescape
static void check_unescape(void)
Definition: vc1dsp.c:392
ff_vc1dsp_init
av_cold void ff_vc1dsp_init(VC1DSPContext *dsp)
Definition: vc1dsp.c:974
test::width
int width
Definition: vc1dsp.c:39
UNESCAPE_BUF_SIZE
#define UNESCAPE_BUF_SIZE
height
#define height
a
The reader does not expect b to be semantically here and if the code is changed by maybe adding a a division or other the signedness will almost certainly be mistaken To avoid this confusion a new type was SUINT is the C unsigned type but it holds a signed int to use the same example SUINT a
Definition: undefined.txt:41
matrix::d
float d[]
Definition: vc1dsp.c:46
offset
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
Definition: writing_filters.txt:86
RANDOMIZE_BUFFER8_MID_WEIGHTED
#define RANDOMIZE_BUFFER8_MID_WEIGHTED(name, size)
Definition: vc1dsp.c:236
new_matrix
static matrix * new_matrix(size_t width, size_t height)
Definition: vc1dsp.c:85
tests
const TestCase tests[]
Definition: fifo_muxer.c:367
report
#define report
Definition: checkasm.h:182
VC1DSP_SIZED_TEST
#define VC1DSP_SIZED_TEST(func, width, height)
Definition: vc1dsp.c:34
VC1DSP_TEST
#define VC1DSP_TEST(func)
Definition: vc1dsp.c:33
bench_new
#define bench_new(...)
Definition: checkasm.h:358
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:256
internal.h
common.h
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:256
VC1DSPContext
Definition: vc1dsp.h:35
AV_CPU_FLAG_MMX
#define AV_CPU_FLAG_MMX
standard MMX
Definition: cpu.h:29
check_inv_trans_inplace
static void check_inv_trans_inplace(void)
Definition: vc1dsp.c:249
check_inv_trans_adding
static void check_inv_trans_adding(void)
Definition: vc1dsp.c:282
multiply
static matrix * multiply(const matrix *a, const matrix *b)
Definition: vc1dsp.c:97
test
static void test(const char *pattern, const char *host)
Definition: noproxy.c:23
mem.h
RANDOMIZE_BUFFER8
#define RANDOMIZE_BUFFER8(name, size)
Definition: vc1dsp.c:226
declare_func
#define declare_func(ret,...)
Definition: checkasm.h:174
av_free
#define av_free(p)
Definition: tableprint_vlc.h:33
checkasm_check_vc1dsp
void checkasm_check_vc1dsp(void)
Definition: vc1dsp.c:442
normalise
static void normalise(matrix *a)
Definition: vc1dsp.c:115
h
h
Definition: vp9dsp_template.c:2038
int
int
Definition: ffmpeg_filter.c:424