Browse code

Add the rdft family of transforms (fft/ifft of an all real sequence) to dsputil.

Originally committed as revision 16864 to svn://svn.ffmpeg.org/ffmpeg/trunk

Alex Converse authored on 2009/01/31 05:15:48
Showing 5 changed files
... ...
@@ -102,6 +102,7 @@ show_help(){
102 102
   echo "  --disable-fft            disable FFT code"
103 103
   echo "  --disable-golomb         disable Golomb code"
104 104
   echo "  --disable-mdct           disable MDCT code"
105
+  echo "  --disable-rdft           disable RDFT code"
105 106
   echo "  --enable-hardcoded-tables use hardcoded tables instead of runtime generation"
106 107
   echo "  --enable-memalign-hack   emulate memalign, interferes with memory debuggers"
107 108
   echo "  --enable-beos-netserver  enable BeOS netserver"
... ...
@@ -781,6 +782,7 @@ CONFIG_LIST="
781 781
     nonfree
782 782
     postproc
783 783
     powerpc_perf
784
+    rdft
784 785
     shared
785 786
     small
786 787
     static
... ...
@@ -29,6 +29,7 @@ OBJS-$(CONFIG_ENCODERS)                += faandct.o jfdctfst.o jfdctint.o
29 29
 OBJS-$(CONFIG_FFT)                     += fft.o
30 30
 OBJS-$(CONFIG_GOLOMB)                  += golomb.o
31 31
 OBJS-$(CONFIG_MDCT)                    += mdct.o
32
+OBJS-$(CONFIG_RDFT)                    += rdft.o
32 33
 OBJS-$(CONFIG_OLDSCALER)               += imgresample.o
33 34
 
34 35
 # decoders/encoders
... ...
@@ -674,6 +674,8 @@ typedef struct FFTContext {
674 674
     void (*imdct_half)(struct MDCTContext *s, FFTSample *output, const FFTSample *input);
675 675
 } FFTContext;
676 676
 
677
+extern FFTSample* ff_cos_tabs[13];
678
+
677 679
 /**
678 680
  * Sets up a complex FFT.
679 681
  * @param nbits           log2 of the length of the input array
... ...
@@ -759,6 +761,35 @@ void ff_imdct_half_sse(MDCTContext *s, FFTSample *output, const FFTSample *input
759 759
 void ff_mdct_calc(MDCTContext *s, FFTSample *out, const FFTSample *input);
760 760
 void ff_mdct_end(MDCTContext *s);
761 761
 
762
+/* Real Discrete Fourier Transform */
763
+
764
+enum RDFTransformType {
765
+    RDFT,
766
+    IRDFT,
767
+    RIDFT,
768
+    IRIDFT,
769
+};
770
+
771
+typedef struct {
772
+    int nbits;
773
+    int inverse;
774
+    int sign_convention;
775
+
776
+    /* pre/post rotation tables */
777
+    FFTSample *tcos;
778
+    FFTSample *tsin;
779
+    FFTContext fft;
780
+} RDFTContext;
781
+
782
+/**
783
+ * Sets up a real FFT.
784
+ * @param nbits           log2 of the length of the input array
785
+ * @param trans           the type of transform
786
+ */
787
+int ff_rdft_init(RDFTContext *s, int nbits, enum RDFTransformType trans);
788
+void ff_rdft_calc(RDFTContext *s, FFTSample *data);
789
+void ff_rdft_end(RDFTContext *s);
790
+
762 791
 #define WRAPPER8_16(name8, name16)\
763 792
 static int name16(void /*MpegEncContext*/ *s, uint8_t *dst, uint8_t *src, int stride, int h){\
764 793
     return name8(s, dst           , src           , stride, h)\
... ...
@@ -42,7 +42,7 @@ DECLARE_ALIGNED_16(FFTSample, ff_cos_8192[4096]);
42 42
 DECLARE_ALIGNED_16(FFTSample, ff_cos_16384[8192]);
43 43
 DECLARE_ALIGNED_16(FFTSample, ff_cos_32768[16384]);
44 44
 DECLARE_ALIGNED_16(FFTSample, ff_cos_65536[32768]);
45
-static FFTSample *ff_cos_tabs[] = {
45
+FFTSample *ff_cos_tabs[] = {
46 46
     ff_cos_16, ff_cos_32, ff_cos_64, ff_cos_128, ff_cos_256, ff_cos_512, ff_cos_1024,
47 47
     ff_cos_2048, ff_cos_4096, ff_cos_8192, ff_cos_16384, ff_cos_32768, ff_cos_65536,
48 48
 };
49 49
new file mode 100644
... ...
@@ -0,0 +1,127 @@
0
+/*
1
+ * (I)RDFT transforms
2
+ * Copyright (c) 2009 Alex Converse <alex dot converse at gmail dot com>
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
+#include <math.h>
21
+#include "dsputil.h"
22
+
23
+/**
24
+ * @file rdft.c
25
+ * (Inverse) Real Discrete Fourier Transforms.
26
+ */
27
+
28
+/* sin(2*pi*x/n) for 0<=x<n/4, followed by n/2<=x<3n/4 */
29
+DECLARE_ALIGNED_16(FFTSample, ff_sin_16[8]);
30
+DECLARE_ALIGNED_16(FFTSample, ff_sin_32[16]);
31
+DECLARE_ALIGNED_16(FFTSample, ff_sin_64[32]);
32
+DECLARE_ALIGNED_16(FFTSample, ff_sin_128[64]);
33
+DECLARE_ALIGNED_16(FFTSample, ff_sin_256[128]);
34
+DECLARE_ALIGNED_16(FFTSample, ff_sin_512[256]);
35
+DECLARE_ALIGNED_16(FFTSample, ff_sin_1024[512]);
36
+DECLARE_ALIGNED_16(FFTSample, ff_sin_2048[1024]);
37
+DECLARE_ALIGNED_16(FFTSample, ff_sin_4096[2048]);
38
+DECLARE_ALIGNED_16(FFTSample, ff_sin_8192[4096]);
39
+DECLARE_ALIGNED_16(FFTSample, ff_sin_16384[8192]);
40
+DECLARE_ALIGNED_16(FFTSample, ff_sin_32768[16384]);
41
+DECLARE_ALIGNED_16(FFTSample, ff_sin_65536[32768]);
42
+FFTSample *ff_sin_tabs[] = {
43
+    ff_sin_16, ff_sin_32, ff_sin_64, ff_sin_128, ff_sin_256, ff_sin_512, ff_sin_1024,
44
+    ff_sin_2048, ff_sin_4096, ff_sin_8192, ff_sin_16384, ff_sin_32768, ff_sin_65536,
45
+};
46
+
47
+av_cold int ff_rdft_init(RDFTContext *s, int nbits, enum RDFTransformType trans)
48
+{
49
+    int n = 1 << nbits;
50
+    int i;
51
+    const double theta = (trans == RDFT || trans == IRIDFT ? -1 : 1)*2*M_PI/n;
52
+
53
+    s->nbits           = nbits;
54
+    s->inverse         = trans == IRDFT || trans == IRIDFT;
55
+    s->sign_convention = trans == RIDFT || trans == IRIDFT ? 1 : -1;
56
+
57
+    if (nbits < 4 || nbits > 16)
58
+        return -1;
59
+
60
+    if (ff_fft_init(&s->fft, nbits-1, trans == IRDFT || trans == RIDFT) < 0)
61
+        return -1;
62
+
63
+    s->tcos = ff_cos_tabs[nbits-4];
64
+    s->tsin = ff_sin_tabs[nbits-4]+(trans == RDFT || trans == IRIDFT)*(n>>2);
65
+    for (i = 0; i < (n>>2); i++) {
66
+        s->tcos[i] = cos(i*theta);
67
+        s->tsin[i] = sin(i*theta);
68
+    }
69
+    return 0;
70
+}
71
+
72
+/** Map one real FFT into two parallel real even and odd FFTs. Then interleave
73
+ * the two real FFTs into one complex FFT. Unmangle the results.
74
+ * ref: http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM
75
+ */
76
+void ff_rdft_calc_c(RDFTContext* s, FFTSample* data)
77
+{
78
+    int i, i1, i2;
79
+    FFTComplex ev, od;
80
+    const int n = 1 << s->nbits;
81
+    const float k1 = 0.5;
82
+    const float k2 = 0.5 - s->inverse;
83
+    const FFTSample *tcos = s->tcos;
84
+    const FFTSample *tsin = s->tsin;
85
+
86
+    if (!s->inverse) {
87
+        ff_fft_permute(&s->fft, (FFTComplex*)data);
88
+        ff_fft_calc(&s->fft, (FFTComplex*)data);
89
+    }
90
+    /* i=0 is a special case because of packing, the DC term is real, so we
91
+       are going to throw the N/2 term (also real) in with it. */
92
+    ev.re = data[0];
93
+    data[0] = ev.re+data[1];
94
+    data[1] = ev.re-data[1];
95
+    for (i = 1; i < (n>>2); i++) {
96
+        i1 = 2*i;
97
+        i2 = n-i1;
98
+        /* Separate even and odd FFTs */
99
+        ev.re =  k1*(data[i1  ]+data[i2  ]);
100
+        od.im = -k2*(data[i1  ]-data[i2  ]);
101
+        ev.im =  k1*(data[i1+1]-data[i2+1]);
102
+        od.re =  k2*(data[i1+1]+data[i2+1]);
103
+        /* Apply twiddle factors to the odd FFT and add to the even FFT */
104
+        data[i1  ] =  ev.re + od.re*tcos[i] - od.im*tsin[i];
105
+        data[i1+1] =  ev.im + od.im*tcos[i] + od.re*tsin[i];
106
+        data[i2  ] =  ev.re - od.re*tcos[i] + od.im*tsin[i];
107
+        data[i2+1] = -ev.im + od.im*tcos[i] + od.re*tsin[i];
108
+    }
109
+    data[2*i+1]=s->sign_convention*data[2*i+1];
110
+    if (s->inverse) {
111
+        data[0] *= k1;
112
+        data[1] *= k1;
113
+        ff_fft_permute(&s->fft, (FFTComplex*)data);
114
+        ff_fft_calc(&s->fft, (FFTComplex*)data);
115
+    }
116
+}
117
+
118
+void ff_rdft_calc(RDFTContext *s, FFTSample *data)
119
+{
120
+    ff_rdft_calc_c(s, data);
121
+}
122
+
123
+av_cold void ff_rdft_end(RDFTContext *s)
124
+{
125
+    ff_fft_end(&s->fft);
126
+}