| 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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |