multi_channel_resampler.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/multi_channel_resampler.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/logging.h" 10#include "media/base/audio_bus.h" 11 12namespace media { 13 14MultiChannelResampler::MultiChannelResampler(int channels, 15 double io_sample_rate_ratio, 16 const ReadCB& read_cb) 17 : last_frame_count_(0), 18 read_cb_(read_cb), 19 output_frames_ready_(0) { 20 // Allocate each channel's resampler. 21 resamplers_.reserve(channels); 22 for (int i = 0; i < channels; ++i) { 23 resamplers_.push_back(new SincResampler(io_sample_rate_ratio, base::Bind( 24 &MultiChannelResampler::ProvideInput, base::Unretained(this), i))); 25 } 26} 27 28MultiChannelResampler::~MultiChannelResampler() {} 29 30void MultiChannelResampler::Resample(AudioBus* audio_bus, int frames) { 31 DCHECK_EQ(static_cast<size_t>(audio_bus->channels()), resamplers_.size()); 32 33 // We need to ensure that SincResampler only calls ProvideInput once for each 34 // channel. To ensure this, we chunk the number of requested frames into 35 // SincResampler::ChunkSize() sized chunks. SincResampler guarantees it will 36 // only call ProvideInput() once when we resample this way. 37 output_frames_ready_ = 0; 38 int chunk_size = resamplers_[0]->ChunkSize(); 39 while (output_frames_ready_ < frames) { 40 int frames_this_time = std::min(frames - output_frames_ready_, chunk_size); 41 42 // Resample each channel. 43 for (size_t i = 0; i < resamplers_.size(); ++i) { 44 DCHECK_EQ(chunk_size, resamplers_[i]->ChunkSize()); 45 46 // Depending on the sample-rate scale factor, and the internal buffering 47 // used in a SincResampler kernel, this call to Resample() will only 48 // sometimes call ProvideInput(). However, if it calls ProvideInput() for 49 // the first channel, then it will call it for the remaining channels, 50 // since they all buffer in the same way and are processing the same 51 // number of frames. 52 resamplers_[i]->Resample( 53 audio_bus->channel(i) + output_frames_ready_, frames_this_time); 54 } 55 56 output_frames_ready_ += frames_this_time; 57 } 58} 59 60void MultiChannelResampler::ProvideInput(int channel, float* destination, 61 int frames) { 62 // Get the data from the multi-channel provider when the first channel asks 63 // for it. For subsequent channels, we can just dish out the channel data 64 // from that (stored in |resampler_audio_bus_|). 65 if (channel == 0) { 66 // Allocate staging arrays on the first request and if the frame size or 67 // |destination| changes (should only happen once). 68 if (!resampler_audio_bus_.get() || 69 resampler_audio_bus_->frames() != frames || 70 wrapped_resampler_audio_bus_->channel(0) != destination) { 71 resampler_audio_bus_ = AudioBus::Create(resamplers_.size(), frames); 72 73 // Create a channel vector based on |resampler_audio_bus_| but using 74 // |destination| directly for the first channel and then wrap it in a new 75 // AudioBus so we can avoid an extra memcpy later. 76 resampler_audio_data_.clear(); 77 resampler_audio_data_.reserve(resampler_audio_bus_->channels()); 78 resampler_audio_data_.push_back(destination); 79 for (int i = 1; i < resampler_audio_bus_->channels(); ++i) 80 resampler_audio_data_.push_back(resampler_audio_bus_->channel(i)); 81 wrapped_resampler_audio_bus_ = AudioBus::WrapVector( 82 frames, resampler_audio_data_); 83 } 84 85 last_frame_count_ = frames; 86 read_cb_.Run(output_frames_ready_, wrapped_resampler_audio_bus_.get()); 87 } else { 88 // All channels must ask for the same amount. This should always be the 89 // case, but let's just make sure. 90 DCHECK_EQ(frames, last_frame_count_); 91 92 // Copy the channel data from what we received from |read_cb_|. 93 memcpy(destination, resampler_audio_bus_->channel(channel), 94 sizeof(*resampler_audio_bus_->channel(channel)) * frames); 95 } 96} 97 98void MultiChannelResampler::Flush() { 99 last_frame_count_ = 0; 100 for (size_t i = 0; i < resamplers_.size(); ++i) 101 resamplers_[i]->Flush(); 102} 103 104} // namespace media 105