Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Side by Side Diff: media/base/audio_renderer_mixer.cc

Issue 10802005: Add SSE optimizations to AudioRendererMixer. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix cast truncation. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/base/audio_renderer_mixer.h ('k') | media/base/audio_renderer_mixer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/base/audio_renderer_mixer.h" 5 #include "media/base/audio_renderer_mixer.h"
6 6
7 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__)
8 #include <xmmintrin.h>
9 #endif
10
7 #include "base/bind.h" 11 #include "base/bind.h"
8 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
13 #include "base/cpu.h"
9 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/memory/aligned_memory.h"
10 #include "media/audio/audio_util.h" 16 #include "media/audio/audio_util.h"
11 #include "media/base/limits.h" 17 #include "media/base/limits.h"
12 18
13 namespace media { 19 namespace media {
14 20
15 AudioRendererMixer::AudioRendererMixer( 21 AudioRendererMixer::AudioRendererMixer(
16 const AudioParameters& input_params, const AudioParameters& output_params, 22 const AudioParameters& input_params, const AudioParameters& output_params,
17 const scoped_refptr<AudioRendererSink>& sink) 23 const scoped_refptr<AudioRendererSink>& sink)
18 : audio_sink_(sink), 24 : audio_sink_(sink),
19 current_audio_delay_milliseconds_(0) { 25 current_audio_delay_milliseconds_(0) {
(...skipping 15 matching lines...) Expand all
35 audio_sink_->Initialize(output_params, this); 41 audio_sink_->Initialize(output_params, this);
36 audio_sink_->Start(); 42 audio_sink_->Start();
37 } 43 }
38 44
39 AudioRendererMixer::~AudioRendererMixer() { 45 AudioRendererMixer::~AudioRendererMixer() {
40 // AudioRendererSinks must be stopped before being destructed. 46 // AudioRendererSinks must be stopped before being destructed.
41 audio_sink_->Stop(); 47 audio_sink_->Stop();
42 48
43 // Clean up |mixer_input_audio_data_|. 49 // Clean up |mixer_input_audio_data_|.
44 for (size_t i = 0; i < mixer_input_audio_data_.size(); ++i) 50 for (size_t i = 0; i < mixer_input_audio_data_.size(); ++i)
45 delete [] mixer_input_audio_data_[i]; 51 base::AlignedFree(mixer_input_audio_data_[i]);
46 mixer_input_audio_data_.clear(); 52 mixer_input_audio_data_.clear();
47 53
48 // Ensures that all mixer inputs have stopped themselves prior to destruction 54 // Ensures that all mixer inputs have stopped themselves prior to destruction
49 // and have called RemoveMixerInput(). 55 // and have called RemoveMixerInput().
50 DCHECK_EQ(mixer_inputs_.size(), 0U); 56 DCHECK_EQ(mixer_inputs_.size(), 0U);
51 } 57 }
52 58
53 void AudioRendererMixer::AddMixerInput( 59 void AudioRendererMixer::AddMixerInput(
54 const scoped_refptr<AudioRendererMixerInput>& input) { 60 const scoped_refptr<AudioRendererMixerInput>& input) {
55 base::AutoLock auto_lock(mixer_inputs_lock_); 61 base::AutoLock auto_lock(mixer_inputs_lock_);
(...skipping 21 matching lines...) Expand all
77 return number_of_frames; 83 return number_of_frames;
78 } 84 }
79 85
80 void AudioRendererMixer::ProvideInput(const std::vector<float*>& audio_data, 86 void AudioRendererMixer::ProvideInput(const std::vector<float*>& audio_data,
81 int number_of_frames) { 87 int number_of_frames) {
82 base::AutoLock auto_lock(mixer_inputs_lock_); 88 base::AutoLock auto_lock(mixer_inputs_lock_);
83 89
84 // Allocate staging area for each mixer input's audio data on first call. We 90 // Allocate staging area for each mixer input's audio data on first call. We
85 // won't know how much to allocate until here because of resampling. 91 // won't know how much to allocate until here because of resampling.
86 if (mixer_input_audio_data_.size() == 0) { 92 if (mixer_input_audio_data_.size() == 0) {
87 // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to
88 // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes.
89 mixer_input_audio_data_.reserve(audio_data.size()); 93 mixer_input_audio_data_.reserve(audio_data.size());
90 for (size_t i = 0; i < audio_data.size(); ++i) 94 for (size_t i = 0; i < audio_data.size(); ++i) {
91 mixer_input_audio_data_.push_back(new float[number_of_frames]); 95 // Allocate audio data with a 16-byte alignment for SSE optimizations.
96 mixer_input_audio_data_.push_back(static_cast<float*>(
97 base::AlignedAlloc(sizeof(float) * number_of_frames, 16)));
98 }
92 mixer_input_audio_data_size_ = number_of_frames; 99 mixer_input_audio_data_size_ = number_of_frames;
93 } 100 }
94 101
95 // Sanity check our inputs. 102 // Sanity check our inputs.
96 DCHECK_LE(number_of_frames, mixer_input_audio_data_size_); 103 DCHECK_LE(number_of_frames, mixer_input_audio_data_size_);
97 DCHECK_EQ(audio_data.size(), mixer_input_audio_data_.size()); 104 DCHECK_EQ(audio_data.size(), mixer_input_audio_data_.size());
98 105
99 // Zero |audio_data| so we're mixing into a clean buffer and return silence if 106 // Zero |audio_data| so we're mixing into a clean buffer and return silence if
100 // we couldn't get enough data from our inputs. 107 // we couldn't get enough data from our inputs.
101 for (size_t i = 0; i < audio_data.size(); ++i) 108 for (size_t i = 0; i < audio_data.size(); ++i)
(...skipping 11 matching lines...) Expand all
113 if (!input->playing()) 120 if (!input->playing())
114 continue; 121 continue;
115 122
116 int frames_filled = input->callback()->Render( 123 int frames_filled = input->callback()->Render(
117 mixer_input_audio_data_, number_of_frames, 124 mixer_input_audio_data_, number_of_frames,
118 current_audio_delay_milliseconds_); 125 current_audio_delay_milliseconds_);
119 if (frames_filled == 0) 126 if (frames_filled == 0)
120 continue; 127 continue;
121 128
122 // Volume adjust and mix each mixer input into |audio_data| after rendering. 129 // Volume adjust and mix each mixer input into |audio_data| after rendering.
123 // TODO(dalecurtis): Optimize with NEON/SSE/AVX vector_fmac from FFmpeg.
124 for (size_t j = 0; j < audio_data.size(); ++j) { 130 for (size_t j = 0; j < audio_data.size(); ++j) {
125 float* dest = audio_data[j]; 131 VectorFMAC(
126 float* source = mixer_input_audio_data_[j]; 132 mixer_input_audio_data_[j], volume, frames_filled, audio_data[j]);
127 for (int k = 0; k < frames_filled; ++k)
128 dest[k] += source[k] * static_cast<float>(volume);
129 } 133 }
130 134
131 // No need to clamp values as InterleaveFloatToInt() will take care of this 135 // No need to clamp values as InterleaveFloatToInt() will take care of this
132 // for us later when data is transferred to the browser process. 136 // for us later when data is transferred to the browser process.
133 } 137 }
134 } 138 }
135 139
136 void AudioRendererMixer::OnRenderError() { 140 void AudioRendererMixer::OnRenderError() {
137 base::AutoLock auto_lock(mixer_inputs_lock_); 141 base::AutoLock auto_lock(mixer_inputs_lock_);
138 142
139 // Call each mixer input and signal an error. 143 // Call each mixer input and signal an error.
140 for (AudioRendererMixerInputSet::iterator it = mixer_inputs_.begin(); 144 for (AudioRendererMixerInputSet::iterator it = mixer_inputs_.begin();
141 it != mixer_inputs_.end(); ++it) { 145 it != mixer_inputs_.end(); ++it) {
142 (*it)->callback()->OnRenderError(); 146 (*it)->callback()->OnRenderError();
143 } 147 }
144 } 148 }
145 149
150 void AudioRendererMixer::VectorFMAC(const float src[], float scale, int len,
151 float dest[]) {
152 // Rely on function level static initialization to keep VectorFMACProc
153 // selection thread safe.
154 typedef void (*VectorFMACProc)(const float src[], float scale, int len,
155 float dest[]);
156 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__)
157 static const VectorFMACProc kVectorFMACProc =
158 base::CPU().has_sse() ? VectorFMAC_SSE : VectorFMAC_C;
159 #else
160 static const VectorFMACProc kVectorFMACProc = VectorFMAC_C;
161 #endif
162
163 return kVectorFMACProc(src, scale, len, dest);
164 }
165
166 void AudioRendererMixer::VectorFMAC_C(const float src[], float scale, int len,
167 float dest[]) {
168 for (int i = 0; i < len; ++i)
169 dest[i] += src[i] * scale;
170 }
171
172 #if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__)
173 void AudioRendererMixer::VectorFMAC_SSE(const float src[], float scale, int len,
174 float dest[]) {
175 // Ensure |src| and |dest| are 16-byte aligned.
176 DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(src) & 0x0F);
177 DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(dest) & 0x0F);
178
179 __m128 m_scale = _mm_set_ps1(scale);
180 int rem = len % 4;
181 for (int i = 0; i < len - rem; i += 4) {
182 _mm_store_ps(dest + i, _mm_add_ps(_mm_load_ps(dest + i),
183 _mm_mul_ps(_mm_load_ps(src + i), m_scale)));
184 }
185
186 // Handle any remaining values that wouldn't fit in an SSE pass.
187 if (rem)
188 VectorFMAC_C(src + len - rem, scale, rem, dest + len - rem);
189 }
190 #endif
191
146 } // namespace media 192 } // namespace media
OLDNEW
« no previous file with comments | « media/base/audio_renderer_mixer.h ('k') | media/base/audio_renderer_mixer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698