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 |