| Index: media/base/audio_renderer_mixer.cc
|
| diff --git a/media/base/audio_renderer_mixer.cc b/media/base/audio_renderer_mixer.cc
|
| index 6d23faad35d6257274d0738ffdbb903104e7006f..88b7ac0f624772d2c0902c4d489d50eb5df306b0 100644
|
| --- a/media/base/audio_renderer_mixer.cc
|
| +++ b/media/base/audio_renderer_mixer.cc
|
| @@ -6,17 +6,57 @@
|
|
|
| #include "base/bind.h"
|
| #include "base/bind_helpers.h"
|
| +#include "base/cpu.h"
|
| #include "base/logging.h"
|
| #include "media/audio/audio_util.h"
|
| #include "media/base/limits.h"
|
|
|
| +#if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__)
|
| +#include <xmmintrin.h>
|
| +#endif
|
| +
|
| namespace media {
|
|
|
| +static void VectorFMAC_C(float* src, float* dest, float scale, int len) {
|
| + for (int i = 0; i < len; ++i)
|
| + dest[i] += src[i] * scale;
|
| +}
|
| +
|
| +#if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__)
|
| +static const int kFloatsPerPass = sizeof(__m128) / sizeof(float);
|
| +static void VectorFMAC_SSE(float* src, float* dest, float scale, int len) {
|
| + // Ensure |src| and |dest| are aligned properly.
|
| + DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(src) & (sizeof(__m128) - 1));
|
| + DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(dest) & (sizeof(__m128) - 1));
|
| +
|
| + __m128 m_scale = _mm_set_ps1(scale);
|
| + int rem = len % kFloatsPerPass;
|
| + for (int i = 0; i < len - rem; i += kFloatsPerPass) {
|
| + _mm_store_ps(dest + i, _mm_add_ps(_mm_load_ps(dest + i),
|
| + _mm_mul_ps(_mm_load_ps(src + i), m_scale)));
|
| + }
|
| +
|
| + // Handle any remaining values that wouldn't fit in an SSE pass.
|
| + if (rem)
|
| + VectorFMAC_C(src + len - rem, dest + len - rem, scale, rem);
|
| +}
|
| +#endif
|
| +
|
| +typedef void (*VectorFMACProc)(float* src, float* dest, float scale, int len);
|
| +static VectorFMACProc vector_fmac_proc = NULL;
|
| +
|
| AudioRendererMixer::AudioRendererMixer(
|
| const AudioParameters& input_params, const AudioParameters& output_params,
|
| const scoped_refptr<AudioRendererSink>& sink)
|
| : audio_sink_(sink),
|
| current_audio_delay_milliseconds_(0) {
|
| + if (!vector_fmac_proc) {
|
| + vector_fmac_proc = VectorFMAC_C;
|
| + base::CPU cpu;
|
| + if (cpu.has_sse())
|
| + vector_fmac_proc = VectorFMAC_SSE;
|
| + }
|
| +
|
| // Sanity check sample rates.
|
| DCHECK_LE(input_params.sample_rate(), limits::kMaxSampleRate);
|
| DCHECK_GE(input_params.sample_rate(), limits::kMinSampleRate);
|
| @@ -120,12 +160,9 @@ void AudioRendererMixer::ProvideInput(const std::vector<float*>& audio_data,
|
| continue;
|
|
|
| // Volume adjust and mix each mixer input into |audio_data| after rendering.
|
| - // TODO(dalecurtis): Optimize with NEON/SSE/AVX vector_fmac from FFmpeg.
|
| for (size_t j = 0; j < audio_data.size(); ++j) {
|
| - float* dest = audio_data[j];
|
| - float* source = mixer_input_audio_data_[j];
|
| - for (int k = 0; k < frames_filled; ++k)
|
| - dest[k] += source[k] * static_cast<float>(volume);
|
| + vector_fmac_proc(
|
| + mixer_input_audio_data_[j], audio_data[j], volume, frames_filled);
|
| }
|
|
|
| // No need to clamp values as InterleaveFloatToInt() will take care of this
|
|
|