Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / audio / ffmpeg / FFTFrameFFMPEG.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 // FFTFrame implementation using FFmpeg's RDFT algorithm,
27 // suitable for use on Windows and Linux.
28
29 #include "config.h"
30
31 #if ENABLE(WEB_AUDIO)
32
33 #if USE(WEBAUDIO_FFMPEG)
34
35 #include "platform/audio/FFTFrame.h"
36
37 #include "platform/audio/VectorMath.h"
38
39 extern "C" {
40     #include <libavcodec/avfft.h>
41 }
42
43 #include "wtf/MathExtras.h"
44
45 namespace blink {
46
47 #if ENABLE(ASSERT)
48 const int kMaxFFTPow2Size = 24;
49 #endif
50
51 // Normal constructor: allocates for a given fftSize.
52 FFTFrame::FFTFrame(unsigned fftSize)
53     : m_FFTSize(fftSize)
54     , m_log2FFTSize(static_cast<unsigned>(log2(fftSize)))
55     , m_realData(fftSize / 2)
56     , m_imagData(fftSize / 2)
57     , m_forwardContext(0)
58     , m_inverseContext(0)
59     , m_complexData(fftSize)
60 {
61     // We only allow power of two.
62     ASSERT(1UL << m_log2FFTSize == m_FFTSize);
63
64     m_forwardContext = contextForSize(fftSize, DFT_R2C);
65     m_inverseContext = contextForSize(fftSize, IDFT_C2R);
66 }
67
68 // Creates a blank/empty frame (interpolate() must later be called).
69 FFTFrame::FFTFrame()
70     : m_FFTSize(0)
71     , m_log2FFTSize(0)
72     , m_forwardContext(0)
73     , m_inverseContext(0)
74 {
75 }
76
77 // Copy constructor.
78 FFTFrame::FFTFrame(const FFTFrame& frame)
79     : m_FFTSize(frame.m_FFTSize)
80     , m_log2FFTSize(frame.m_log2FFTSize)
81     , m_realData(frame.m_FFTSize / 2)
82     , m_imagData(frame.m_FFTSize / 2)
83     , m_forwardContext(0)
84     , m_inverseContext(0)
85     , m_complexData(frame.m_FFTSize)
86 {
87     m_forwardContext = contextForSize(m_FFTSize, DFT_R2C);
88     m_inverseContext = contextForSize(m_FFTSize, IDFT_C2R);
89
90     // Copy/setup frame data.
91     unsigned nbytes = sizeof(float) * (m_FFTSize / 2);
92     memcpy(realData(), frame.realData(), nbytes);
93     memcpy(imagData(), frame.imagData(), nbytes);
94 }
95
96 void FFTFrame::initialize()
97 {
98 }
99
100 void FFTFrame::cleanup()
101 {
102 }
103
104 FFTFrame::~FFTFrame()
105 {
106     av_rdft_end(m_forwardContext);
107     av_rdft_end(m_inverseContext);
108 }
109
110 void FFTFrame::doFFT(const float* data)
111 {
112     // Copy since processing is in-place.
113     float* p = m_complexData.data();
114     memcpy(p, data, sizeof(float) * m_FFTSize);
115
116     // Compute Forward transform.
117     av_rdft_calc(m_forwardContext, p);
118
119     // De-interleave to separate real and complex arrays.
120     int len = m_FFTSize / 2;
121
122     float* real = m_realData.data();
123     float* imag = m_imagData.data();
124     for (int i = 0; i < len; ++i) {
125         int baseComplexIndex = 2 * i;
126         // m_realData[0] is the DC component and m_imagData[0] is the nyquist component
127         // since the interleaved complex data is packed.
128         real[i] = p[baseComplexIndex];
129         imag[i] = p[baseComplexIndex + 1];
130     }
131 }
132
133 void FFTFrame::doInverseFFT(float* data)
134 {
135     // Prepare interleaved data.
136     float* interleavedData = getUpToDateComplexData();
137
138     // Compute inverse transform.
139     av_rdft_calc(m_inverseContext, interleavedData);
140
141     // Scale so that a forward then inverse FFT yields exactly the original data. For some reason
142     // av_rdft_calc above returns values that are half of what I expect. Hence make the scale factor
143     // twice as large to compensate for that.
144     const float scale = 2.0 / m_FFTSize;
145     VectorMath::vsmul(interleavedData, 1, &scale, data, 1, m_FFTSize);
146 }
147
148 float* FFTFrame::getUpToDateComplexData()
149 {
150     // FIXME: if we can't completely get rid of this method, SSE
151     // optimization could be considered if it shows up hot on profiles.
152     int len = m_FFTSize / 2;
153     const float* real = m_realData.data();
154     const float* imag = m_imagData.data();
155     float* c = m_complexData.data();
156     for (int i = 0; i < len; ++i) {
157         int baseComplexIndex = 2 * i;
158         c[baseComplexIndex] = real[i];
159         c[baseComplexIndex + 1] = imag[i];
160     }
161     return const_cast<float*>(m_complexData.data());
162 }
163
164 RDFTContext* FFTFrame::contextForSize(unsigned fftSize, int trans)
165 {
166     // FIXME: This is non-optimal. Ideally, we'd like to share the contexts for FFTFrames of the same size.
167     // But FFmpeg's RDFT uses a scratch buffer inside the context and so they are not thread-safe.
168     // We could improve this by sharing the FFTFrames on a per-thread basis.
169     ASSERT(fftSize);
170     int pow2size = static_cast<int>(log2(fftSize));
171     ASSERT(pow2size < kMaxFFTPow2Size);
172
173     RDFTContext* context = av_rdft_init(pow2size, (RDFTransformType)trans);
174     return context;
175 }
176
177 } // namespace blink
178
179 #endif // USE(WEBAUDIO_FFMPEG)
180
181 #endif // ENABLE(WEB_AUDIO)