]> git.sesse.net Git - ffmpeg/blob - libavcodec/dct-test.c
avcodec/mpeg12dec: fix support for interlaced mpeg2 with missing last slice
[ffmpeg] / libavcodec / dct-test.c
1 /*
2  * (c) 2001 Fabrice Bellard
3  *     2007 Marc Hoffman <marc.hoffman@analog.com>
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21
22 /**
23  * @file
24  * DCT test (c) 2001 Fabrice Bellard
25  * Started from sample code by Juan J. Sierralta P.
26  */
27
28 #include "config.h"
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #if HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 #include <math.h>
36
37 #include "libavutil/cpu.h"
38 #include "libavutil/common.h"
39 #include "libavutil/lfg.h"
40 #include "libavutil/time.h"
41
42 #include "dct.h"
43 #include "idctdsp.h"
44 #include "simple_idct.h"
45 #include "aandcttab.h"
46 #include "faandct.h"
47 #include "faanidct.h"
48 #include "dctref.h"
49
50 struct algo {
51     const char *name;
52     void (*func)(int16_t *block);
53     enum idct_permutation_type perm_type;
54     int cpu_flag;
55     int nonspec;
56 };
57
58 static const struct algo fdct_tab[] = {
59     { "REF-DBL",     ff_ref_fdct,          FF_IDCT_PERM_NONE },
60     { "FAAN",        ff_faandct,           FF_IDCT_PERM_NONE },
61     { "IJG-AAN-INT", ff_fdct_ifast,        FF_IDCT_PERM_NONE },
62     { "IJG-LLM-INT", ff_jpeg_fdct_islow_8, FF_IDCT_PERM_NONE },
63 };
64
65 static void ff_prores_idct_wrap(int16_t *dst){
66     DECLARE_ALIGNED(16, static int16_t, qmat)[64];
67     int i;
68
69     for(i=0; i<64; i++){
70         qmat[i]=4;
71     }
72     ff_prores_idct(dst, qmat);
73     for(i=0; i<64; i++) {
74          dst[i] -= 512;
75     }
76 }
77
78 static const struct algo idct_tab[] = {
79     { "FAANI",       ff_faanidct,          FF_IDCT_PERM_NONE },
80     { "REF-DBL",     ff_ref_idct,          FF_IDCT_PERM_NONE },
81     { "INT",         ff_j_rev_dct,         FF_IDCT_PERM_LIBMPEG2 },
82     { "SIMPLE-C",    ff_simple_idct_8,     FF_IDCT_PERM_NONE },
83     { "PR-C",        ff_prores_idct_wrap,  FF_IDCT_PERM_NONE, 0, 1 },
84 };
85
86 #if ARCH_ARM
87 #include "arm/dct-test.c"
88 #elif ARCH_PPC
89 #include "ppc/dct-test.c"
90 #elif ARCH_X86
91 #include "x86/dct-test.c"
92 #else
93 static const struct algo fdct_tab_arch[] = { 0 };
94 static const struct algo idct_tab_arch[] = { 0 };
95 #endif
96
97 #define AANSCALE_BITS 12
98
99 #define NB_ITS 20000
100 #define NB_ITS_SPEED 50000
101
102 DECLARE_ALIGNED(16, static int16_t, block)[64];
103 DECLARE_ALIGNED(8,  static int16_t, block1)[64];
104
105 static void init_block(int16_t block[64], int test, int is_idct, AVLFG *prng, int vals)
106 {
107     int i, j;
108
109     memset(block, 0, 64 * sizeof(*block));
110
111     switch (test) {
112     case 0:
113         for (i = 0; i < 64; i++)
114             block[i] = (av_lfg_get(prng) % (2*vals)) -vals;
115         if (is_idct) {
116             ff_ref_fdct(block);
117             for (i = 0; i < 64; i++)
118                 block[i] >>= 3;
119         }
120         break;
121     case 1:
122         j = av_lfg_get(prng) % 10 + 1;
123         for (i = 0; i < j; i++) {
124             int idx = av_lfg_get(prng) % 64;
125             block[idx] = av_lfg_get(prng) % (2*vals) -vals;
126         }
127         break;
128     case 2:
129         block[ 0] = av_lfg_get(prng) % (16*vals) - (8*vals);
130         block[63] = (block[0] & 1) ^ 1;
131         break;
132     }
133 }
134
135 static void permute(int16_t dst[64], const int16_t src[64],
136                     enum idct_permutation_type perm_type)
137 {
138     int i;
139
140 #if ARCH_X86
141     if (permute_x86(dst, src, perm_type))
142         return;
143 #endif
144
145     switch (perm_type) {
146     case FF_IDCT_PERM_LIBMPEG2:
147         for (i = 0; i < 64; i++)
148             dst[(i & 0x38) | ((i & 6) >> 1) | ((i & 1) << 2)] = src[i];
149         break;
150     case FF_IDCT_PERM_PARTTRANS:
151         for (i = 0; i < 64; i++)
152             dst[(i & 0x24) | ((i & 3) << 3) | ((i >> 3) & 3)] = src[i];
153         break;
154     case FF_IDCT_PERM_TRANSPOSE:
155         for (i = 0; i < 64; i++)
156             dst[(i>>3) | ((i<<3)&0x38)] = src[i];
157         break;
158     default:
159         for (i = 0; i < 64; i++)
160             dst[i] = src[i];
161         break;
162     }
163 }
164
165 static int dct_error(const struct algo *dct, int test, int is_idct, int speed, const int bits)
166 {
167     void (*ref)(int16_t *block) = is_idct ? ff_ref_idct : ff_ref_fdct;
168     int it, i, scale;
169     int err_inf, v;
170     int64_t err2, ti, ti1, it1, err_sum = 0;
171     int64_t sysErr[64], sysErrMax = 0;
172     int maxout = 0;
173     int blockSumErrMax = 0, blockSumErr;
174     AVLFG prng;
175     const int vals=1<<bits;
176     double omse, ome;
177     int spec_err;
178
179     av_lfg_init(&prng, 1);
180
181     err_inf = 0;
182     err2 = 0;
183     for (i = 0; i < 64; i++)
184         sysErr[i] = 0;
185     for (it = 0; it < NB_ITS; it++) {
186         init_block(block1, test, is_idct, &prng, vals);
187         permute(block, block1, dct->perm_type);
188
189         dct->func(block);
190         emms_c();
191
192         if (!strcmp(dct->name, "IJG-AAN-INT")) {
193             for (i = 0; i < 64; i++) {
194                 scale = 8 * (1 << (AANSCALE_BITS + 11)) / ff_aanscales[i];
195                 block[i] = (block[i] * scale) >> AANSCALE_BITS;
196             }
197         }
198
199         ref(block1);
200         if (!strcmp(dct->name, "PR-SSE2"))
201             for (i = 0; i < 64; i++)
202                 block1[i] = av_clip(block1[i], 4-512, 1019-512);
203
204         blockSumErr = 0;
205         for (i = 0; i < 64; i++) {
206             int err = block[i] - block1[i];
207             err_sum += err;
208             v = abs(err);
209             if (v > err_inf)
210                 err_inf = v;
211             err2 += v * v;
212             sysErr[i] += block[i] - block1[i];
213             blockSumErr += v;
214             if (abs(block[i]) > maxout)
215                 maxout = abs(block[i]);
216         }
217         if (blockSumErrMax < blockSumErr)
218             blockSumErrMax = blockSumErr;
219     }
220     for (i = 0; i < 64; i++)
221         sysErrMax = FFMAX(sysErrMax, FFABS(sysErr[i]));
222
223     for (i = 0; i < 64; i++) {
224         if (i % 8 == 0)
225             printf("\n");
226         printf("%7d ", (int) sysErr[i]);
227     }
228     printf("\n");
229
230     omse = (double) err2 / NB_ITS / 64;
231     ome  = (double) err_sum / NB_ITS / 64;
232
233     spec_err = is_idct && (err_inf > 1 || omse > 0.02 || fabs(ome) > 0.0015);
234
235     printf("%s %s: max_err=%d omse=%0.8f ome=%0.8f syserr=%0.8f maxout=%d blockSumErr=%d\n",
236            is_idct ? "IDCT" : "DCT", dct->name, err_inf,
237            omse, ome, (double) sysErrMax / NB_ITS,
238            maxout, blockSumErrMax);
239
240     if (spec_err && !dct->nonspec)
241         return 1;
242
243     if (!speed)
244         return 0;
245
246     /* speed test */
247
248     init_block(block, test, is_idct, &prng, vals);
249     permute(block1, block, dct->perm_type);
250
251     ti = av_gettime_relative();
252     it1 = 0;
253     do {
254         for (it = 0; it < NB_ITS_SPEED; it++) {
255             memcpy(block, block1, sizeof(block));
256             dct->func(block);
257         }
258         emms_c();
259         it1 += NB_ITS_SPEED;
260         ti1 = av_gettime_relative() - ti;
261     } while (ti1 < 1000000);
262
263     printf("%s %s: %0.1f kdct/s\n", is_idct ? "IDCT" : "DCT", dct->name,
264            (double) it1 * 1000.0 / (double) ti1);
265
266     return 0;
267 }
268
269 DECLARE_ALIGNED(8, static uint8_t, img_dest)[64];
270 DECLARE_ALIGNED(8, static uint8_t, img_dest1)[64];
271
272 static void idct248_ref(uint8_t *dest, int linesize, int16_t *block)
273 {
274     static int init;
275     static double c8[8][8];
276     static double c4[4][4];
277     double block1[64], block2[64], block3[64];
278     double s, sum, v;
279     int i, j, k;
280
281     if (!init) {
282         init = 1;
283
284         for (i = 0; i < 8; i++) {
285             sum = 0;
286             for (j = 0; j < 8; j++) {
287                 s = (i == 0) ? sqrt(1.0 / 8.0) : sqrt(1.0 / 4.0);
288                 c8[i][j] = s * cos(M_PI * i * (j + 0.5) / 8.0);
289                 sum += c8[i][j] * c8[i][j];
290             }
291         }
292
293         for (i = 0; i < 4; i++) {
294             sum = 0;
295             for (j = 0; j < 4; j++) {
296                 s = (i == 0) ? sqrt(1.0 / 4.0) : sqrt(1.0 / 2.0);
297                 c4[i][j] = s * cos(M_PI * i * (j + 0.5) / 4.0);
298                 sum += c4[i][j] * c4[i][j];
299             }
300         }
301     }
302
303     /* butterfly */
304     s = 0.5 * sqrt(2.0);
305     for (i = 0; i < 4; i++) {
306         for (j = 0; j < 8; j++) {
307             block1[8 * (2 * i) + j] =
308                 (block[8 * (2 * i) + j] + block[8 * (2 * i + 1) + j]) * s;
309             block1[8 * (2 * i + 1) + j] =
310                 (block[8 * (2 * i) + j] - block[8 * (2 * i + 1) + j]) * s;
311         }
312     }
313
314     /* idct8 on lines */
315     for (i = 0; i < 8; i++) {
316         for (j = 0; j < 8; j++) {
317             sum = 0;
318             for (k = 0; k < 8; k++)
319                 sum += c8[k][j] * block1[8 * i + k];
320             block2[8 * i + j] = sum;
321         }
322     }
323
324     /* idct4 */
325     for (i = 0; i < 8; i++) {
326         for (j = 0; j < 4; j++) {
327             /* top */
328             sum = 0;
329             for (k = 0; k < 4; k++)
330                 sum += c4[k][j] * block2[8 * (2 * k) + i];
331             block3[8 * (2 * j) + i] = sum;
332
333             /* bottom */
334             sum = 0;
335             for (k = 0; k < 4; k++)
336                 sum += c4[k][j] * block2[8 * (2 * k + 1) + i];
337             block3[8 * (2 * j + 1) + i] = sum;
338         }
339     }
340
341     /* clamp and store the result */
342     for (i = 0; i < 8; i++) {
343         for (j = 0; j < 8; j++) {
344             v = block3[8 * i + j];
345             if      (v < 0)   v = 0;
346             else if (v > 255) v = 255;
347             dest[i * linesize + j] = (int) rint(v);
348         }
349     }
350 }
351
352 static void idct248_error(const char *name,
353                           void (*idct248_put)(uint8_t *dest, int line_size,
354                                               int16_t *block),
355                           int speed)
356 {
357     int it, i, it1, ti, ti1, err_max, v;
358     AVLFG prng;
359
360     av_lfg_init(&prng, 1);
361
362     /* just one test to see if code is correct (precision is less
363        important here) */
364     err_max = 0;
365     for (it = 0; it < NB_ITS; it++) {
366         /* XXX: use forward transform to generate values */
367         for (i = 0; i < 64; i++)
368             block1[i] = av_lfg_get(&prng) % 256 - 128;
369         block1[0] += 1024;
370
371         for (i = 0; i < 64; i++)
372             block[i] = block1[i];
373         idct248_ref(img_dest1, 8, block);
374
375         for (i = 0; i < 64; i++)
376             block[i] = block1[i];
377         idct248_put(img_dest, 8, block);
378
379         for (i = 0; i < 64; i++) {
380             v = abs((int) img_dest[i] - (int) img_dest1[i]);
381             if (v == 255)
382                 printf("%d %d\n", img_dest[i], img_dest1[i]);
383             if (v > err_max)
384                 err_max = v;
385         }
386 #if 0
387         printf("ref=\n");
388         for(i=0;i<8;i++) {
389             int j;
390             for(j=0;j<8;j++) {
391                 printf(" %3d", img_dest1[i*8+j]);
392             }
393             printf("\n");
394         }
395
396         printf("out=\n");
397         for(i=0;i<8;i++) {
398             int j;
399             for(j=0;j<8;j++) {
400                 printf(" %3d", img_dest[i*8+j]);
401             }
402             printf("\n");
403         }
404 #endif
405     }
406     printf("%s %s: err_inf=%d\n", 1 ? "IDCT248" : "DCT248", name, err_max);
407
408     if (!speed)
409         return;
410
411     ti = av_gettime_relative();
412     it1 = 0;
413     do {
414         for (it = 0; it < NB_ITS_SPEED; it++) {
415             for (i = 0; i < 64; i++)
416                 block[i] = block1[i];
417             idct248_put(img_dest, 8, block);
418         }
419         emms_c();
420         it1 += NB_ITS_SPEED;
421         ti1 = av_gettime_relative() - ti;
422     } while (ti1 < 1000000);
423
424     printf("%s %s: %0.1f kdct/s\n", 1 ? "IDCT248" : "DCT248", name,
425            (double) it1 * 1000.0 / (double) ti1);
426 }
427
428 static void help(void)
429 {
430     printf("dct-test [-i] [<test-number>] [<bits>]\n"
431            "test-number 0 -> test with random matrixes\n"
432            "            1 -> test with random sparse matrixes\n"
433            "            2 -> do 3. test from mpeg4 std\n"
434            "bits        Number of time domain bits to use, 8 is default\n"
435            "-i          test IDCT implementations\n"
436            "-4          test IDCT248 implementations\n"
437            "-t          speed test\n");
438 }
439
440 #if !HAVE_GETOPT
441 #include "compat/getopt.c"
442 #endif
443
444 int main(int argc, char **argv)
445 {
446     int test_idct = 0, test_248_dct = 0;
447     int c, i;
448     int test = 1;
449     int speed = 0;
450     int err = 0;
451     int bits=8;
452
453     ff_ref_dct_init();
454
455     for (;;) {
456         c = getopt(argc, argv, "ih4t");
457         if (c == -1)
458             break;
459         switch (c) {
460         case 'i':
461             test_idct = 1;
462             break;
463         case '4':
464             test_248_dct = 1;
465             break;
466         case 't':
467             speed = 1;
468             break;
469         default:
470         case 'h':
471             help();
472             return 0;
473         }
474     }
475
476     if (optind < argc)
477         test = atoi(argv[optind]);
478     if(optind+1 < argc) bits= atoi(argv[optind+1]);
479
480     printf("ffmpeg DCT/IDCT test\n");
481
482     if (test_248_dct) {
483         idct248_error("SIMPLE-C", ff_simple_idct248_put, speed);
484     } else {
485         const int cpu_flags = av_get_cpu_flags();
486         if (test_idct) {
487             for (i = 0; i < FF_ARRAY_ELEMS(idct_tab); i++)
488                 err |= dct_error(&idct_tab[i], test, test_idct, speed, bits);
489
490             for (i = 0; idct_tab_arch[i].name; i++)
491                 if (!(~cpu_flags & idct_tab_arch[i].cpu_flag))
492                     err |= dct_error(&idct_tab_arch[i], test, test_idct, speed, bits);
493         }
494 #if CONFIG_FDCTDSP
495         else {
496             for (i = 0; i < FF_ARRAY_ELEMS(fdct_tab); i++)
497                 err |= dct_error(&fdct_tab[i], test, test_idct, speed, bits);
498
499             for (i = 0; fdct_tab_arch[i].name; i++)
500                 if (!(~cpu_flags & fdct_tab_arch[i].cpu_flag))
501                     err |= dct_error(&fdct_tab_arch[i], test, test_idct, speed, bits);
502         }
503 #endif /* CONFIG_FDCTDSP */
504     }
505
506     if (err)
507         printf("Error: %d.\n", err);
508
509     return !!err;
510 }