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 3 // found in the LICENSE file. 4 5 #include "media/base/audio_splicer.h" 6 7 #include <cstdlib> 8 9 #include "base/logging.h" 10 #include "media/base/audio_buffer.h" 11 #include "media/base/audio_decoder_config.h" 12 #include "media/base/audio_timestamp_helper.h" 13 #include "media/base/buffers.h" 14 15 namespace media { 16 17 // Largest gap or overlap allowed by this class. Anything 18 // larger than this will trigger an error. 19 // This is an arbitrary value, but the initial selection of 50ms 20 // roughly represents the duration of 2 compressed AAC or MP3 frames. 21 static const int kMaxTimeDeltaInMilliseconds = 50; 22 AudioSplicer(int samples_per_second)23AudioSplicer::AudioSplicer(int samples_per_second) 24 : output_timestamp_helper_(samples_per_second), 25 min_gap_size_(2), 26 received_end_of_stream_(false) { 27 } 28 ~AudioSplicer()29AudioSplicer::~AudioSplicer() { 30 } 31 Reset()32void AudioSplicer::Reset() { 33 output_timestamp_helper_.SetBaseTimestamp(kNoTimestamp()); 34 output_buffers_.clear(); 35 received_end_of_stream_ = false; 36 } 37 AddInput(const scoped_refptr<AudioBuffer> & input)38bool AudioSplicer::AddInput(const scoped_refptr<AudioBuffer>& input) { 39 DCHECK(!received_end_of_stream_ || input->end_of_stream()); 40 41 if (input->end_of_stream()) { 42 output_buffers_.push_back(input); 43 received_end_of_stream_ = true; 44 return true; 45 } 46 47 DCHECK(input->timestamp() != kNoTimestamp()); 48 DCHECK(input->duration() > base::TimeDelta()); 49 DCHECK_GT(input->frame_count(), 0); 50 51 if (output_timestamp_helper_.base_timestamp() == kNoTimestamp()) 52 output_timestamp_helper_.SetBaseTimestamp(input->timestamp()); 53 54 if (output_timestamp_helper_.base_timestamp() > input->timestamp()) { 55 DVLOG(1) << "Input timestamp is before the base timestamp."; 56 return false; 57 } 58 59 base::TimeDelta timestamp = input->timestamp(); 60 base::TimeDelta expected_timestamp = output_timestamp_helper_.GetTimestamp(); 61 base::TimeDelta delta = timestamp - expected_timestamp; 62 63 if (std::abs(delta.InMilliseconds()) > kMaxTimeDeltaInMilliseconds) { 64 DVLOG(1) << "Timestamp delta too large: " << delta.InMicroseconds() << "us"; 65 return false; 66 } 67 68 int frames_to_fill = 0; 69 if (delta != base::TimeDelta()) 70 frames_to_fill = output_timestamp_helper_.GetFramesToTarget(timestamp); 71 72 if (frames_to_fill == 0 || std::abs(frames_to_fill) < min_gap_size_) { 73 AddOutputBuffer(input); 74 return true; 75 } 76 77 if (frames_to_fill > 0) { 78 DVLOG(1) << "Gap detected @ " << expected_timestamp.InMicroseconds() 79 << " us: " << delta.InMicroseconds() << " us"; 80 81 // Create a buffer with enough silence samples to fill the gap and 82 // add it to the output buffer. 83 scoped_refptr<AudioBuffer> gap = AudioBuffer::CreateEmptyBuffer( 84 input->channel_count(), 85 frames_to_fill, 86 expected_timestamp, 87 output_timestamp_helper_.GetFrameDuration(frames_to_fill)); 88 AddOutputBuffer(gap); 89 90 // Add the input buffer now that the gap has been filled. 91 AddOutputBuffer(input); 92 return true; 93 } 94 95 int frames_to_skip = -frames_to_fill; 96 97 DVLOG(1) << "Overlap detected @ " << expected_timestamp.InMicroseconds() 98 << " us: " << -delta.InMicroseconds() << " us"; 99 100 if (input->frame_count() <= frames_to_skip) { 101 DVLOG(1) << "Dropping whole buffer"; 102 return true; 103 } 104 105 // Copy the trailing samples that do not overlap samples already output 106 // into a new buffer. Add this new buffer to the output queue. 107 // 108 // TODO(acolwell): Implement a cross-fade here so the transition is less 109 // jarring. 110 input->TrimStart(frames_to_skip); 111 AddOutputBuffer(input); 112 return true; 113 } 114 HasNextBuffer() const115bool AudioSplicer::HasNextBuffer() const { 116 return !output_buffers_.empty(); 117 } 118 GetNextBuffer()119scoped_refptr<AudioBuffer> AudioSplicer::GetNextBuffer() { 120 scoped_refptr<AudioBuffer> ret = output_buffers_.front(); 121 output_buffers_.pop_front(); 122 return ret; 123 } 124 AddOutputBuffer(const scoped_refptr<AudioBuffer> & buffer)125void AudioSplicer::AddOutputBuffer(const scoped_refptr<AudioBuffer>& buffer) { 126 output_timestamp_helper_.AddFrames(buffer->frame_count()); 127 output_buffers_.push_back(buffer); 128 } 129 130 } // namespace media 131