summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorkylep@chromium.org <kylep@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-10 00:59:05 +0000
committerkylep@chromium.org <kylep@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-07-10 00:59:05 +0000
commit7efe9469ec72471d8bd110c44c82c4efa81d2772 (patch)
treeed99f43e78655b5ca8d012bb9b2ec7d06511aed2 /media
parent2e2307ef575107d2710075f543fcabfce495585b (diff)
downloadchromium_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
Diffstat (limited to 'media')
-rw-r--r--media/filters/audio_renderer_algorithm_base.cc49
-rw-r--r--media/filters/audio_renderer_algorithm_base.h40
-rw-r--r--media/filters/audio_renderer_algorithm_default.cc62
-rw-r--r--media/filters/audio_renderer_algorithm_default.h3
-rw-r--r--media/filters/audio_renderer_algorithm_ola.cc99
-rw-r--r--media/filters/audio_renderer_algorithm_ola.h33
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_;