Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / platform / audio / ffmpeg / FFTFrameFFMPEG.cpp
blobd578f2276085777532d7bae37412ebb70813a5af
1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
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.
26 // FFTFrame implementation using FFmpeg's RDFT algorithm,
27 // suitable for use on Windows and Linux.
29 #include "config.h"
31 #if ENABLE(WEB_AUDIO)
33 #if USE(WEBAUDIO_FFMPEG)
35 #include "platform/audio/FFTFrame.h"
37 #include "platform/audio/VectorMath.h"
39 extern "C" {
40 #include <libavcodec/avfft.h>
43 #include "wtf/MathExtras.h"
45 namespace blink {
47 #if ENABLE(ASSERT)
48 const int kMaxFFTPow2Size = 24;
49 #endif
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(nullptr)
58 , m_inverseContext(nullptr)
59 , m_complexData(fftSize)
61 // We only allow power of two.
62 ASSERT(1UL << m_log2FFTSize == m_FFTSize);
64 m_forwardContext = contextForSize(fftSize, DFT_R2C);
65 m_inverseContext = contextForSize(fftSize, IDFT_C2R);
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(nullptr)
73 , m_inverseContext(nullptr)
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(nullptr)
84 , m_inverseContext(nullptr)
85 , m_complexData(frame.m_FFTSize)
87 m_forwardContext = contextForSize(m_FFTSize, DFT_R2C);
88 m_inverseContext = contextForSize(m_FFTSize, IDFT_C2R);
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);
96 void FFTFrame::initialize()
100 void FFTFrame::cleanup()
104 FFTFrame::~FFTFrame()
106 av_rdft_end(m_forwardContext);
107 av_rdft_end(m_inverseContext);
110 void FFTFrame::doFFT(const float* data)
112 // Copy since processing is in-place.
113 float* p = m_complexData.data();
114 memcpy(p, data, sizeof(float) * m_FFTSize);
116 // Compute Forward transform.
117 av_rdft_calc(m_forwardContext, p);
119 // De-interleave to separate real and complex arrays.
120 int len = m_FFTSize / 2;
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];
133 void FFTFrame::doInverseFFT(float* data)
135 // Prepare interleaved data.
136 float* interleavedData = getUpToDateComplexData();
138 // Compute inverse transform.
139 av_rdft_calc(m_inverseContext, interleavedData);
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);
148 float* FFTFrame::getUpToDateComplexData()
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];
161 return const_cast<float*>(m_complexData.data());
164 RDFTContext* FFTFrame::contextForSize(unsigned fftSize, int trans)
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);
173 RDFTContext* context = av_rdft_init(pow2size, (RDFTransformType)trans);
174 return context;
177 } // namespace blink
179 #endif // USE(WEBAUDIO_FFMPEG)
181 #endif // ENABLE(WEB_AUDIO)