audio_buffer_converter.cc revision 010d83a9304c5a91596085d917d248abff47903a
1// Copyright 2014 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_buffer_converter.h" 6 7#include <cmath> 8 9#include "base/logging.h" 10#include "media/base/audio_buffer.h" 11#include "media/base/audio_bus.h" 12#include "media/base/audio_decoder_config.h" 13#include "media/base/audio_timestamp_helper.h" 14#include "media/base/buffers.h" 15#include "media/base/sinc_resampler.h" 16#include "media/base/vector_math.h" 17 18namespace media { 19 20// Is the config presented by |buffer| a config change from |params|? 21static bool IsConfigChange(const AudioParameters& params, 22 const scoped_refptr<AudioBuffer>& buffer) { 23 return buffer->sample_rate() != params.sample_rate() || 24 buffer->channel_count() != params.channels() || 25 buffer->channel_layout() != params.channel_layout(); 26} 27 28AudioBufferConverter::AudioBufferConverter(const AudioParameters& output_params) 29 : output_params_(output_params), 30 input_params_(output_params), 31 last_input_buffer_offset_(0), 32 input_frames_(0), 33 buffered_input_frames_(0.0), 34 io_sample_rate_ratio_(1.0), 35 timestamp_helper_(output_params_.sample_rate()), 36 is_flushing_(false) {} 37 38AudioBufferConverter::~AudioBufferConverter() {} 39 40void AudioBufferConverter::AddInput(const scoped_refptr<AudioBuffer>& buffer) { 41 // On EOS flush any remaining buffered data. 42 if (buffer->end_of_stream()) { 43 Flush(); 44 queued_outputs_.push_back(buffer); 45 return; 46 } 47 48 // We'll need a new |audio_converter_| if there was a config change. 49 if (IsConfigChange(input_params_, buffer)) 50 ResetConverter(buffer); 51 52 // Pass straight through if there's no work to be done. 53 if (!audio_converter_) { 54 queued_outputs_.push_back(buffer); 55 return; 56 } 57 58 if (timestamp_helper_.base_timestamp() == kNoTimestamp()) 59 timestamp_helper_.SetBaseTimestamp(buffer->timestamp()); 60 61 queued_inputs_.push_back(buffer); 62 input_frames_ += buffer->frame_count(); 63 64 ConvertIfPossible(); 65} 66 67bool AudioBufferConverter::HasNextBuffer() { return !queued_outputs_.empty(); } 68 69scoped_refptr<AudioBuffer> AudioBufferConverter::GetNextBuffer() { 70 DCHECK(!queued_outputs_.empty()); 71 scoped_refptr<AudioBuffer> out = queued_outputs_.front(); 72 queued_outputs_.pop_front(); 73 return out; 74} 75 76void AudioBufferConverter::Reset() { 77 audio_converter_.reset(); 78 queued_inputs_.clear(); 79 queued_outputs_.clear(); 80 timestamp_helper_.SetBaseTimestamp(kNoTimestamp()); 81 input_params_ = output_params_; 82 input_frames_ = 0; 83 buffered_input_frames_ = 0.0; 84 last_input_buffer_offset_ = 0; 85} 86 87void AudioBufferConverter::ResetTimestampState() { 88 Flush(); 89 timestamp_helper_.SetBaseTimestamp(kNoTimestamp()); 90} 91 92double AudioBufferConverter::ProvideInput(AudioBus* audio_bus, 93 base::TimeDelta buffer_delay) { 94 DCHECK(is_flushing_ || input_frames_ >= audio_bus->frames()); 95 96 int requested_frames_left = audio_bus->frames(); 97 int dest_index = 0; 98 99 while (requested_frames_left > 0 && !queued_inputs_.empty()) { 100 scoped_refptr<AudioBuffer> input_buffer = queued_inputs_.front(); 101 102 int frames_to_read = 103 std::min(requested_frames_left, 104 input_buffer->frame_count() - last_input_buffer_offset_); 105 input_buffer->ReadFrames( 106 frames_to_read, last_input_buffer_offset_, dest_index, audio_bus); 107 last_input_buffer_offset_ += frames_to_read; 108 109 if (last_input_buffer_offset_ == input_buffer->frame_count()) { 110 // We've consumed all the frames in |input_buffer|. 111 queued_inputs_.pop_front(); 112 last_input_buffer_offset_ = 0; 113 } 114 115 requested_frames_left -= frames_to_read; 116 dest_index += frames_to_read; 117 } 118 119 // If we're flushing, zero any extra space, otherwise we should always have 120 // enough data to completely fulfill the request. 121 if (is_flushing_ && requested_frames_left > 0) { 122 audio_bus->ZeroFramesPartial(audio_bus->frames() - requested_frames_left, 123 requested_frames_left); 124 } else { 125 DCHECK_EQ(requested_frames_left, 0); 126 } 127 128 input_frames_ -= audio_bus->frames() - requested_frames_left; 129 DCHECK_GE(input_frames_, 0); 130 131 buffered_input_frames_ += audio_bus->frames() - requested_frames_left; 132 133 // Full volume. 134 return 1.0; 135} 136 137void AudioBufferConverter::ResetConverter( 138 const scoped_refptr<AudioBuffer>& buffer) { 139 Flush(); 140 audio_converter_.reset(); 141 input_params_.Reset( 142 input_params_.format(), 143 buffer->channel_layout(), 144 buffer->channel_count(), 145 0, 146 buffer->sample_rate(), 147 input_params_.bits_per_sample(), 148 // If resampling is needed and the FIFO disabled, the AudioConverter will 149 // always request SincResampler::kDefaultRequestSize frames. Otherwise it 150 // will use the output frame size. 151 buffer->sample_rate() == output_params_.sample_rate() 152 ? output_params_.frames_per_buffer() 153 : SincResampler::kDefaultRequestSize); 154 155 io_sample_rate_ratio_ = static_cast<double>(input_params_.sample_rate()) / 156 output_params_.sample_rate(); 157 158 // If |buffer| matches |output_params_| we don't need an AudioConverter at 159 // all, and can early-out here. 160 if (!IsConfigChange(output_params_, buffer)) 161 return; 162 163 // Note: The FIFO is disabled to avoid extraneous memcpy(). 164 audio_converter_.reset( 165 new AudioConverter(input_params_, output_params_, true)); 166 audio_converter_->AddInput(this); 167} 168 169void AudioBufferConverter::ConvertIfPossible() { 170 DCHECK(audio_converter_); 171 172 int request_frames = 0; 173 174 if (is_flushing_) { 175 // If we're flushing we want to convert *everything* even if this means 176 // we'll have to pad some silence in ProvideInput(). 177 request_frames = 178 ceil((buffered_input_frames_ + input_frames_) / io_sample_rate_ratio_); 179 } else { 180 // How many calls to ProvideInput() we can satisfy completely. 181 int chunks = input_frames_ / input_params_.frames_per_buffer(); 182 183 // How many output frames that corresponds to: 184 request_frames = chunks * audio_converter_->ChunkSize(); 185 } 186 187 if (!request_frames) 188 return; 189 190 scoped_refptr<AudioBuffer> output_buffer = 191 AudioBuffer::CreateBuffer(kSampleFormatPlanarF32, 192 output_params_.channel_layout(), 193 output_params_.channels(), 194 output_params_.sample_rate(), 195 request_frames); 196 scoped_ptr<AudioBus> output_bus = 197 AudioBus::CreateWrapper(output_buffer->channel_count()); 198 199 int frames_remaining = request_frames; 200 201 // The AudioConverter wants requests of a fixed size, so we'll slide an 202 // AudioBus of that size across the |output_buffer|. 203 while (frames_remaining != 0) { 204 // It's important that this is a multiple of AudioBus::kChannelAlignment in 205 // all requests except for the last, otherwise downstream SIMD optimizations 206 // will crash on unaligned data. 207 const int frames_this_iteration = std::min( 208 static_cast<int>(SincResampler::kDefaultRequestSize), frames_remaining); 209 const int offset_into_buffer = 210 output_buffer->frame_count() - frames_remaining; 211 212 // Wrap the portion of the AudioBuffer in an AudioBus so the AudioConverter 213 // can fill it. 214 output_bus->set_frames(frames_this_iteration); 215 for (int ch = 0; ch < output_buffer->channel_count(); ++ch) { 216 output_bus->SetChannelData( 217 ch, 218 reinterpret_cast<float*>(output_buffer->channel_data()[ch]) + 219 offset_into_buffer); 220 } 221 222 // Do the actual conversion. 223 audio_converter_->Convert(output_bus.get()); 224 frames_remaining -= frames_this_iteration; 225 buffered_input_frames_ -= frames_this_iteration * io_sample_rate_ratio_; 226 } 227 228 // Compute the timestamp. 229 output_buffer->set_timestamp(timestamp_helper_.GetTimestamp()); 230 timestamp_helper_.AddFrames(request_frames); 231 232 queued_outputs_.push_back(output_buffer); 233} 234 235void AudioBufferConverter::Flush() { 236 if (!audio_converter_) 237 return; 238 is_flushing_ = true; 239 ConvertIfPossible(); 240 is_flushing_ = false; 241 audio_converter_->Reset(); 242 DCHECK_EQ(input_frames_, 0); 243 DCHECK_EQ(last_input_buffer_offset_, 0); 244 DCHECK_LT(buffered_input_frames_, 1.0); 245 DCHECK(queued_inputs_.empty()); 246 buffered_input_frames_ = 0.0; 247} 248 249} // namespace media 250