Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6148 serge 1
/*
2
 * (c) 2002 Fabrice Bellard
3
 *
4
 * This file is part of FFmpeg.
5
 *
6
 * FFmpeg is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (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 GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
 
21
/**
22
 * @file
23
 * FFT and MDCT tests.
24
 */
25
 
26
#include "libavutil/cpu.h"
27
#include "libavutil/mathematics.h"
28
#include "libavutil/lfg.h"
29
#include "libavutil/log.h"
30
#include "libavutil/time.h"
31
#include "fft.h"
32
#if CONFIG_FFT_FLOAT
33
#include "dct.h"
34
#include "rdft.h"
35
#endif
36
#include 
37
#if HAVE_UNISTD_H
38
#include 
39
#endif
40
#include 
41
#include 
42
#include 
43
 
44
/* reference fft */
45
 
46
#define MUL16(a,b) ((a) * (b))
47
 
48
#define CMAC(pre, pim, are, aim, bre, bim) \
49
{\
50
   pre += (MUL16(are, bre) - MUL16(aim, bim));\
51
   pim += (MUL16(are, bim) + MUL16(bre, aim));\
52
}
53
 
54
#if CONFIG_FFT_FLOAT
55
#   define RANGE 1.0
56
#   define REF_SCALE(x, bits)  (x)
57
#   define FMT "%10.6f"
58
#elif CONFIG_FFT_FIXED_32
59
#   define RANGE 8388608
60
#   define REF_SCALE(x, bits) (x)
61
#   define FMT "%6d"
62
#else
63
#   define RANGE 16384
64
#   define REF_SCALE(x, bits) ((x) / (1<<(bits)))
65
#   define FMT "%6d"
66
#endif
67
 
68
struct {
69
    float re, im;
70
} *exptab;
71
 
72
static void fft_ref_init(int nbits, int inverse)
73
{
74
    int n, i;
75
    double c1, s1, alpha;
76
 
77
    n = 1 << nbits;
78
    exptab = av_malloc((n / 2) * sizeof(*exptab));
79
 
80
    for (i = 0; i < (n/2); i++) {
81
        alpha = 2 * M_PI * (float)i / (float)n;
82
        c1 = cos(alpha);
83
        s1 = sin(alpha);
84
        if (!inverse)
85
            s1 = -s1;
86
        exptab[i].re = c1;
87
        exptab[i].im = s1;
88
    }
89
}
90
 
91
static void fft_ref(FFTComplex *tabr, FFTComplex *tab, int nbits)
92
{
93
    int n, i, j, k, n2;
94
    double tmp_re, tmp_im, s, c;
95
    FFTComplex *q;
96
 
97
    n = 1 << nbits;
98
    n2 = n >> 1;
99
    for (i = 0; i < n; i++) {
100
        tmp_re = 0;
101
        tmp_im = 0;
102
        q = tab;
103
        for (j = 0; j < n; j++) {
104
            k = (i * j) & (n - 1);
105
            if (k >= n2) {
106
                c = -exptab[k - n2].re;
107
                s = -exptab[k - n2].im;
108
            } else {
109
                c = exptab[k].re;
110
                s = exptab[k].im;
111
            }
112
            CMAC(tmp_re, tmp_im, c, s, q->re, q->im);
113
            q++;
114
        }
115
        tabr[i].re = REF_SCALE(tmp_re, nbits);
116
        tabr[i].im = REF_SCALE(tmp_im, nbits);
117
    }
118
}
119
 
120
static void imdct_ref(FFTSample *out, FFTSample *in, int nbits)
121
{
122
    int n = 1<
123
    int k, i, a;
124
    double sum, f;
125
 
126
    for (i = 0; i < n; i++) {
127
        sum = 0;
128
        for (k = 0; k < n/2; k++) {
129
            a = (2 * i + 1 + (n / 2)) * (2 * k + 1);
130
            f = cos(M_PI * a / (double)(2 * n));
131
            sum += f * in[k];
132
        }
133
        out[i] = REF_SCALE(-sum, nbits - 2);
134
    }
135
}
136
 
137
/* NOTE: no normalisation by 1 / N is done */
138
static void mdct_ref(FFTSample *output, FFTSample *input, int nbits)
139
{
140
    int n = 1<
141
    int k, i;
142
    double a, s;
143
 
144
    /* do it by hand */
145
    for (k = 0; k < n/2; k++) {
146
        s = 0;
147
        for (i = 0; i < n; i++) {
148
            a = (2*M_PI*(2*i+1+n/2)*(2*k+1) / (4 * n));
149
            s += input[i] * cos(a);
150
        }
151
        output[k] = REF_SCALE(s, nbits - 1);
152
    }
153
}
154
 
155
#if CONFIG_FFT_FLOAT
156
static void idct_ref(FFTSample *output, FFTSample *input, int nbits)
157
{
158
    int n = 1<
159
    int k, i;
160
    double a, s;
161
 
162
    /* do it by hand */
163
    for (i = 0; i < n; i++) {
164
        s = 0.5 * input[0];
165
        for (k = 1; k < n; k++) {
166
            a = M_PI*k*(i+0.5) / n;
167
            s += input[k] * cos(a);
168
        }
169
        output[i] = 2 * s / n;
170
    }
171
}
172
static void dct_ref(FFTSample *output, FFTSample *input, int nbits)
173
{
174
    int n = 1<
175
    int k, i;
176
    double a, s;
177
 
178
    /* do it by hand */
179
    for (k = 0; k < n; k++) {
180
        s = 0;
181
        for (i = 0; i < n; i++) {
182
            a = M_PI*k*(i+0.5) / n;
183
            s += input[i] * cos(a);
184
        }
185
        output[k] = s;
186
    }
187
}
188
#endif
189
 
190
 
191
static FFTSample frandom(AVLFG *prng)
192
{
193
    return (int16_t)av_lfg_get(prng) / 32768.0 * RANGE;
194
}
195
 
196
static int check_diff(FFTSample *tab1, FFTSample *tab2, int n, double scale)
197
{
198
    int i;
199
    double max= 0;
200
    double error= 0;
201
    int err = 0;
202
 
203
    for (i = 0; i < n; i++) {
204
        double e = fabsf(tab1[i] - (tab2[i] / scale)) / RANGE;
205
        if (e >= 1e-3) {
206
            av_log(NULL, AV_LOG_ERROR, "ERROR %5d: "FMT" "FMT"\n",
207
                   i, tab1[i], tab2[i]);
208
            err = 1;
209
        }
210
        error+= e*e;
211
        if(e>max) max= e;
212
    }
213
    av_log(NULL, AV_LOG_INFO, "max:%f e:%g\n", max, sqrt(error/n));
214
    return err;
215
}
216
 
217
 
218
static void help(void)
219
{
220
    av_log(NULL, AV_LOG_INFO,"usage: fft-test [-h] [-s] [-i] [-n b]\n"
221
           "-h     print this help\n"
222
           "-s     speed test\n"
223
           "-m     (I)MDCT test\n"
224
           "-d     (I)DCT test\n"
225
           "-r     (I)RDFT test\n"
226
           "-i     inverse transform test\n"
227
           "-n b   set the transform size to 2^b\n"
228
           "-f x   set scale factor for output data of (I)MDCT to x\n"
229
           );
230
}
231
 
232
enum tf_transform {
233
    TRANSFORM_FFT,
234
    TRANSFORM_MDCT,
235
    TRANSFORM_RDFT,
236
    TRANSFORM_DCT,
237
};
238
 
239
#if !HAVE_GETOPT
240
#include "compat/getopt.c"
241
#endif
242
 
243
int main(int argc, char **argv)
244
{
245
    FFTComplex *tab, *tab1, *tab_ref;
246
    FFTSample *tab2;
247
    int it, i, c;
248
    int cpuflags;
249
    int do_speed = 0;
250
    int err = 1;
251
    enum tf_transform transform = TRANSFORM_FFT;
252
    int do_inverse = 0;
253
    FFTContext s1, *s = &s1;
254
    FFTContext m1, *m = &m1;
255
#if CONFIG_FFT_FLOAT
256
    RDFTContext r1, *r = &r1;
257
    DCTContext d1, *d = &d1;
258
    int fft_size_2;
259
#endif
260
    int fft_nbits, fft_size;
261
    double scale = 1.0;
262
    AVLFG prng;
263
    av_lfg_init(&prng, 1);
264
 
265
    fft_nbits = 9;
266
    for(;;) {
267
        c = getopt(argc, argv, "hsimrdn:f:c:");
268
        if (c == -1)
269
            break;
270
        switch(c) {
271
        case 'h':
272
            help();
273
            return 1;
274
        case 's':
275
            do_speed = 1;
276
            break;
277
        case 'i':
278
            do_inverse = 1;
279
            break;
280
        case 'm':
281
            transform = TRANSFORM_MDCT;
282
            break;
283
        case 'r':
284
            transform = TRANSFORM_RDFT;
285
            break;
286
        case 'd':
287
            transform = TRANSFORM_DCT;
288
            break;
289
        case 'n':
290
            fft_nbits = atoi(optarg);
291
            break;
292
        case 'f':
293
            scale = atof(optarg);
294
            break;
295
        case 'c':
296
            cpuflags = av_get_cpu_flags();
297
 
298
            if (av_parse_cpu_caps(&cpuflags, optarg) < 0)
299
                return 1;
300
 
301
            av_force_cpu_flags(cpuflags);
302
            break;
303
        }
304
    }
305
 
306
    fft_size = 1 << fft_nbits;
307
    tab = av_malloc(fft_size * sizeof(FFTComplex));
308
    tab1 = av_malloc(fft_size * sizeof(FFTComplex));
309
    tab_ref = av_malloc(fft_size * sizeof(FFTComplex));
310
    tab2 = av_malloc(fft_size * sizeof(FFTSample));
311
 
312
    switch (transform) {
313
    case TRANSFORM_MDCT:
314
        av_log(NULL, AV_LOG_INFO,"Scale factor is set to %f\n", scale);
315
        if (do_inverse)
316
            av_log(NULL, AV_LOG_INFO,"IMDCT");
317
        else
318
            av_log(NULL, AV_LOG_INFO,"MDCT");
319
        ff_mdct_init(m, fft_nbits, do_inverse, scale);
320
        break;
321
    case TRANSFORM_FFT:
322
        if (do_inverse)
323
            av_log(NULL, AV_LOG_INFO,"IFFT");
324
        else
325
            av_log(NULL, AV_LOG_INFO,"FFT");
326
        ff_fft_init(s, fft_nbits, do_inverse);
327
        fft_ref_init(fft_nbits, do_inverse);
328
        break;
329
#if CONFIG_FFT_FLOAT
330
    case TRANSFORM_RDFT:
331
        if (do_inverse)
332
            av_log(NULL, AV_LOG_INFO,"IDFT_C2R");
333
        else
334
            av_log(NULL, AV_LOG_INFO,"DFT_R2C");
335
        ff_rdft_init(r, fft_nbits, do_inverse ? IDFT_C2R : DFT_R2C);
336
        fft_ref_init(fft_nbits, do_inverse);
337
        break;
338
#    if CONFIG_DCT
339
    case TRANSFORM_DCT:
340
        if (do_inverse)
341
            av_log(NULL, AV_LOG_INFO,"DCT_III");
342
        else
343
            av_log(NULL, AV_LOG_INFO,"DCT_II");
344
        ff_dct_init(d, fft_nbits, do_inverse ? DCT_III : DCT_II);
345
        break;
346
#    endif
347
#endif
348
    default:
349
        av_log(NULL, AV_LOG_ERROR, "Requested transform not supported\n");
350
        return 1;
351
    }
352
    av_log(NULL, AV_LOG_INFO," %d test\n", fft_size);
353
 
354
    /* generate random data */
355
 
356
    for (i = 0; i < fft_size; i++) {
357
        tab1[i].re = frandom(&prng);
358
        tab1[i].im = frandom(&prng);
359
    }
360
 
361
    /* checking result */
362
    av_log(NULL, AV_LOG_INFO,"Checking...\n");
363
 
364
    switch (transform) {
365
    case TRANSFORM_MDCT:
366
        if (do_inverse) {
367
            imdct_ref((FFTSample *)tab_ref, (FFTSample *)tab1, fft_nbits);
368
            m->imdct_calc(m, tab2, (FFTSample *)tab1);
369
            err = check_diff((FFTSample *)tab_ref, tab2, fft_size, scale);
370
        } else {
371
            mdct_ref((FFTSample *)tab_ref, (FFTSample *)tab1, fft_nbits);
372
 
373
            m->mdct_calc(m, tab2, (FFTSample *)tab1);
374
 
375
            err = check_diff((FFTSample *)tab_ref, tab2, fft_size / 2, scale);
376
        }
377
        break;
378
    case TRANSFORM_FFT:
379
        memcpy(tab, tab1, fft_size * sizeof(FFTComplex));
380
        s->fft_permute(s, tab);
381
        s->fft_calc(s, tab);
382
 
383
        fft_ref(tab_ref, tab1, fft_nbits);
384
        err = check_diff((FFTSample *)tab_ref, (FFTSample *)tab, fft_size * 2, 1.0);
385
        break;
386
#if CONFIG_FFT_FLOAT
387
    case TRANSFORM_RDFT:
388
        fft_size_2 = fft_size >> 1;
389
        if (do_inverse) {
390
            tab1[         0].im = 0;
391
            tab1[fft_size_2].im = 0;
392
            for (i = 1; i < fft_size_2; i++) {
393
                tab1[fft_size_2+i].re =  tab1[fft_size_2-i].re;
394
                tab1[fft_size_2+i].im = -tab1[fft_size_2-i].im;
395
            }
396
 
397
            memcpy(tab2, tab1, fft_size * sizeof(FFTSample));
398
            tab2[1] = tab1[fft_size_2].re;
399
 
400
            r->rdft_calc(r, tab2);
401
            fft_ref(tab_ref, tab1, fft_nbits);
402
            for (i = 0; i < fft_size; i++) {
403
                tab[i].re = tab2[i];
404
                tab[i].im = 0;
405
            }
406
            err = check_diff((float *)tab_ref, (float *)tab, fft_size * 2, 0.5);
407
        } else {
408
            for (i = 0; i < fft_size; i++) {
409
                tab2[i]    = tab1[i].re;
410
                tab1[i].im = 0;
411
            }
412
            r->rdft_calc(r, tab2);
413
            fft_ref(tab_ref, tab1, fft_nbits);
414
            tab_ref[0].im = tab_ref[fft_size_2].re;
415
            err = check_diff((float *)tab_ref, (float *)tab2, fft_size, 1.0);
416
        }
417
        break;
418
    case TRANSFORM_DCT:
419
        memcpy(tab, tab1, fft_size * sizeof(FFTComplex));
420
        d->dct_calc(d, (FFTSample *)tab);
421
        if (do_inverse) {
422
            idct_ref((FFTSample*)tab_ref, (FFTSample *)tab1, fft_nbits);
423
        } else {
424
            dct_ref((FFTSample*)tab_ref, (FFTSample *)tab1, fft_nbits);
425
        }
426
        err = check_diff((float *)tab_ref, (float *)tab, fft_size, 1.0);
427
        break;
428
#endif
429
    }
430
 
431
    /* do a speed test */
432
 
433
    if (do_speed) {
434
        int64_t time_start, duration;
435
        int nb_its;
436
 
437
        av_log(NULL, AV_LOG_INFO,"Speed test...\n");
438
        /* we measure during about 1 seconds */
439
        nb_its = 1;
440
        for(;;) {
441
            time_start = av_gettime();
442
            for (it = 0; it < nb_its; it++) {
443
                switch (transform) {
444
                case TRANSFORM_MDCT:
445
                    if (do_inverse) {
446
                        m->imdct_calc(m, (FFTSample *)tab, (FFTSample *)tab1);
447
                    } else {
448
                        m->mdct_calc(m, (FFTSample *)tab, (FFTSample *)tab1);
449
                    }
450
                    break;
451
                case TRANSFORM_FFT:
452
                    memcpy(tab, tab1, fft_size * sizeof(FFTComplex));
453
                    s->fft_calc(s, tab);
454
                    break;
455
#if CONFIG_FFT_FLOAT
456
                case TRANSFORM_RDFT:
457
                    memcpy(tab2, tab1, fft_size * sizeof(FFTSample));
458
                    r->rdft_calc(r, tab2);
459
                    break;
460
                case TRANSFORM_DCT:
461
                    memcpy(tab2, tab1, fft_size * sizeof(FFTSample));
462
                    d->dct_calc(d, tab2);
463
                    break;
464
#endif
465
                }
466
            }
467
            duration = av_gettime() - time_start;
468
            if (duration >= 1000000)
469
                break;
470
            nb_its *= 2;
471
        }
472
        av_log(NULL, AV_LOG_INFO,"time: %0.1f us/transform [total time=%0.2f s its=%d]\n",
473
               (double)duration / nb_its,
474
               (double)duration / 1000000.0,
475
               nb_its);
476
    }
477
 
478
    switch (transform) {
479
    case TRANSFORM_MDCT:
480
        ff_mdct_end(m);
481
        break;
482
    case TRANSFORM_FFT:
483
        ff_fft_end(s);
484
        break;
485
#if CONFIG_FFT_FLOAT
486
    case TRANSFORM_RDFT:
487
        ff_rdft_end(r);
488
        break;
489
#    if CONFIG_DCT
490
    case TRANSFORM_DCT:
491
        ff_dct_end(d);
492
        break;
493
#    endif
494
#endif
495
    }
496
 
497
    av_free(tab);
498
    av_free(tab1);
499
    av_free(tab2);
500
    av_free(tab_ref);
501
    av_free(exptab);
502
 
503
    if (err)
504
        printf("Error: %d.\n", err);
505
 
506
    return !!err;
507
}