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

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

Issue 240123004: Simplify AudioSplicer logic which slots buffers before or after a splice point. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Docs. Created 6 years, 8 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/base/audio_splicer.h" 5 #include "media/base/audio_splicer.h"
6 6
7 #include <cstdlib> 7 #include <cstdlib>
8 #include <deque> 8 #include <deque>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 // Returns true if the sanitizer has a buffer to return. 84 // Returns true if the sanitizer has a buffer to return.
85 bool HasNextBuffer() const; 85 bool HasNextBuffer() const;
86 86
87 // Removes the next buffer from the output buffer queue and returns it; should 87 // Removes the next buffer from the output buffer queue and returns it; should
88 // only be called if HasNextBuffer() returns true. 88 // only be called if HasNextBuffer() returns true.
89 scoped_refptr<AudioBuffer> GetNextBuffer(); 89 scoped_refptr<AudioBuffer> GetNextBuffer();
90 90
91 // Returns the total frame count of all buffers available for output. 91 // Returns the total frame count of all buffers available for output.
92 int GetFrameCount() const; 92 int GetFrameCount() const;
93 93
94 // Returns the duration of all buffers added to the output queue thus far.
95 base::TimeDelta GetDuration() const;
96
97 const AudioTimestampHelper& timestamp_helper() { 94 const AudioTimestampHelper& timestamp_helper() {
98 return output_timestamp_helper_; 95 return output_timestamp_helper_;
99 } 96 }
100 97
101 // Transfer all buffers into |output|. Returns false if AddInput() on the 98 // Transfer all buffers into |output|. Returns false if AddInput() on the
102 // |output| sanitizer fails for any buffer removed from |this|. 99 // |output| sanitizer fails for any buffer removed from |this|.
103 bool DrainInto(AudioStreamSanitizer* output); 100 bool DrainInto(AudioStreamSanitizer* output);
104 101
105 private: 102 private:
106 void AddOutputBuffer(const scoped_refptr<AudioBuffer>& buffer); 103 void AddOutputBuffer(const scoped_refptr<AudioBuffer>& buffer);
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 233
237 int AudioStreamSanitizer::GetFrameCount() const { 234 int AudioStreamSanitizer::GetFrameCount() const {
238 int frame_count = 0; 235 int frame_count = 0;
239 for (BufferQueue::const_iterator it = output_buffers_.begin(); 236 for (BufferQueue::const_iterator it = output_buffers_.begin();
240 it != output_buffers_.end(); ++it) { 237 it != output_buffers_.end(); ++it) {
241 frame_count += (*it)->frame_count(); 238 frame_count += (*it)->frame_count();
242 } 239 }
243 return frame_count; 240 return frame_count;
244 } 241 }
245 242
246 base::TimeDelta AudioStreamSanitizer::GetDuration() const {
247 DCHECK(output_timestamp_helper_.base_timestamp() != kNoTimestamp());
248 return output_timestamp_helper_.GetTimestamp() -
249 output_timestamp_helper_.base_timestamp();
250 }
251
252 bool AudioStreamSanitizer::DrainInto(AudioStreamSanitizer* output) { 243 bool AudioStreamSanitizer::DrainInto(AudioStreamSanitizer* output) {
253 while (HasNextBuffer()) { 244 while (HasNextBuffer()) {
254 if (!output->AddInput(GetNextBuffer())) 245 if (!output->AddInput(GetNextBuffer()))
255 return false; 246 return false;
256 } 247 }
257 return true; 248 return true;
258 } 249 }
259 250
260 AudioSplicer::AudioSplicer(int samples_per_second) 251 AudioSplicer::AudioSplicer(int samples_per_second)
261 : max_crossfade_duration_( 252 : max_crossfade_duration_(
262 base::TimeDelta::FromMilliseconds(kCrossfadeDurationInMilliseconds)), 253 base::TimeDelta::FromMilliseconds(kCrossfadeDurationInMilliseconds)),
263 splice_timestamp_(kNoTimestamp()), 254 splice_timestamp_(kNoTimestamp()),
264 max_splice_end_timestamp_(kNoTimestamp()), 255 max_splice_end_timestamp_(kNoTimestamp()),
265 output_sanitizer_(new AudioStreamSanitizer(samples_per_second)), 256 output_sanitizer_(new AudioStreamSanitizer(samples_per_second)),
266 pre_splice_sanitizer_(new AudioStreamSanitizer(samples_per_second)), 257 pre_splice_sanitizer_(new AudioStreamSanitizer(samples_per_second)),
267 post_splice_sanitizer_(new AudioStreamSanitizer(samples_per_second)) {} 258 post_splice_sanitizer_(new AudioStreamSanitizer(samples_per_second)),
259 have_all_pre_splice_buffers_(false) {}
268 260
269 AudioSplicer::~AudioSplicer() {} 261 AudioSplicer::~AudioSplicer() {}
270 262
271 void AudioSplicer::Reset() { 263 void AudioSplicer::Reset() {
272 output_sanitizer_->Reset(); 264 output_sanitizer_->Reset();
273 pre_splice_sanitizer_->Reset(); 265 pre_splice_sanitizer_->Reset();
274 post_splice_sanitizer_->Reset(); 266 post_splice_sanitizer_->Reset();
267 have_all_pre_splice_buffers_ = false;
275 reset_splice_timestamps(); 268 reset_splice_timestamps();
276 } 269 }
277 270
278 bool AudioSplicer::AddInput(const scoped_refptr<AudioBuffer>& input) { 271 bool AudioSplicer::AddInput(const scoped_refptr<AudioBuffer>& input) {
279 // If we're not processing a splice, add the input to the output queue. 272 // If we're not processing a splice, add the input to the output queue.
280 if (splice_timestamp_ == kNoTimestamp()) { 273 if (splice_timestamp_ == kNoTimestamp()) {
281 DCHECK(!pre_splice_sanitizer_->HasNextBuffer()); 274 DCHECK(!pre_splice_sanitizer_->HasNextBuffer());
282 DCHECK(!post_splice_sanitizer_->HasNextBuffer()); 275 DCHECK(!post_splice_sanitizer_->HasNextBuffer());
283 return output_sanitizer_->AddInput(input); 276 return output_sanitizer_->AddInput(input);
284 } 277 }
285 278
286 const AudioTimestampHelper& output_ts_helper = 279 const AudioTimestampHelper& output_ts_helper =
287 output_sanitizer_->timestamp_helper(); 280 output_sanitizer_->timestamp_helper();
288 281
289 if (!post_splice_sanitizer_->HasNextBuffer()) { 282 if (!have_all_pre_splice_buffers_) {
290 // Due to inaccurate demuxer timestamps a splice may have been incorrectly 283 DCHECK(!input->end_of_stream());
291 // marked such that the "pre splice buffers" were all entirely before the
292 // splice point. Here we check for end of stream or buffers which couldn't
293 // possibly be part of the splice.
294 if (input->end_of_stream() ||
295 input->timestamp() >= max_splice_end_timestamp_) {
296 CHECK(pre_splice_sanitizer_->DrainInto(output_sanitizer_.get()));
297 reset_splice_timestamps();
298 return output_sanitizer_->AddInput(input);
299 }
300 284
301 // If the provided buffer is entirely before the splice point it can also be 285 // If the provided buffer is entirely before the splice point it can also be
302 // added to the output queue. 286 // added to the output queue.
303 if (input->timestamp() + input->duration() < splice_timestamp_) { 287 if (input->timestamp() + input->duration() < splice_timestamp_) {
304 DCHECK(!pre_splice_sanitizer_->HasNextBuffer()); 288 DCHECK(!pre_splice_sanitizer_->HasNextBuffer());
305 return output_sanitizer_->AddInput(input); 289 return output_sanitizer_->AddInput(input);
306 } 290 }
307 291
308 // If we've encountered the first pre splice buffer, reset the pre splice 292 // If we've encountered the first pre splice buffer, reset the pre splice
309 // sanitizer based on |output_sanitizer_|. This is done so that gaps and 293 // sanitizer based on |output_sanitizer_|. This is done so that gaps and
310 // overlaps between buffers across the sanitizers are accounted for prior 294 // overlaps between buffers across the sanitizers are accounted for prior
311 // to calculating crossfade. 295 // to calculating crossfade.
312 if (!pre_splice_sanitizer_->HasNextBuffer()) { 296 if (!pre_splice_sanitizer_->HasNextBuffer()) {
313 pre_splice_sanitizer_->ResetTimestampState( 297 pre_splice_sanitizer_->ResetTimestampState(
314 output_ts_helper.frame_count(), output_ts_helper.base_timestamp()); 298 output_ts_helper.frame_count(), output_ts_helper.base_timestamp());
315 } 299 }
316 300
317 // The first overlapping buffer is expected to have a timestamp of exactly 301 return pre_splice_sanitizer_->AddInput(input);
318 // |splice_timestamp_|. Until that timestamp is seen, all buffers go into 302 }
319 // |pre_splice_sanitizer_|.
320 if (!pre_splice_sanitizer_->HasNextBuffer() ||
321 input->timestamp() != splice_timestamp_) {
322 return pre_splice_sanitizer_->AddInput(input);
323 }
324 303
325 // We've received the first overlapping buffer. 304 // The first post splice buffer is expected to match |splice_timestamp_|.
326 } else if (!input->end_of_stream() && 305 if (!post_splice_sanitizer_->HasNextBuffer())
327 input->timestamp() == splice_timestamp_) { 306 DCHECK(splice_timestamp_ == input->timestamp());
328 // In this case we accidentally put a pre splice buffer in the post splice
329 // sanitizer, so we need to recover by transferring all current post splice
330 // buffers into the pre splice sanitizer and continuing with the splice.
331 post_splice_sanitizer_->DrainInto(pre_splice_sanitizer_.get());
332 post_splice_sanitizer_->Reset();
333 }
334 307
335 // At this point we have all the fade out preroll buffers from the decoder. 308 // At this point we have all the fade out preroll buffers from the decoder.
336 // We now need to wait until we have enough data to perform the crossfade (or 309 // We now need to wait until we have enough data to perform the crossfade (or
337 // we receive an end of stream). 310 // we receive an end of stream).
338 if (!post_splice_sanitizer_->AddInput(input)) 311 if (!post_splice_sanitizer_->AddInput(input))
339 return false; 312 return false;
340 313
341 // Ensure |output_sanitizer_| has a valid base timestamp so we can use it for 314 // Ensure |output_sanitizer_| has a valid base timestamp so we can use it for
342 // timestamp calculations. 315 // timestamp calculations.
343 if (output_ts_helper.base_timestamp() == kNoTimestamp()) { 316 if (output_ts_helper.base_timestamp() == kNoTimestamp()) {
344 output_sanitizer_->ResetTimestampState( 317 output_sanitizer_->ResetTimestampState(
345 0, pre_splice_sanitizer_->timestamp_helper().base_timestamp()); 318 0, pre_splice_sanitizer_->timestamp_helper().base_timestamp());
346 } 319 }
347 320
348 // If a splice frame was incorrectly marked due to poor demuxed timestamps, we 321 // If a splice frame was incorrectly marked due to poor demuxed timestamps, we
349 // may not actually have a splice. Here we check if any frames exist before 322 // may not actually have a splice. Here we check if any frames exist before
350 // the splice. In this case, just transfer all data to the output sanitizer. 323 // the splice. In this case, just transfer all data to the output sanitizer.
351 if (pre_splice_sanitizer_->GetFrameCount() <= 324 if (pre_splice_sanitizer_->GetFrameCount() <=
352 output_ts_helper.GetFramesToTarget(splice_timestamp_)) { 325 output_ts_helper.GetFramesToTarget(splice_timestamp_)) {
353 CHECK(pre_splice_sanitizer_->DrainInto(output_sanitizer_.get())); 326 CHECK(pre_splice_sanitizer_->DrainInto(output_sanitizer_.get()));
354 CHECK(post_splice_sanitizer_->DrainInto(output_sanitizer_.get())); 327 CHECK(post_splice_sanitizer_->DrainInto(output_sanitizer_.get()));
355 reset_splice_timestamps(); 328 reset_splice_timestamps();
356 return true; 329 return true;
357 } 330 }
358 331
359 // Since it's possible that a pre splice buffer after the first might have its 332 // Wait until we have enough data to crossfade or end of stream.
360 // timestamp fuzzed to be |splice_timestamp_| we need to always wait until we 333 if (!input->end_of_stream() &&
361 // have seen all possible post splice buffers to ensure we didn't mistakenly 334 input->timestamp() + input->duration() < max_splice_end_timestamp_) {
362 // put a pre splice buffer into the post splice sanitizer.
363 if (!input->end_of_stream() && input->timestamp() < max_splice_end_timestamp_)
364 return true; 335 return true;
336 }
365 337
366 scoped_refptr<AudioBuffer> crossfade_buffer; 338 scoped_refptr<AudioBuffer> crossfade_buffer;
367 scoped_ptr<AudioBus> pre_splice = 339 scoped_ptr<AudioBus> pre_splice =
368 ExtractCrossfadeFromPreSplice(&crossfade_buffer); 340 ExtractCrossfadeFromPreSplice(&crossfade_buffer);
369 341
370 // Crossfade the pre splice and post splice sections and transfer all relevant 342 // Crossfade the pre splice and post splice sections and transfer all relevant
371 // buffers into |output_sanitizer_|. 343 // buffers into |output_sanitizer_|.
372 CrossfadePostSplice(pre_splice.Pass(), crossfade_buffer); 344 CrossfadePostSplice(pre_splice.Pass(), crossfade_buffer);
373 345
374 // Clear the splice timestamp so new splices can be accepted. 346 // Clear the splice timestamp so new splices can be accepted.
375 reset_splice_timestamps(); 347 reset_splice_timestamps();
376 return true; 348 return true;
377 } 349 }
378 350
379 bool AudioSplicer::HasNextBuffer() const { 351 bool AudioSplicer::HasNextBuffer() const {
380 return output_sanitizer_->HasNextBuffer(); 352 return output_sanitizer_->HasNextBuffer();
381 } 353 }
382 354
383 scoped_refptr<AudioBuffer> AudioSplicer::GetNextBuffer() { 355 scoped_refptr<AudioBuffer> AudioSplicer::GetNextBuffer() {
384 return output_sanitizer_->GetNextBuffer(); 356 return output_sanitizer_->GetNextBuffer();
385 } 357 }
386 358
387 void AudioSplicer::SetSpliceTimestamp(base::TimeDelta splice_timestamp) { 359 void AudioSplicer::SetSpliceTimestamp(base::TimeDelta splice_timestamp) {
388 DCHECK(splice_timestamp != kNoTimestamp()); 360 if (splice_timestamp == kNoTimestamp()) {
361 DCHECK(splice_timestamp_ != kNoTimestamp());
362 DCHECK(!have_all_pre_splice_buffers_);
363 have_all_pre_splice_buffers_ = true;
364 return;
365 }
366
389 if (splice_timestamp_ == splice_timestamp) 367 if (splice_timestamp_ == splice_timestamp)
390 return; 368 return;
391 369
392 // TODO(dalecurtis): We may need the concept of a future_splice_timestamp_ to 370 // TODO(dalecurtis): We may need the concept of a future_splice_timestamp_ to
393 // handle cases where another splice comes in before we've received 5ms of 371 // handle cases where another splice comes in before we've received 5ms of
394 // data from the last one. Leave this as a CHECK for now to figure out if 372 // data from the last one. Leave this as a CHECK for now to figure out if
395 // this case is possible. 373 // this case is possible.
396 CHECK(splice_timestamp_ == kNoTimestamp()); 374 CHECK(splice_timestamp_ == kNoTimestamp());
397 splice_timestamp_ = splice_timestamp; 375 splice_timestamp_ = splice_timestamp;
398 max_splice_end_timestamp_ = splice_timestamp_ + max_crossfade_duration_; 376 max_splice_end_timestamp_ = splice_timestamp_ + max_crossfade_duration_;
399 pre_splice_sanitizer_->Reset(); 377 pre_splice_sanitizer_->Reset();
400 post_splice_sanitizer_->Reset(); 378 post_splice_sanitizer_->Reset();
379 have_all_pre_splice_buffers_ = false;
401 } 380 }
402 381
403 scoped_ptr<AudioBus> AudioSplicer::ExtractCrossfadeFromPreSplice( 382 scoped_ptr<AudioBus> AudioSplicer::ExtractCrossfadeFromPreSplice(
404 scoped_refptr<AudioBuffer>* crossfade_buffer) { 383 scoped_refptr<AudioBuffer>* crossfade_buffer) {
405 DCHECK(crossfade_buffer); 384 DCHECK(crossfade_buffer);
406 const AudioTimestampHelper& output_ts_helper = 385 const AudioTimestampHelper& output_ts_helper =
407 output_sanitizer_->timestamp_helper(); 386 output_sanitizer_->timestamp_helper();
408 387
409 int frames_before_splice = 388 int frames_before_splice =
410 output_ts_helper.GetFramesToTarget(splice_timestamp_); 389 output_ts_helper.GetFramesToTarget(splice_timestamp_);
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 AccurateTrimStart(frames_to_trim, remainder, output_ts_helper); 510 AccurateTrimStart(frames_to_trim, remainder, output_ts_helper);
532 CHECK(output_sanitizer_->AddInput(remainder)); 511 CHECK(output_sanitizer_->AddInput(remainder));
533 } 512 }
534 513
535 // Transfer all remaining buffers out and reset once empty. 514 // Transfer all remaining buffers out and reset once empty.
536 CHECK(post_splice_sanitizer_->DrainInto(output_sanitizer_.get())); 515 CHECK(post_splice_sanitizer_->DrainInto(output_sanitizer_.get()));
537 post_splice_sanitizer_->Reset(); 516 post_splice_sanitizer_->Reset();
538 } 517 }
539 518
540 } // namespace media 519 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698