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 |