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

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

Powered by Google App Engine
This is Rietveld 408576698