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

Side by Side Diff: media/filters/audio_renderer_algorithm.cc

Issue 411683002: Remove muted_ and playback_rate_ from media::AudioRendererAlgorithm. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix cast Created 6 years, 5 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
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/filters/audio_renderer_algorithm.h" 5 #include "media/filters/audio_renderer_algorithm.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 24 matching lines...) Expand all
35 // 35 //
36 // 4) Update: 36 // 4) Update:
37 // |optimal_block_| = |transition_window_| * |target_block_| + 37 // |optimal_block_| = |transition_window_| * |target_block_| +
38 // (1 - |transition_window_|) * |optimal_block_|. 38 // (1 - |transition_window_|) * |optimal_block_|.
39 // 39 //
40 // 5) Overlap-and-add |optimal_block_| to the |wsola_output_|. 40 // 5) Overlap-and-add |optimal_block_| to the |wsola_output_|.
41 // 41 //
42 // 6) Update: 42 // 6) Update:
43 // |target_block_| = |optimal_index| + |ola_window_size_| / 2. 43 // |target_block_| = |optimal_index| + |ola_window_size_| / 2.
44 // |output_index_| = |output_index_| + |ola_window_size_| / 2, 44 // |output_index_| = |output_index_| + |ola_window_size_| / 2,
45 // |search_block_center_offset_| = |output_index_| * |playback_rate_|, and 45 // |search_block_center_offset_| = |output_index_| * |playback_rate|, and
46 // |search_block_index_| = |search_block_center_offset_| - 46 // |search_block_index_| = |search_block_center_offset_| -
47 // |search_block_center_offset_|. 47 // |search_block_center_offset_|.
48 48
49 // Max/min supported playback rates for fast/slow audio. Audio outside of these 49 // Max/min supported playback rates for fast/slow audio. Audio outside of these
50 // ranges are muted. 50 // ranges are muted.
51 // Audio at these speeds would sound better under a frequency domain algorithm. 51 // Audio at these speeds would sound better under a frequency domain algorithm.
52 static const float kMinPlaybackRate = 0.5f; 52 static const float kMinPlaybackRate = 0.5f;
53 static const float kMaxPlaybackRate = 4.0f; 53 static const float kMaxPlaybackRate = 4.0f;
54 54
55 // Overlap-and-add window size in milliseconds. 55 // Overlap-and-add window size in milliseconds.
56 static const int kOlaWindowSizeMs = 20; 56 static const int kOlaWindowSizeMs = 20;
57 57
58 // Size of search interval in milliseconds. The search interval is 58 // Size of search interval in milliseconds. The search interval is
59 // [-delta delta] around |output_index_| * |playback_rate_|. So the search 59 // [-delta delta] around |output_index_| * |playback_rate|. So the search
60 // interval is 2 * delta. 60 // interval is 2 * delta.
61 static const int kWsolaSearchIntervalMs = 30; 61 static const int kWsolaSearchIntervalMs = 30;
62 62
63 // The maximum size in seconds for the |audio_buffer_|. Arbitrarily determined. 63 // The maximum size in seconds for the |audio_buffer_|. Arbitrarily determined.
64 static const int kMaxCapacityInSeconds = 3; 64 static const int kMaxCapacityInSeconds = 3;
65 65
66 // The starting size in frames for |audio_buffer_|. Previous usage maintained a 66 // The starting size in frames for |audio_buffer_|. Previous usage maintained a
67 // queue of 16 AudioBuffers, each of 512 frames. This worked well, so we 67 // queue of 16 AudioBuffers, each of 512 frames. This worked well, so we
68 // maintain this number of frames. 68 // maintain this number of frames.
69 static const int kStartingBufferSizeInFrames = 16 * 512; 69 static const int kStartingBufferSizeInFrames = 16 * 512;
70 70
71 COMPILE_ASSERT(kStartingBufferSizeInFrames < 71 COMPILE_ASSERT(kStartingBufferSizeInFrames <
72 (kMaxCapacityInSeconds * limits::kMinSampleRate), 72 (kMaxCapacityInSeconds * limits::kMinSampleRate),
73 max_capacity_smaller_than_starting_buffer_size); 73 max_capacity_smaller_than_starting_buffer_size);
74 74
75 AudioRendererAlgorithm::AudioRendererAlgorithm() 75 AudioRendererAlgorithm::AudioRendererAlgorithm()
76 : channels_(0), 76 : channels_(0),
77 samples_per_second_(0), 77 samples_per_second_(0),
78 playback_rate_(0),
79 muted_(false),
80 muted_partial_frame_(0), 78 muted_partial_frame_(0),
81 capacity_(kStartingBufferSizeInFrames), 79 capacity_(kStartingBufferSizeInFrames),
82 output_time_(0.0), 80 output_time_(0.0),
83 search_block_center_offset_(0), 81 search_block_center_offset_(0),
84 search_block_index_(0), 82 search_block_index_(0),
85 num_candidate_blocks_(0), 83 num_candidate_blocks_(0),
86 target_block_index_(0), 84 target_block_index_(0),
87 ola_window_size_(0), 85 ola_window_size_(0),
88 ola_hop_size_(0), 86 ola_hop_size_(0),
89 num_complete_frames_(0) { 87 num_complete_frames_(0) {
90 } 88 }
91 89
92 AudioRendererAlgorithm::~AudioRendererAlgorithm() {} 90 AudioRendererAlgorithm::~AudioRendererAlgorithm() {}
93 91
94 void AudioRendererAlgorithm::Initialize(float initial_playback_rate, 92 void AudioRendererAlgorithm::Initialize(const AudioParameters& params) {
95 const AudioParameters& params) {
96 CHECK(params.IsValid()); 93 CHECK(params.IsValid());
97 94
98 channels_ = params.channels(); 95 channels_ = params.channels();
99 samples_per_second_ = params.sample_rate(); 96 samples_per_second_ = params.sample_rate();
100 SetPlaybackRate(initial_playback_rate);
101 num_candidate_blocks_ = (kWsolaSearchIntervalMs * samples_per_second_) / 1000; 97 num_candidate_blocks_ = (kWsolaSearchIntervalMs * samples_per_second_) / 1000;
102 ola_window_size_ = kOlaWindowSizeMs * samples_per_second_ / 1000; 98 ola_window_size_ = kOlaWindowSizeMs * samples_per_second_ / 1000;
103 99
104 // Make sure window size in an even number. 100 // Make sure window size in an even number.
105 ola_window_size_ += ola_window_size_ & 1; 101 ola_window_size_ += ola_window_size_ & 1;
106 ola_hop_size_ = ola_window_size_ / 2; 102 ola_hop_size_ = ola_window_size_ / 2;
107 103
108 // |num_candidate_blocks_| / 2 is the offset of the center of the search 104 // |num_candidate_blocks_| / 2 is the offset of the center of the search
109 // block to the center of the first (left most) candidate block. The offset 105 // block to the center of the first (left most) candidate block. The offset
110 // of the center of a candidate block to its left most point is 106 // of the center of a candidate block to its left most point is
(...skipping 27 matching lines...) Expand all
138 wsola_output_ = AudioBus::Create(channels_, ola_window_size_ + ola_hop_size_); 134 wsola_output_ = AudioBus::Create(channels_, ola_window_size_ + ola_hop_size_);
139 wsola_output_->Zero(); // Initialize for overlap-and-add of the first block. 135 wsola_output_->Zero(); // Initialize for overlap-and-add of the first block.
140 136
141 // Auxiliary containers. 137 // Auxiliary containers.
142 optimal_block_ = AudioBus::Create(channels_, ola_window_size_); 138 optimal_block_ = AudioBus::Create(channels_, ola_window_size_);
143 search_block_ = AudioBus::Create( 139 search_block_ = AudioBus::Create(
144 channels_, num_candidate_blocks_ + (ola_window_size_ - 1)); 140 channels_, num_candidate_blocks_ + (ola_window_size_ - 1));
145 target_block_ = AudioBus::Create(channels_, ola_window_size_); 141 target_block_ = AudioBus::Create(channels_, ola_window_size_);
146 } 142 }
147 143
148 int AudioRendererAlgorithm::FillBuffer(AudioBus* dest, int requested_frames) { 144 int AudioRendererAlgorithm::FillBuffer(AudioBus* dest,
149 if (playback_rate_ == 0) 145 int requested_frames,
146 float playback_rate) {
147 if (playback_rate == 0)
150 return 0; 148 return 0;
151 149
152 DCHECK_EQ(channels_, dest->channels()); 150 DCHECK_EQ(channels_, dest->channels());
153 151
154 // Optimize the |muted_| case to issue a single clear instead of performing 152 // Optimize the muted case to issue a single clear instead of performing
155 // the full crossfade and clearing each crossfaded frame. 153 // the full crossfade and clearing each crossfaded frame.
156 if (muted_) { 154 if (playback_rate < kMinPlaybackRate || playback_rate > kMaxPlaybackRate) {
157 int frames_to_render = 155 int frames_to_render =
158 std::min(static_cast<int>(audio_buffer_.frames() / playback_rate_), 156 std::min(static_cast<int>(audio_buffer_.frames() / playback_rate),
159 requested_frames); 157 requested_frames);
160 158
161 // Compute accurate number of frames to actually skip in the source data. 159 // Compute accurate number of frames to actually skip in the source data.
162 // Includes the leftover partial frame from last request. However, we can 160 // Includes the leftover partial frame from last request. However, we can
163 // only skip over complete frames, so a partial frame may remain for next 161 // only skip over complete frames, so a partial frame may remain for next
164 // time. 162 // time.
165 muted_partial_frame_ += frames_to_render * playback_rate_; 163 muted_partial_frame_ += frames_to_render * playback_rate;
166 int seek_frames = static_cast<int>(muted_partial_frame_); 164 int seek_frames = static_cast<int>(muted_partial_frame_);
167 dest->ZeroFrames(frames_to_render); 165 dest->ZeroFrames(frames_to_render);
168 audio_buffer_.SeekFrames(seek_frames); 166 audio_buffer_.SeekFrames(seek_frames);
169 167
170 // Determine the partial frame that remains to be skipped for next call. If 168 // Determine the partial frame that remains to be skipped for next call. If
171 // the user switches back to playing, it may be off time by this partial 169 // the user switches back to playing, it may be off time by this partial
172 // frame, which would be undetectable. If they subsequently switch to 170 // frame, which would be undetectable. If they subsequently switch to
173 // another playback rate that mutes, the code will attempt to line up the 171 // another playback rate that mutes, the code will attempt to line up the
174 // frames again. 172 // frames again.
175 muted_partial_frame_ -= seek_frames; 173 muted_partial_frame_ -= seek_frames;
176 return frames_to_render; 174 return frames_to_render;
177 } 175 }
178 176
179 int slower_step = ceil(ola_window_size_ * playback_rate_); 177 int slower_step = ceil(ola_window_size_ * playback_rate);
180 int faster_step = ceil(ola_window_size_ / playback_rate_); 178 int faster_step = ceil(ola_window_size_ / playback_rate);
181 179
182 // Optimize the most common |playback_rate_| ~= 1 case to use a single copy 180 // Optimize the most common |playback_rate| ~= 1 case to use a single copy
183 // instead of copying frame by frame. 181 // instead of copying frame by frame.
184 if (ola_window_size_ <= faster_step && slower_step >= ola_window_size_) { 182 if (ola_window_size_ <= faster_step && slower_step >= ola_window_size_) {
185 const int frames_to_copy = 183 const int frames_to_copy =
186 std::min(audio_buffer_.frames(), requested_frames); 184 std::min(audio_buffer_.frames(), requested_frames);
187 const int frames_read = audio_buffer_.ReadFrames(frames_to_copy, 0, dest); 185 const int frames_read = audio_buffer_.ReadFrames(frames_to_copy, 0, dest);
188 DCHECK_EQ(frames_read, frames_to_copy); 186 DCHECK_EQ(frames_read, frames_to_copy);
189 return frames_read; 187 return frames_read;
190 } 188 }
191 189
192 int rendered_frames = 0; 190 int rendered_frames = 0;
193 do { 191 do {
194 rendered_frames += WriteCompletedFramesTo( 192 rendered_frames += WriteCompletedFramesTo(
195 requested_frames - rendered_frames, rendered_frames, dest); 193 requested_frames - rendered_frames, rendered_frames, dest);
196 } while (rendered_frames < requested_frames && RunOneWsolaIteration()); 194 } while (rendered_frames < requested_frames &&
195 RunOneWsolaIteration(playback_rate));
197 return rendered_frames; 196 return rendered_frames;
198 } 197 }
199 198
200 void AudioRendererAlgorithm::SetPlaybackRate(float new_rate) {
201 DCHECK_GE(new_rate, 0);
202 playback_rate_ = new_rate;
203 muted_ =
204 playback_rate_ < kMinPlaybackRate || playback_rate_ > kMaxPlaybackRate;
205 }
206
207 void AudioRendererAlgorithm::FlushBuffers() { 199 void AudioRendererAlgorithm::FlushBuffers() {
208 // Clear the queue of decoded packets (releasing the buffers). 200 // Clear the queue of decoded packets (releasing the buffers).
209 audio_buffer_.Clear(); 201 audio_buffer_.Clear();
210 output_time_ = 0.0; 202 output_time_ = 0.0;
211 search_block_index_ = 0; 203 search_block_index_ = 0;
212 target_block_index_ = 0; 204 target_block_index_ = 0;
213 wsola_output_->Zero(); 205 wsola_output_->Zero();
214 num_complete_frames_ = 0; 206 num_complete_frames_ = 0;
215 207
216 // Reset |capacity_| so growth triggered by underflows doesn't penalize 208 // Reset |capacity_| so growth triggered by underflows doesn't penalize
(...skipping 22 matching lines...) Expand all
239 capacity_ = std::min(2 * capacity_, max_capacity); 231 capacity_ = std::min(2 * capacity_, max_capacity);
240 } 232 }
241 233
242 bool AudioRendererAlgorithm::CanPerformWsola() const { 234 bool AudioRendererAlgorithm::CanPerformWsola() const {
243 const int search_block_size = num_candidate_blocks_ + (ola_window_size_ - 1); 235 const int search_block_size = num_candidate_blocks_ + (ola_window_size_ - 1);
244 const int frames = audio_buffer_.frames(); 236 const int frames = audio_buffer_.frames();
245 return target_block_index_ + ola_window_size_ <= frames && 237 return target_block_index_ + ola_window_size_ <= frames &&
246 search_block_index_ + search_block_size <= frames; 238 search_block_index_ + search_block_size <= frames;
247 } 239 }
248 240
249 bool AudioRendererAlgorithm::RunOneWsolaIteration() { 241 bool AudioRendererAlgorithm::RunOneWsolaIteration(float playback_rate) {
250 if (!CanPerformWsola()) 242 if (!CanPerformWsola())
251 return false; 243 return false;
252 244
253 GetOptimalBlock(); 245 GetOptimalBlock();
254 246
255 // Overlap-and-add. 247 // Overlap-and-add.
256 for (int k = 0; k < channels_; ++k) { 248 for (int k = 0; k < channels_; ++k) {
257 const float* const ch_opt_frame = optimal_block_->channel(k); 249 const float* const ch_opt_frame = optimal_block_->channel(k);
258 float* ch_output = wsola_output_->channel(k) + num_complete_frames_; 250 float* ch_output = wsola_output_->channel(k) + num_complete_frames_;
259 for (int n = 0; n < ola_hop_size_; ++n) { 251 for (int n = 0; n < ola_hop_size_; ++n) {
260 ch_output[n] = ch_output[n] * ola_window_[ola_hop_size_ + n] + 252 ch_output[n] = ch_output[n] * ola_window_[ola_hop_size_ + n] +
261 ch_opt_frame[n] * ola_window_[n]; 253 ch_opt_frame[n] * ola_window_[n];
262 } 254 }
263 255
264 // Copy the second half to the output. 256 // Copy the second half to the output.
265 memcpy(&ch_output[ola_hop_size_], &ch_opt_frame[ola_hop_size_], 257 memcpy(&ch_output[ola_hop_size_], &ch_opt_frame[ola_hop_size_],
266 sizeof(*ch_opt_frame) * ola_hop_size_); 258 sizeof(*ch_opt_frame) * ola_hop_size_);
267 } 259 }
268 260
269 num_complete_frames_ += ola_hop_size_; 261 num_complete_frames_ += ola_hop_size_;
270 UpdateOutputTime(ola_hop_size_); 262 UpdateOutputTime(playback_rate, ola_hop_size_);
271 RemoveOldInputFrames(); 263 RemoveOldInputFrames(playback_rate);
272 return true; 264 return true;
273 } 265 }
274 266
275 void AudioRendererAlgorithm::UpdateOutputTime(double time_change) { 267 void AudioRendererAlgorithm::UpdateOutputTime(float playback_rate,
268 double time_change) {
276 output_time_ += time_change; 269 output_time_ += time_change;
277 // Center of the search region, in frames. 270 // Center of the search region, in frames.
278 const int search_block_center_index = static_cast<int>( 271 const int search_block_center_index = static_cast<int>(
279 output_time_ * playback_rate_ + 0.5); 272 output_time_ * playback_rate + 0.5);
280 search_block_index_ = search_block_center_index - search_block_center_offset_; 273 search_block_index_ = search_block_center_index - search_block_center_offset_;
281 } 274 }
282 275
283 void AudioRendererAlgorithm::RemoveOldInputFrames() { 276 void AudioRendererAlgorithm::RemoveOldInputFrames(float playback_rate) {
284 const int earliest_used_index = std::min(target_block_index_, 277 const int earliest_used_index = std::min(target_block_index_,
285 search_block_index_); 278 search_block_index_);
286 if (earliest_used_index <= 0) 279 if (earliest_used_index <= 0)
287 return; // Nothing to remove. 280 return; // Nothing to remove.
288 281
289 // Remove frames from input and adjust indices accordingly. 282 // Remove frames from input and adjust indices accordingly.
290 audio_buffer_.SeekFrames(earliest_used_index); 283 audio_buffer_.SeekFrames(earliest_used_index);
291 target_block_index_ -= earliest_used_index; 284 target_block_index_ -= earliest_used_index;
292 285
293 // Adjust output index. 286 // Adjust output index.
294 double output_time_change = static_cast<double>(earliest_used_index) / 287 double output_time_change = static_cast<double>(earliest_used_index) /
295 playback_rate_; 288 playback_rate;
296 CHECK_GE(output_time_, output_time_change); 289 CHECK_GE(output_time_, output_time_change);
297 UpdateOutputTime(-output_time_change); 290 UpdateOutputTime(playback_rate, -output_time_change);
298 } 291 }
299 292
300 int AudioRendererAlgorithm::WriteCompletedFramesTo( 293 int AudioRendererAlgorithm::WriteCompletedFramesTo(
301 int requested_frames, int dest_offset, AudioBus* dest) { 294 int requested_frames, int dest_offset, AudioBus* dest) {
302 int rendered_frames = std::min(num_complete_frames_, requested_frames); 295 int rendered_frames = std::min(num_complete_frames_, requested_frames);
303 296
304 if (rendered_frames == 0) 297 if (rendered_frames == 0)
305 return 0; // There is nothing to read from |wsola_output_|, return. 298 return 0; // There is nothing to read from |wsola_output_|, return.
306 299
307 wsola_output_->CopyPartialFramesTo(0, rendered_frames, dest_offset, dest); 300 wsola_output_->CopyPartialFramesTo(0, rendered_frames, dest_offset, dest);
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
387 read_offset_frames = 0; 380 read_offset_frames = 0;
388 num_frames_to_read -= num_zero_frames_appended; 381 num_frames_to_read -= num_zero_frames_appended;
389 write_offset = num_zero_frames_appended; 382 write_offset = num_zero_frames_appended;
390 dest->ZeroFrames(num_zero_frames_appended); 383 dest->ZeroFrames(num_zero_frames_appended);
391 } 384 }
392 audio_buffer_.PeekFrames(num_frames_to_read, read_offset_frames, 385 audio_buffer_.PeekFrames(num_frames_to_read, read_offset_frames,
393 write_offset, dest); 386 write_offset, dest);
394 } 387 }
395 388
396 } // namespace media 389 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/audio_renderer_algorithm.h ('k') | media/filters/audio_renderer_algorithm_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698