audio_splicer.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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_decoder_config.h" 11#include "media/base/audio_timestamp_helper.h" 12#include "media/base/buffers.h" 13#include "media/base/data_buffer.h" 14 15namespace 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. 21static const int kMaxTimeDeltaInMilliseconds = 50; 22 23AudioSplicer::AudioSplicer(int bytes_per_frame, int samples_per_second) 24 : output_timestamp_helper_(bytes_per_frame, samples_per_second), 25 min_gap_size_(2 * bytes_per_frame), 26 received_end_of_stream_(false) { 27} 28 29AudioSplicer::~AudioSplicer() { 30} 31 32void AudioSplicer::Reset() { 33 output_timestamp_helper_.SetBaseTimestamp(kNoTimestamp()); 34 output_buffers_.clear(); 35 received_end_of_stream_ = false; 36} 37 38bool AudioSplicer::AddInput(const scoped_refptr<DataBuffer>& 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->data_size(), 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 bytes_to_fill = 0; 69 if (delta != base::TimeDelta()) 70 bytes_to_fill = output_timestamp_helper_.GetBytesToTarget(timestamp); 71 72 if (bytes_to_fill == 0 || std::abs(bytes_to_fill) < min_gap_size_) { 73 AddOutputBuffer(input); 74 return true; 75 } 76 77 if (bytes_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<DataBuffer> gap = new DataBuffer(bytes_to_fill); 84 gap->set_data_size(bytes_to_fill); 85 memset(gap->writable_data(), 0, bytes_to_fill); 86 gap->set_timestamp(expected_timestamp); 87 gap->set_duration(output_timestamp_helper_.GetDuration(bytes_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 bytes_to_skip = -bytes_to_fill; 96 97 DVLOG(1) << "Overlap detected @ " << expected_timestamp.InMicroseconds() 98 << " us: " << -delta.InMicroseconds() << " us"; 99 100 if (input->data_size() <= bytes_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 int new_buffer_size = input->data_size() - bytes_to_skip; 111 112 scoped_refptr<DataBuffer> new_buffer = new DataBuffer(new_buffer_size); 113 new_buffer->set_data_size(new_buffer_size); 114 memcpy(new_buffer->writable_data(), 115 input->data() + bytes_to_skip, 116 new_buffer_size); 117 new_buffer->set_timestamp(expected_timestamp); 118 new_buffer->set_duration( 119 output_timestamp_helper_.GetDuration(new_buffer_size)); 120 AddOutputBuffer(new_buffer); 121 return true; 122} 123 124bool AudioSplicer::HasNextBuffer() const { 125 return !output_buffers_.empty(); 126} 127 128scoped_refptr<DataBuffer> AudioSplicer::GetNextBuffer() { 129 scoped_refptr<DataBuffer> ret = output_buffers_.front(); 130 output_buffers_.pop_front(); 131 return ret; 132} 133 134void AudioSplicer::AddOutputBuffer(const scoped_refptr<DataBuffer>& buffer) { 135 output_timestamp_helper_.AddBytes(buffer->data_size()); 136 output_buffers_.push_back(buffer); 137} 138 139} // namespace media 140