annotate ffmpeg/libavcodec/fft-test.c @ 13:844d341cf643 tip

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