| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |