X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Ffft-test.c;h=59a53ddeb6df0130a0ba7e87518c3cb549e4b470;hb=a72cad0a6c05aa74940101e937cb3dc602d7d67b;hp=87cb863a7a3546c63ad25b448bc98ef0dc7117d3;hpb=0979831511cf8cbc6675019c5932c18b8fec0d57;p=ffmpeg diff --git a/libavcodec/fft-test.c b/libavcodec/fft-test.c index 87cb863a7a3..59a53ddeb6d 100644 --- a/libavcodec/fft-test.c +++ b/libavcodec/fft-test.c @@ -1,14 +1,43 @@ +/* + * (c) 2002 Fabrice Bellard + * + * This file is part of Libav. + * + * Libav is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * Libav is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with Libav; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + /** - * @file fft-test.c + * @file * FFT and MDCT tests. */ -#include "dsputil.h" +#include "libavutil/mathematics.h" +#include "libavutil/lfg.h" +#include "libavutil/log.h" +#include "fft.h" +#if CONFIG_FFT_FLOAT +#include "dct.h" +#include "rdft.h" +#endif #include #include #include +#include +#include -int mm_flags; +#undef exit /* reference fft */ @@ -20,17 +49,29 @@ int mm_flags; pim += (MUL16(are, bim) + MUL16(bre, aim));\ } -FFTComplex *exptab; - -void fft_ref_init(int nbits, int inverse) +#if CONFIG_FFT_FLOAT +# define RANGE 1.0 +# define REF_SCALE(x, bits) (x) +# define FMT "%10.6f" +#else +# define RANGE 16384 +# define REF_SCALE(x, bits) ((x) / (1<<(bits))) +# define FMT "%6d" +#endif + +struct { + float re, im; +} *exptab; + +static void fft_ref_init(int nbits, int inverse) { int n, i; - float c1, s1, alpha; + double c1, s1, alpha; n = 1 << nbits; - exptab = av_malloc((n / 2) * sizeof(FFTComplex)); + exptab = av_malloc((n / 2) * sizeof(*exptab)); - for(i=0;i<(n/2);i++) { + for (i = 0; i < (n/2); i++) { alpha = 2 * M_PI * (float)i / (float)n; c1 = cos(alpha); s1 = sin(alpha); @@ -41,19 +82,19 @@ void fft_ref_init(int nbits, int inverse) } } -void fft_ref(FFTComplex *tabr, FFTComplex *tab, int nbits) +static void fft_ref(FFTComplex *tabr, FFTComplex *tab, int nbits) { int n, i, j, k, n2; - float tmp_re, tmp_im, s, c; + double tmp_re, tmp_im, s, c; FFTComplex *q; n = 1 << nbits; n2 = n >> 1; - for(i=0;i= n2) { c = -exptab[k - n2].re; @@ -65,100 +106,162 @@ void fft_ref(FFTComplex *tabr, FFTComplex *tab, int nbits) CMAC(tmp_re, tmp_im, c, s, q->re, q->im); q++; } - tabr[i].re = tmp_re; - tabr[i].im = tmp_im; + tabr[i].re = REF_SCALE(tmp_re, nbits); + tabr[i].im = REF_SCALE(tmp_im, nbits); } } -void imdct_ref(float *out, float *in, int n) +static void imdct_ref(FFTSample *out, FFTSample *in, int nbits) { + int n = 1<= 1e-3) { - av_log(NULL, AV_LOG_ERROR, "ERROR %d: %f %f\n", + double max= 0; + double error= 0; + int err = 0; + + for (i = 0; i < n; i++) { + double e = fabsf(tab1[i] - (tab2[i] / scale)) / RANGE; + if (e >= 1e-3) { + av_log(NULL, AV_LOG_ERROR, "ERROR %5d: "FMT" "FMT"\n", i, tab1[i], tab2[i]); + err = 1; } + error+= e*e; + if(e>max) max= e; } + av_log(NULL, AV_LOG_INFO, "max:%f e:%g\n", max, sqrt(error)/n); + return err; } -void help(void) +static void help(void) { av_log(NULL, AV_LOG_INFO,"usage: fft-test [-h] [-s] [-i] [-n b]\n" "-h print this help\n" "-s speed test\n" "-m (I)MDCT test\n" + "-d (I)DCT test\n" + "-r (I)RDFT test\n" "-i inverse transform test\n" "-n b set the transform size to 2^b\n" + "-f x set scale factor for output data of (I)MDCT to x\n" ); exit(1); } - +enum tf_transform { + TRANSFORM_FFT, + TRANSFORM_MDCT, + TRANSFORM_RDFT, + TRANSFORM_DCT, +}; int main(int argc, char **argv) { FFTComplex *tab, *tab1, *tab_ref; - FFTSample *tabtmp, *tab2; + FFTSample *tab2; int it, i, c; int do_speed = 0; - int do_mdct = 0; + int err = 1; + enum tf_transform transform = TRANSFORM_FFT; int do_inverse = 0; FFTContext s1, *s = &s1; - MDCTContext m1, *m = &m1; + FFTContext m1, *m = &m1; +#if CONFIG_FFT_FLOAT + RDFTContext r1, *r = &r1; + DCTContext d1, *d = &d1; + int fft_size_2; +#endif int fft_nbits, fft_size; + double scale = 1.0; + AVLFG prng; + av_lfg_init(&prng, 1); - mm_flags = 0; fft_nbits = 9; for(;;) { - c = getopt(argc, argv, "hsimn:"); + c = getopt(argc, argv, "hsimrdn:f:"); if (c == -1) break; switch(c) { @@ -172,11 +275,20 @@ int main(int argc, char **argv) do_inverse = 1; break; case 'm': - do_mdct = 1; + transform = TRANSFORM_MDCT; + break; + case 'r': + transform = TRANSFORM_RDFT; + break; + case 'd': + transform = TRANSFORM_DCT; break; case 'n': fft_nbits = atoi(optarg); break; + case 'f': + scale = atof(optarg); + break; } } @@ -184,54 +296,123 @@ int main(int argc, char **argv) tab = av_malloc(fft_size * sizeof(FFTComplex)); tab1 = av_malloc(fft_size * sizeof(FFTComplex)); tab_ref = av_malloc(fft_size * sizeof(FFTComplex)); - tabtmp = av_malloc(fft_size / 2 * sizeof(FFTSample)); tab2 = av_malloc(fft_size * sizeof(FFTSample)); - if (do_mdct) { + switch (transform) { + case TRANSFORM_MDCT: + av_log(NULL, AV_LOG_INFO,"Scale factor is set to %f\n", scale); if (do_inverse) av_log(NULL, AV_LOG_INFO,"IMDCT"); else av_log(NULL, AV_LOG_INFO,"MDCT"); - ff_mdct_init(m, fft_nbits, do_inverse); - } else { + ff_mdct_init(m, fft_nbits, do_inverse, scale); + break; + case TRANSFORM_FFT: if (do_inverse) av_log(NULL, AV_LOG_INFO,"IFFT"); else av_log(NULL, AV_LOG_INFO,"FFT"); ff_fft_init(s, fft_nbits, do_inverse); fft_ref_init(fft_nbits, do_inverse); + break; +#if CONFIG_FFT_FLOAT + case TRANSFORM_RDFT: + if (do_inverse) + av_log(NULL, AV_LOG_INFO,"IDFT_C2R"); + else + av_log(NULL, AV_LOG_INFO,"DFT_R2C"); + ff_rdft_init(r, fft_nbits, do_inverse ? IDFT_C2R : DFT_R2C); + fft_ref_init(fft_nbits, do_inverse); + break; + case TRANSFORM_DCT: + if (do_inverse) + av_log(NULL, AV_LOG_INFO,"DCT_III"); + else + av_log(NULL, AV_LOG_INFO,"DCT_II"); + ff_dct_init(d, fft_nbits, do_inverse ? DCT_III : DCT_II); + break; +#endif + default: + av_log(NULL, AV_LOG_ERROR, "Requested transform not supported\n"); + return 1; } av_log(NULL, AV_LOG_INFO," %d test\n", fft_size); /* generate random data */ - for(i=0;iimdct_calc(m, tab2, (FFTSample *)tab1); + err = check_diff((FFTSample *)tab_ref, tab2, fft_size, scale); } else { - mdct_ref((float *)tab_ref, (float *)tab1, fft_size); - - ff_mdct_calc(m, tab2, (float *)tab1, tabtmp); + mdct_ref((FFTSample *)tab_ref, (FFTSample *)tab1, fft_nbits); - check_diff((float *)tab_ref, tab2, fft_size / 2); + m->mdct_calc(m, tab2, (FFTSample *)tab1); + + err = check_diff((FFTSample *)tab_ref, tab2, fft_size / 2, scale); } - } else { + break; + case TRANSFORM_FFT: memcpy(tab, tab1, fft_size * sizeof(FFTComplex)); - ff_fft_permute(s, tab); - ff_fft_calc(s, tab); - + s->fft_permute(s, tab); + s->fft_calc(s, tab); + fft_ref(tab_ref, tab1, fft_nbits); - check_diff((float *)tab_ref, (float *)tab, fft_size * 2); + err = check_diff((FFTSample *)tab_ref, (FFTSample *)tab, fft_size * 2, 1.0); + break; +#if CONFIG_FFT_FLOAT + case TRANSFORM_RDFT: + fft_size_2 = fft_size >> 1; + if (do_inverse) { + tab1[ 0].im = 0; + tab1[fft_size_2].im = 0; + for (i = 1; i < fft_size_2; i++) { + tab1[fft_size_2+i].re = tab1[fft_size_2-i].re; + tab1[fft_size_2+i].im = -tab1[fft_size_2-i].im; + } + + memcpy(tab2, tab1, fft_size * sizeof(FFTSample)); + tab2[1] = tab1[fft_size_2].re; + + r->rdft_calc(r, tab2); + fft_ref(tab_ref, tab1, fft_nbits); + for (i = 0; i < fft_size; i++) { + tab[i].re = tab2[i]; + tab[i].im = 0; + } + err = check_diff((float *)tab_ref, (float *)tab, fft_size * 2, 0.5); + } else { + for (i = 0; i < fft_size; i++) { + tab2[i] = tab1[i].re; + tab1[i].im = 0; + } + r->rdft_calc(r, tab2); + fft_ref(tab_ref, tab1, fft_nbits); + tab_ref[0].im = tab_ref[fft_size_2].re; + err = check_diff((float *)tab_ref, (float *)tab2, fft_size, 1.0); + } + break; + case TRANSFORM_DCT: + memcpy(tab, tab1, fft_size * sizeof(FFTComplex)); + d->dct_calc(d, tab); + if (do_inverse) { + idct_ref(tab_ref, tab1, fft_nbits); + } else { + dct_ref(tab_ref, tab1, fft_nbits); + } + err = check_diff((float *)tab_ref, (float *)tab, fft_size, 1.0); + break; +#endif } /* do a speed test */ @@ -245,16 +426,29 @@ int main(int argc, char **argv) nb_its = 1; for(;;) { time_start = gettime(); - for(it=0;itimdct_calc(m, (FFTSample *)tab, (FFTSample *)tab1); } else { - ff_mdct_calc(m, (float *)tab, (float *)tab1, tabtmp); + m->mdct_calc(m, (FFTSample *)tab, (FFTSample *)tab1); } - } else { + break; + case TRANSFORM_FFT: memcpy(tab, tab1, fft_size * sizeof(FFTComplex)); - ff_fft_calc(s, tab); + s->fft_calc(s, tab); + break; +#if CONFIG_FFT_FLOAT + case TRANSFORM_RDFT: + memcpy(tab2, tab1, fft_size * sizeof(FFTSample)); + r->rdft_calc(r, tab2); + break; + case TRANSFORM_DCT: + memcpy(tab2, tab1, fft_size * sizeof(FFTSample)); + d->dct_calc(d, tab2); + break; +#endif } } duration = gettime() - time_start; @@ -262,16 +456,34 @@ int main(int argc, char **argv) break; nb_its *= 2; } - av_log(NULL, AV_LOG_INFO,"time: %0.1f us/transform [total time=%0.2f s its=%d]\n", - (double)duration / nb_its, + av_log(NULL, AV_LOG_INFO,"time: %0.1f us/transform [total time=%0.2f s its=%d]\n", + (double)duration / nb_its, (double)duration / 1000000.0, nb_its); } - - if (do_mdct) { + + switch (transform) { + case TRANSFORM_MDCT: ff_mdct_end(m); - } else { + break; + case TRANSFORM_FFT: ff_fft_end(s); + break; +#if CONFIG_FFT_FLOAT + case TRANSFORM_RDFT: + ff_rdft_end(r); + break; + case TRANSFORM_DCT: + ff_dct_end(d); + break; +#endif } - return 0; + + av_free(tab); + av_free(tab1); + av_free(tab2); + av_free(tab_ref); + av_free(exptab); + + return err; }