diff options
author | kylep@chromium.org <kylep@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-10 00:59:05 +0000 |
---|---|---|
committer | kylep@chromium.org <kylep@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-10 00:59:05 +0000 |
commit | 7efe9469ec72471d8bd110c44c82c4efa81d2772 (patch) | |
tree | ed99f43e78655b5ca8d012bb9b2ec7d06511aed2 | |
parent | 2e2307ef575107d2710075f543fcabfce495585b (diff) | |
download | chromium_src-7efe9469ec72471d8bd110c44c82c4efa81d2772.zip chromium_src-7efe9469ec72471d8bd110c44c82c4efa81d2772.tar.gz chromium_src-7efe9469ec72471d8bd110c44c82c4efa81d2772.tar.bz2 |
Refactor audio renderer algorithms to use BufferQueue. Also cleaned up some comments and unnecessary functions/fields.
BUG=16011
TEST=none
Review URL: http://codereview.chromium.org/155255
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20347 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | media/filters/audio_renderer_algorithm_base.cc | 49 | ||||
-rw-r--r-- | media/filters/audio_renderer_algorithm_base.h | 40 | ||||
-rw-r--r-- | media/filters/audio_renderer_algorithm_default.cc | 62 | ||||
-rw-r--r-- | media/filters/audio_renderer_algorithm_default.h | 3 | ||||
-rw-r--r-- | media/filters/audio_renderer_algorithm_ola.cc | 99 | ||||
-rw-r--r-- | media/filters/audio_renderer_algorithm_ola.h | 33 |
6 files changed, 88 insertions, 198 deletions
diff --git a/media/filters/audio_renderer_algorithm_base.cc b/media/filters/audio_renderer_algorithm_base.cc index acbc35a..013c716 100644 --- a/media/filters/audio_renderer_algorithm_base.cc +++ b/media/filters/audio_renderer_algorithm_base.cc @@ -8,14 +8,10 @@ namespace media { -// The maximum size of the queue, which also acts as the number of initial reads -// to perform for buffering. The size of the queue should never exceed this -// number since we read only after we've dequeued and released a buffer in -// callback thread. -// -// This is sort of a magic number, but for 44.1kHz stereo audio this will give -// us enough data to fill approximately 4 complete callback buffers. -const size_t kDefaultMaxQueueSize = 16; +// The size in bytes we try to maintain for the |queue_|. Previous usage +// maintained a deque of 16 Buffers, each of size 4Kb. This worked well, so we +// maintain this number of bytes (16 * 4096). +const size_t kDefaultMaxQueueSizeInBytes = 65536; AudioRendererAlgorithmBase::AudioRendererAlgorithmBase() : channels_(0), @@ -40,21 +36,24 @@ void AudioRendererAlgorithmBase::Initialize(int channels, set_playback_rate(initial_playback_rate); - for (size_t i = 0; i < kDefaultMaxQueueSize; ++i) - request_read_callback_->Run(); + // Do the initial read. + request_read_callback_->Run(); } void AudioRendererAlgorithmBase::FlushBuffers() { // Clear the queue of decoded packets (releasing the buffers). - queue_.clear(); + queue_.Clear(); + request_read_callback_->Run(); } void AudioRendererAlgorithmBase::EnqueueBuffer(Buffer* buffer_in) { // If we're at end of stream, |buffer_in| contains no data. - if (!buffer_in->IsEndOfStream()) { - queue_.push_back(buffer_in); - DCHECK_LE(queue_.size(), kDefaultMaxQueueSize); - } + if (!buffer_in->IsEndOfStream()) + queue_.Enqueue(buffer_in); + + // If we still don't have enough data, request more. + if (queue_.SizeInBytes() < kDefaultMaxQueueSizeInBytes) + request_read_callback_->Run(); } float AudioRendererAlgorithmBase::playback_rate() { @@ -66,17 +65,23 @@ void AudioRendererAlgorithmBase::set_playback_rate(float new_rate) { playback_rate_ = new_rate; } -bool AudioRendererAlgorithmBase::IsQueueEmpty() { - return queue_.empty(); +void AudioRendererAlgorithmBase::AdvanceInputPosition(size_t bytes) { + queue_.Consume(bytes); + + if (queue_.SizeInBytes() < kDefaultMaxQueueSizeInBytes) + request_read_callback_->Run(); } -scoped_refptr<Buffer> AudioRendererAlgorithmBase::FrontQueue() { - return queue_.front(); +size_t AudioRendererAlgorithmBase::CopyFromInput(uint8* dest, size_t bytes) { + return queue_.Copy(dest, bytes); } -void AudioRendererAlgorithmBase::PopFrontQueue() { - queue_.pop_front(); - request_read_callback_->Run(); +bool AudioRendererAlgorithmBase::IsQueueEmpty() { + return queue_.IsEmpty(); +} + +size_t AudioRendererAlgorithmBase::QueueSize() { + return queue_.SizeInBytes(); } int AudioRendererAlgorithmBase::channels() { diff --git a/media/filters/audio_renderer_algorithm_base.h b/media/filters/audio_renderer_algorithm_base.h index 7a370cb..d817e3d 100644 --- a/media/filters/audio_renderer_algorithm_base.h +++ b/media/filters/audio_renderer_algorithm_base.h @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// AudioRendererAlgorithmBase provides an interface for algorithms that -// modify playback speed. ARAB owns its own deque of Buffers because -// subclasses may need more than one to produce output. Subclasses -// must implement the following method: +// AudioRendererAlgorithmBase provides an interface for algorithms that modify +// playback speed. ARAB owns a BufferQueue which hides Buffer boundaries from +// subclasses and allows them to access data by byte. Subclasses must implement +// the following method: // // FillBuffer() - fills the buffer passed to it & returns how many bytes // copied. @@ -19,11 +19,6 @@ // Exectution of ARAB is thread-unsafe. This class should be used as // the guts of AudioRendererBase, which should lock calls into us so // enqueues and processes do not cause an unpredictable |queue_| size. -// -// Most of ARAB is nonvirtual as the only subclasses we expect are those to -// define FillBuffer(). |queue_| management and common property management -// should not have to change for subclasses, so both are implemented here -// non-virtually. #ifndef MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_BASE_H_ #define MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_BASE_H_ @@ -33,6 +28,7 @@ #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/task.h" +#include "media/base/buffer_queue.h" namespace media { @@ -53,17 +49,16 @@ class AudioRendererAlgorithmBase { float initial_playback_rate, RequestReadCallback* callback); - // Implement this strategy method in derived classes. - // Fills |buffer_out| with possibly scaled data from our |queue_|. - // |buffer_out| must be initialized and have a datasize. - // Returns the number of bytes copied into |buffer_out|. + // Implement this strategy method in derived classes. Fills |buffer_out| with + // possibly scaled data from our |queue_|. |buffer_out| must be initialized + // and have a datasize. Returns the number of bytes copied into |buffer_out|. virtual size_t FillBuffer(DataBuffer* buffer_out) = 0; // Clears |queue_|. virtual void FlushBuffers(); - // Enqueues a buffer. It is called from the owner - // of the algorithm after a read completes. + // Enqueues a buffer. It is called from the owner of the algorithm after a + // read completes. virtual void EnqueueBuffer(Buffer* buffer_in); // Getter/setter for |playback_rate_|. @@ -71,14 +66,18 @@ class AudioRendererAlgorithmBase { virtual void set_playback_rate(float new_rate); protected: + // Advances |queue_|'s internal pointer by |bytes|. + void AdvanceInputPosition(size_t bytes); + + // Tries to copy |bytes| bytes from |queue_| to |dest|. Returns the number of + // bytes successfully copied. + size_t CopyFromInput(uint8* dest, size_t bytes); + // Returns whether |queue_| is empty. virtual bool IsQueueEmpty(); - // Returns a reference to the first element of the |queue_|. - virtual scoped_refptr<Buffer> FrontQueue(); - - // Pops the front of the |queue_| and schedules a read. - virtual void PopFrontQueue(); + // Returns the number of bytes left in |queue_|. + virtual size_t QueueSize(); // Number of audio channels. virtual int channels(); @@ -98,7 +97,6 @@ class AudioRendererAlgorithmBase { scoped_ptr<RequestReadCallback> request_read_callback_; // Queued audio data. - typedef std::deque< scoped_refptr<Buffer> > BufferQueue; BufferQueue queue_; DISALLOW_COPY_AND_ASSIGN(AudioRendererAlgorithmBase); diff --git a/media/filters/audio_renderer_algorithm_default.cc b/media/filters/audio_renderer_algorithm_default.cc index 4184a98..d13cbf0 100644 --- a/media/filters/audio_renderer_algorithm_default.cc +++ b/media/filters/audio_renderer_algorithm_default.cc @@ -9,69 +9,45 @@ namespace media { -AudioRendererAlgorithmDefault::AudioRendererAlgorithmDefault() - : data_offset_(0) { +AudioRendererAlgorithmDefault::AudioRendererAlgorithmDefault() { } AudioRendererAlgorithmDefault::~AudioRendererAlgorithmDefault() { } size_t AudioRendererAlgorithmDefault::FillBuffer(DataBuffer* buffer_out) { - size_t dest_written = 0; if (playback_rate() == 0.0f) { return 0; } + + size_t dest_written = 0; + if (playback_rate() == 1.0f) { size_t dest_length = buffer_out->GetDataSize(); uint8* dest = buffer_out->GetWritableData(dest_length); - while (dest_length > 0 && !IsQueueEmpty()) { - scoped_refptr<Buffer> buffer = FrontQueue(); - size_t data_length = buffer->GetDataSize() - data_offset_; - // Prevent writing past end of the buffer. - if (data_length > dest_length) - data_length = dest_length; - memcpy(dest, buffer->GetData() + data_offset_, data_length); - dest += data_length; - dest_length -= data_length; - dest_written += data_length; - - data_offset_ += data_length; - - // We should not have run over the end of the buffer. - DCHECK_GE(buffer->GetDataSize(), data_offset_); - // but if we've reached the end, dequeue it. - if (buffer->GetDataSize() - data_offset_ == 0) { - PopFrontQueue(); - data_offset_ = 0; - } - } + // If we don't have enough data, copy what we have. + if (QueueSize() < dest_length) + dest_written = CopyFromInput(dest, QueueSize()); + else + dest_written = CopyFromInput(dest, dest_length); + AdvanceInputPosition(dest_written); } else { - // Mute (we will write to the whole buffer, so set |dest_written| - // to the requested size). + // Mute (we will write to the whole buffer, so set |dest_written| to the + // requested size). dest_written = buffer_out->GetDataSize(); memset(buffer_out->GetWritableData(dest_written), 0, dest_written); - // Discard any buffers that should be "used". - size_t scaled_dest_length_remaining = + // Calculate the number of bytes we "used". + size_t scaled_dest_length = static_cast<size_t>(dest_written * playback_rate()); - while (scaled_dest_length_remaining > 0 && !IsQueueEmpty()) { - size_t data_length = FrontQueue()->GetDataSize() - data_offset_; - // Last buffer we need. - if (data_length > scaled_dest_length_remaining) { - data_offset_ += scaled_dest_length_remaining; - } else { - scaled_dest_length_remaining -= data_length; - PopFrontQueue(); - data_offset_ = 0; - } - } - // If we ran out, don't report we used more than we did. - if (IsQueueEmpty()) { - dest_written -= - static_cast<size_t>(scaled_dest_length_remaining / playback_rate()); + // If this is more than we have, report the correct amount consumed. + if (QueueSize() < scaled_dest_length) { + scaled_dest_length = QueueSize(); + dest_written = static_cast<size_t>(scaled_dest_length / playback_rate()); } + AdvanceInputPosition(scaled_dest_length); } return dest_written; } diff --git a/media/filters/audio_renderer_algorithm_default.h b/media/filters/audio_renderer_algorithm_default.h index 05c13e7..b2a964d 100644 --- a/media/filters/audio_renderer_algorithm_default.h +++ b/media/filters/audio_renderer_algorithm_default.h @@ -25,9 +25,6 @@ class AudioRendererAlgorithmDefault : public AudioRendererAlgorithmBase { virtual size_t FillBuffer(DataBuffer* buffer_out); private: - // Remembers the amount of remaining audio data for the front buffer. - size_t data_offset_; - DISALLOW_COPY_AND_ASSIGN(AudioRendererAlgorithmDefault); }; diff --git a/media/filters/audio_renderer_algorithm_ola.cc b/media/filters/audio_renderer_algorithm_ola.cc index 9a235de..da2992d 100644 --- a/media/filters/audio_renderer_algorithm_ola.cc +++ b/media/filters/audio_renderer_algorithm_ola.cc @@ -16,8 +16,7 @@ namespace media { const size_t kDefaultWindowSize = 4096; AudioRendererAlgorithmOLA::AudioRendererAlgorithmOLA() - : data_offset_(0), - input_step_(0), + : input_step_(0), output_step_(0) { } @@ -25,7 +24,7 @@ AudioRendererAlgorithmOLA::~AudioRendererAlgorithmOLA() { } size_t AudioRendererAlgorithmOLA::FillBuffer(DataBuffer* buffer_out) { - if (IsInputFinished()) + if (IsQueueEmpty()) return 0; if (playback_rate() == 0.0f) return 0; @@ -35,8 +34,11 @@ size_t AudioRendererAlgorithmOLA::FillBuffer(DataBuffer* buffer_out) { uint8* dest = buffer_out->GetWritableData(dest_remaining); size_t dest_written = 0; if (playback_rate() == 1.0f) { - dest_written = CopyInput(dest, dest_remaining); - AdvanceInput(dest_written); + if (QueueSize() < dest_remaining) + dest_written = CopyFromInput(dest, QueueSize()); + else + dest_written = CopyFromInput(dest, dest_remaining); + AdvanceInputPosition(dest_written); return dest_written; } @@ -44,21 +46,25 @@ size_t AudioRendererAlgorithmOLA::FillBuffer(DataBuffer* buffer_out) { // TODO(kylep): Limit the rates to reasonable values. We may want to do this // on the UI side or in set_playback_rate(). while (dest_remaining >= output_step_ + crossfade_size_) { + // If we don't have enough data to completely finish this loop, quit. + if (QueueSize() < kDefaultWindowSize) + break; + // Copy bulk of data to output (including some to crossfade to the next // copy), then add to our running sum of written data and subtract from // our tally of remaing requested. - size_t copied = CopyInput(dest, output_step_ + crossfade_size_); + size_t copied = CopyFromInput(dest, output_step_ + crossfade_size_); dest_written += copied; dest_remaining -= copied; // Advance pointers for crossfade. dest += output_step_; - AdvanceInput(input_step_); + AdvanceInputPosition(input_step_); // Prepare intermediate buffer. size_t crossfade_size; scoped_array<uint8> src(new uint8[crossfade_size_]); - crossfade_size = CopyInput(src.get(), crossfade_size_); + crossfade_size = CopyFromInput(src.get(), crossfade_size_); // Calculate number of samples to crossfade, then do so. int samples = static_cast<int>(crossfade_size / sample_bytes() @@ -82,17 +88,12 @@ size_t AudioRendererAlgorithmOLA::FillBuffer(DataBuffer* buffer_out) { } // Advance pointers again. - AdvanceInput(crossfade_size_); - dest += crossfade_size_; + AdvanceInputPosition(crossfade_size); + dest += crossfade_size; } return dest_written; } -void AudioRendererAlgorithmOLA::FlushBuffers() { - AudioRendererAlgorithmBase::FlushBuffers(); - saved_buf_ = NULL; -} - void AudioRendererAlgorithmOLA::set_playback_rate(float new_rate) { AudioRendererAlgorithmBase::set_playback_rate(new_rate); @@ -118,74 +119,10 @@ void AudioRendererAlgorithmOLA::set_playback_rate(float new_rate) { output_step_ -= crossfade_size_; } -void AudioRendererAlgorithmOLA::AdvanceInput(size_t bytes) { - if (IsInputFinished()) - return; - - DCHECK(saved_buf_) << "Did you forget to call CopyInput()?"; - - // Calculate number of usable bytes in |saved_buf_|. - size_t saved_buf_remaining = saved_buf_->GetDataSize() - data_offset_; - - // If there is enough data in |saved_buf_| to advance into it, do so. - // Otherwise, advance into the queue. - if (saved_buf_remaining > bytes) { - data_offset_ += bytes; - } else { - if (!IsQueueEmpty()) { - saved_buf_ = FrontQueue(); - PopFrontQueue(); - } else { - saved_buf_ = NULL; - } - // TODO(kylep): Make this function loop to eliminate the DCHECK. - DCHECK_GE(bytes, saved_buf_remaining); - - data_offset_ = bytes - saved_buf_remaining; - } -} - void AudioRendererAlgorithmOLA::AlignToSampleBoundary(size_t* value) { (*value) -= ((*value) % (channels() * sample_bytes())); } -// TODO(kylep): Make this function loop to satisfy requests better. -size_t AudioRendererAlgorithmOLA::CopyInput(uint8* dest, size_t length) { - if (IsInputFinished()) - return 0; - - // Lazy initialization. - if (!saved_buf_) { - saved_buf_ = FrontQueue(); - PopFrontQueue(); - } - - size_t dest_written = 0; - size_t data_length = saved_buf_->GetDataSize() - data_offset_; - - // Prevent writing past end of the buffer. - if (data_length > length) - data_length = length; - memcpy(dest, saved_buf_->GetData() + data_offset_, data_length); - - dest += data_length; - length -= data_length; - dest_written += data_length; - - if (length > 0) { - // We should have enough data in the next buffer so long as the - // queue is not empty. - if (IsQueueEmpty()) - return dest_written; - DCHECK_LE(length, FrontQueue()->GetDataSize()); - - memcpy(dest, FrontQueue()->GetData(), length); - dest_written += length; - } - - return dest_written; -} - template <class Type> void AudioRendererAlgorithmOLA::Crossfade(int samples, const Type* src, @@ -205,8 +142,4 @@ void AudioRendererAlgorithmOLA::Crossfade(int samples, } } -bool AudioRendererAlgorithmOLA::IsInputFinished() { - return !saved_buf_ && IsQueueEmpty(); -} - } // namespace media diff --git a/media/filters/audio_renderer_algorithm_ola.h b/media/filters/audio_renderer_algorithm_ola.h index c46ba134..006400c 100644 --- a/media/filters/audio_renderer_algorithm_ola.h +++ b/media/filters/audio_renderer_algorithm_ola.h @@ -4,11 +4,10 @@ // AudioRendererAlgorithmOLA [ARAO] is the pitch-preservation implementation of // AudioRendererAlgorithmBase [ARAB]. For speeds greater than 1.0f, FillBuffer() -// consumes more input data than output data requested and crossfades -// samples to fill |buffer_out|. For speeds less than 1.0f, FillBuffer() -// consumers less input data than output data requested and draws overlapping -// samples from the input data to fill |buffer_out|. As ARAB is thread-unsafe, -// so is ARAO. +// consumes more input data than output data requested and crossfades samples +// to fill |buffer_out|. For speeds less than 1.0f, FillBuffer() consumers less +// input data than output data requested and draws overlapping samples from the +// input data to fill |buffer_out|. As ARAB is thread-unsafe, so is ARAO. #ifndef MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_OLA_H_ #define MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_OLA_H_ @@ -27,21 +26,12 @@ class AudioRendererAlgorithmOLA : public AudioRendererAlgorithmBase { // AudioRendererAlgorithmBase implementation virtual size_t FillBuffer(DataBuffer* buffer_out); - virtual void FlushBuffers(); - virtual void set_playback_rate(float new_rate); private: - // Advances our input position by |bytes| bytes. - void AdvanceInput(size_t bytes); - // Aligns |value| to a channel and sample boundary. void AlignToSampleBoundary(size_t* value); - // Copies |length| bytes from our buffers to |dest|. Returns how many bytes - // of data were copied. - size_t CopyInput(uint8* dest, size_t length); - // Crossfades |samples| samples of |dest| with the data in |src|. Assumes // there is room in |dest| and enough data in |src|. Type is the datatype // of a data point in the waveform (i.e. uint8, int16, int32, etc). Also, @@ -49,18 +39,9 @@ class AudioRendererAlgorithmOLA : public AudioRendererAlgorithmBase { template <class Type> void Crossfade(int samples, const Type* src, Type* dest); - // Returns true if |saved_buf_| is NULL and the queue is empty. - bool IsInputFinished(); - - // Stores the front element of the queue so we can peek at the second one. - scoped_refptr<Buffer> saved_buf_; - - // Remembers the amount of remaining audio data for our |saved_buf_|. - size_t data_offset_; - - // Members for ease of calculation in FillBuffer(). These members are - // based on |playback_rate_|, but are stored seperately so they don't - // have to be recalculated on every call to FillBuffer(). + // Members for ease of calculation in FillBuffer(). These members are based + // on |playback_rate_|, but are stored seperately so they don't have to be + // recalculated on every call to FillBuffer(). size_t input_step_; size_t output_step_; |