annotate rdft.c @ 9473:e38284cd69dc libavcodec

Use memcpy instead of the very inefficient bytecopy where both are correct (i.e. no overlap of src and dst is possible).
author reimar
date Fri, 17 Apr 2009 17:20:48 +0000
parents e9d9d946f213
children 9855215d1b2f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
8694
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
1 /*
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
2 * (I)RDFT transforms
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
3 * Copyright (c) 2009 Alex Converse <alex dot converse at gmail dot com>
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
4 *
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
5 * This file is part of FFmpeg.
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
6 *
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
7 * FFmpeg is free software; you can redistribute it and/or
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
8 * modify it under the terms of the GNU Lesser General Public
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
9 * License as published by the Free Software Foundation; either
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
10 * version 2.1 of the License, or (at your option) any later version.
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
11 *
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
12 * FFmpeg is distributed in the hope that it will be useful,
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
15 * Lesser General Public License for more details.
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
16 *
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
17 * You should have received a copy of the GNU Lesser General Public
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
18 * License along with FFmpeg; if not, write to the Free Software
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
20 */
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
21 #include <math.h>
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
22 #include "dsputil.h"
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
23
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
24 /**
8718
e9d9d946f213 Use full internal pathname in doxygen @file directives.
diego
parents: 8694
diff changeset
25 * @file libavcodec/rdft.c
8694
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
26 * (Inverse) Real Discrete Fourier Transforms.
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
27 */
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
28
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
29 /* sin(2*pi*x/n) for 0<=x<n/4, followed by n/2<=x<3n/4 */
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
30 DECLARE_ALIGNED_16(FFTSample, ff_sin_16[8]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
31 DECLARE_ALIGNED_16(FFTSample, ff_sin_32[16]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
32 DECLARE_ALIGNED_16(FFTSample, ff_sin_64[32]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
33 DECLARE_ALIGNED_16(FFTSample, ff_sin_128[64]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
34 DECLARE_ALIGNED_16(FFTSample, ff_sin_256[128]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
35 DECLARE_ALIGNED_16(FFTSample, ff_sin_512[256]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
36 DECLARE_ALIGNED_16(FFTSample, ff_sin_1024[512]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
37 DECLARE_ALIGNED_16(FFTSample, ff_sin_2048[1024]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
38 DECLARE_ALIGNED_16(FFTSample, ff_sin_4096[2048]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
39 DECLARE_ALIGNED_16(FFTSample, ff_sin_8192[4096]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
40 DECLARE_ALIGNED_16(FFTSample, ff_sin_16384[8192]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
41 DECLARE_ALIGNED_16(FFTSample, ff_sin_32768[16384]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
42 DECLARE_ALIGNED_16(FFTSample, ff_sin_65536[32768]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
43 FFTSample *ff_sin_tabs[] = {
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
44 ff_sin_16, ff_sin_32, ff_sin_64, ff_sin_128, ff_sin_256, ff_sin_512, ff_sin_1024,
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
45 ff_sin_2048, ff_sin_4096, ff_sin_8192, ff_sin_16384, ff_sin_32768, ff_sin_65536,
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
46 };
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
47
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
48 av_cold int ff_rdft_init(RDFTContext *s, int nbits, enum RDFTransformType trans)
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
49 {
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
50 int n = 1 << nbits;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
51 int i;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
52 const double theta = (trans == RDFT || trans == IRIDFT ? -1 : 1)*2*M_PI/n;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
53
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
54 s->nbits = nbits;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
55 s->inverse = trans == IRDFT || trans == IRIDFT;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
56 s->sign_convention = trans == RIDFT || trans == IRIDFT ? 1 : -1;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
57
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
58 if (nbits < 4 || nbits > 16)
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
59 return -1;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
60
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
61 if (ff_fft_init(&s->fft, nbits-1, trans == IRDFT || trans == RIDFT) < 0)
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
62 return -1;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
63
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
64 s->tcos = ff_cos_tabs[nbits-4];
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
65 s->tsin = ff_sin_tabs[nbits-4]+(trans == RDFT || trans == IRIDFT)*(n>>2);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
66 for (i = 0; i < (n>>2); i++) {
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
67 s->tcos[i] = cos(i*theta);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
68 s->tsin[i] = sin(i*theta);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
69 }
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
70 return 0;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
71 }
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
72
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
73 /** Map one real FFT into two parallel real even and odd FFTs. Then interleave
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
74 * the two real FFTs into one complex FFT. Unmangle the results.
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
75 * ref: http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
76 */
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
77 void ff_rdft_calc_c(RDFTContext* s, FFTSample* data)
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
78 {
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
79 int i, i1, i2;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
80 FFTComplex ev, od;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
81 const int n = 1 << s->nbits;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
82 const float k1 = 0.5;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
83 const float k2 = 0.5 - s->inverse;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
84 const FFTSample *tcos = s->tcos;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
85 const FFTSample *tsin = s->tsin;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
86
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
87 if (!s->inverse) {
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
88 ff_fft_permute(&s->fft, (FFTComplex*)data);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
89 ff_fft_calc(&s->fft, (FFTComplex*)data);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
90 }
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
91 /* i=0 is a special case because of packing, the DC term is real, so we
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
92 are going to throw the N/2 term (also real) in with it. */
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
93 ev.re = data[0];
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
94 data[0] = ev.re+data[1];
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
95 data[1] = ev.re-data[1];
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
96 for (i = 1; i < (n>>2); i++) {
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
97 i1 = 2*i;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
98 i2 = n-i1;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
99 /* Separate even and odd FFTs */
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
100 ev.re = k1*(data[i1 ]+data[i2 ]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
101 od.im = -k2*(data[i1 ]-data[i2 ]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
102 ev.im = k1*(data[i1+1]-data[i2+1]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
103 od.re = k2*(data[i1+1]+data[i2+1]);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
104 /* Apply twiddle factors to the odd FFT and add to the even FFT */
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
105 data[i1 ] = ev.re + od.re*tcos[i] - od.im*tsin[i];
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
106 data[i1+1] = ev.im + od.im*tcos[i] + od.re*tsin[i];
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
107 data[i2 ] = ev.re - od.re*tcos[i] + od.im*tsin[i];
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
108 data[i2+1] = -ev.im + od.im*tcos[i] + od.re*tsin[i];
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
109 }
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
110 data[2*i+1]=s->sign_convention*data[2*i+1];
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
111 if (s->inverse) {
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
112 data[0] *= k1;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
113 data[1] *= k1;
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
114 ff_fft_permute(&s->fft, (FFTComplex*)data);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
115 ff_fft_calc(&s->fft, (FFTComplex*)data);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
116 }
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
117 }
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
118
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
119 void ff_rdft_calc(RDFTContext *s, FFTSample *data)
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
120 {
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
121 ff_rdft_calc_c(s, data);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
122 }
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
123
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
124 av_cold void ff_rdft_end(RDFTContext *s)
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
125 {
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
126 ff_fft_end(&s->fft);
68fd157bab48 Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff changeset
127 }