Mercurial > libavcodec.hg
annotate rdft.c @ 12266:48d6738904a9 libavcodec
Fix SPLATB_REG mess. Used to be a if/elseif/elseif/elseif spaghetti, so this
splits it into small optimization-specific macros which are selected for each
DSP function. The advantage of this approach is that the sse4 functions now
use the ssse3 codepath also without needing an explicit sse4 codepath.
author | rbultje |
---|---|
date | Sat, 24 Jul 2010 19:33:05 +0000 |
parents | 7dd2a45249a9 |
children |
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 */ |
11444
6f1697664bf2
Replace many includes of libavutil/common.h with what is actually needed
mru
parents:
11391
diff
changeset
|
21 #include <stdlib.h> |
8694
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
22 #include <math.h> |
11370 | 23 #include "libavutil/mathematics.h" |
24 #include "fft.h" | |
8694
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
25 |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
26 /** |
11644
7dd2a45249a9
Remove explicit filename from Doxygen @file commands.
diego
parents:
11532
diff
changeset
|
27 * @file |
8694
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
28 * (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
|
29 */ |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
30 |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
31 /* sin(2*pi*x/n) for 0<=x<n/4, followed by n/2<=x<3n/4 */ |
10408 | 32 #if !CONFIG_HARDCODED_TABLES |
10407
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
33 SINTABLE(16); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
34 SINTABLE(32); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
35 SINTABLE(64); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
36 SINTABLE(128); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
37 SINTABLE(256); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
38 SINTABLE(512); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
39 SINTABLE(1024); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
40 SINTABLE(2048); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
41 SINTABLE(4096); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
42 SINTABLE(8192); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
43 SINTABLE(16384); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
44 SINTABLE(32768); |
57acce8b1380
Move/add COSTABLE/SINTABLE macros to dsputil to add extern definitions
reimar
parents:
10402
diff
changeset
|
45 SINTABLE(65536); |
10408 | 46 #endif |
47 SINTABLE_CONST FFTSample * const ff_sin_tabs[] = { | |
10492
63910f7ba293
Pad ff_cos_tabs and ff_sin_tabs so that index n points to the table for n bits.
reimar
parents:
10408
diff
changeset
|
48 NULL, NULL, NULL, NULL, |
8694
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
49 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
|
50 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
|
51 }; |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
52 |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
53 /** 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
|
54 * 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
|
55 * 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
|
56 */ |
11374 | 57 static void ff_rdft_calc_c(RDFTContext* s, FFTSample* data) |
8694
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
58 { |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
59 int i, i1, i2; |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
60 FFTComplex ev, od; |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
61 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
|
62 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
|
63 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
|
64 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
|
65 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
|
66 |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
67 if (!s->inverse) { |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
68 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
|
69 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
|
70 } |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
71 /* 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
|
72 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
|
73 ev.re = data[0]; |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
74 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
|
75 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
|
76 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
|
77 i1 = 2*i; |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
78 i2 = n-i1; |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
79 /* 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
|
80 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
|
81 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
|
82 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
|
83 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
|
84 /* 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
|
85 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
|
86 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
|
87 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
|
88 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
|
89 } |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
90 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
|
91 if (s->inverse) { |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
92 data[0] *= k1; |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
93 data[1] *= k1; |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
94 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
|
95 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
|
96 } |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
97 } |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
98 |
11513 | 99 av_cold int ff_rdft_init(RDFTContext *s, int nbits, enum RDFTransformType trans) |
100 { | |
101 int n = 1 << nbits; | |
102 int i; | |
103 const double theta = (trans == DFT_R2C || trans == DFT_C2R ? -1 : 1)*2*M_PI/n; | |
104 | |
105 s->nbits = nbits; | |
106 s->inverse = trans == IDFT_C2R || trans == DFT_C2R; | |
107 s->sign_convention = trans == IDFT_R2C || trans == DFT_C2R ? 1 : -1; | |
108 | |
109 if (nbits < 4 || nbits > 16) | |
110 return -1; | |
111 | |
112 if (ff_fft_init(&s->fft, nbits-1, trans == IDFT_C2R || trans == IDFT_R2C) < 0) | |
113 return -1; | |
114 | |
115 ff_init_ff_cos_tabs(nbits); | |
116 s->tcos = ff_cos_tabs[nbits]; | |
117 s->tsin = ff_sin_tabs[nbits]+(trans == DFT_R2C || trans == DFT_C2R)*(n>>2); | |
118 #if !CONFIG_HARDCODED_TABLES | |
119 for (i = 0; i < (n>>2); i++) { | |
120 s->tsin[i] = sin(i*theta); | |
121 } | |
122 #endif | |
123 s->rdft_calc = ff_rdft_calc_c; | |
11532 | 124 |
125 if (ARCH_ARM) ff_rdft_init_arm(s); | |
126 | |
11513 | 127 return 0; |
128 } | |
129 | |
8694
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
130 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
|
131 { |
68fd157bab48
Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.
alexc
parents:
diff
changeset
|
132 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
|
133 } |