diff options
author | kylep@chromium.org <kylep@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 23:26:26 +0000 |
---|---|---|
committer | kylep@chromium.org <kylep@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-19 23:26:26 +0000 |
commit | 9a9c25c6fbbf231a4271165c30074fb847ea5a5d (patch) | |
tree | 245c2572021705ba49b8b4c654a05cc3f8a4649b /media | |
parent | 143f5f41c37362350380185fadc2f1a6021fabd2 (diff) | |
download | chromium_src-9a9c25c6fbbf231a4271165c30074fb847ea5a5d.zip chromium_src-9a9c25c6fbbf231a4271165c30074fb847ea5a5d.tar.gz chromium_src-9a9c25c6fbbf231a4271165c30074fb847ea5a5d.tar.bz2 |
Draft of base and default algorithm class for AudioRendererBase refactor.
Review URL: http://codereview.chromium.org/118395
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18876 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/filters/audio_renderer_algorithm_base.cc | 69 | ||||
-rw-r--r-- | media/filters/audio_renderer_algorithm_base.h | 109 | ||||
-rw-r--r-- | media/filters/audio_renderer_algorithm_default.cc | 77 | ||||
-rw-r--r-- | media/filters/audio_renderer_algorithm_default.h | 36 | ||||
-rw-r--r-- | media/media.gyp | 4 |
5 files changed, 295 insertions, 0 deletions
diff --git a/media/filters/audio_renderer_algorithm_base.cc b/media/filters/audio_renderer_algorithm_base.cc new file mode 100644 index 0000000..5a521cb --- /dev/null +++ b/media/filters/audio_renderer_algorithm_base.cc @@ -0,0 +1,69 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/filters/audio_renderer_algorithm_base.h" + +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; + +AudioRendererAlgorithmBase::AudioRendererAlgorithmBase() + : channels_(0), + sample_rate_(0), + sample_bits_(0), + playback_rate_(0.0f), + expected_queue_size_(0) { +} + +AudioRendererAlgorithmBase::~AudioRendererAlgorithmBase() {} + +void AudioRendererAlgorithmBase::Initialize(int channels, + int sample_rate, + int sample_bits, + float initial_playback_rate, + RequestReadCallback* callback) { + DCHECK_GT(channels, 0); + DCHECK_GT(sample_rate, 0); + DCHECK_GT(sample_bits, 0); + DCHECK_GE(initial_playback_rate, 0.0); + DCHECK(callback); + + channels_ = channels; + sample_rate_ = sample_rate; + sample_bits_ = sample_bits; + playback_rate_ = initial_playback_rate; + request_read_callback_.reset(callback); + FillQueue(); +} + +void AudioRendererAlgorithmBase::FlushBuffers() { + // Clear the queue of decoded packets (releasing the buffers). + queue_.clear(); +} + +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); + } +} + +void AudioRendererAlgorithmBase::SetPlaybackRate(float new_rate) { + playback_rate_ = new_rate; +} + +void AudioRendererAlgorithmBase::FillQueue() { + for ( ; expected_queue_size_ < kDefaultMaxQueueSize; ++expected_queue_size_) + request_read_callback_->Run(); +} + +} // namespace media diff --git a/media/filters/audio_renderer_algorithm_base.h b/media/filters/audio_renderer_algorithm_base.h new file mode 100644 index 0000000..4b0aec3 --- /dev/null +++ b/media/filters/audio_renderer_algorithm_base.h @@ -0,0 +1,109 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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: +// +// Process() - fills the buffer passed to it & returns how many bytes copied. +// +// Subclasses must also decrement |expected_queue_size_| after a dequeue. +// +// The general assumption is that the owner of this class will provide us with +// Buffers and a playback speed, and we will fill an output buffer when our +// owner requests it. If we needs more Buffers, we will query our owner via +// a callback passed during construction. This should be a nonblocking call. +// When the owner has a Buffer ready for us, it calls EnqueueBuffer(). +// +// 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 Process(). |queue_| management and common property management +// should not have to change for subclasses, so both are implemented here +// non-virtually. + +// TODO(kylep): Clean this whole class up. Refactor out the |queue_| into a +// QueueManager or something like that. + +#ifndef MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_BASE_H_ +#define MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_BASE_H_ + +#include <deque> + +#include "base/ref_counted.h" +#include "base/scoped_ptr.h" +#include "base/task.h" +#include "media/base/data_buffer.h" +#include "media/base/buffers.h" + +namespace media { + +class AudioRendererAlgorithmBase { + public: + // Used to simplify callback declarations. + typedef Callback0::Type RequestReadCallback; + + AudioRendererAlgorithmBase(); + virtual ~AudioRendererAlgorithmBase(); + + // Checks validity of audio parameters and takes ownership of |callback|. + virtual void Initialize(int channels, + int sample_rate, + int sample_bits, + 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|. + // TODO(kylep): Think of a better name. + virtual size_t Process(DataBuffer* buffer_out) = 0; + + // Clears |queue_|. + void FlushBuffers(); + + // Enqueues a buffer. It is called from the owner + // of the algorithm after a read completes. + void EnqueueBuffer(Buffer* buffer_in); + + // Sets the playback rate. + void SetPlaybackRate(float new_rate); + + protected: + // Fills the |queue_|. This is a helper function called from + // Initialize() to initially fill |queue_| and from subclasses' + // Process() method to refill |queue_| after buffers have been used. + void FillQueue(); + + // Audio properties. + int channels_; + int sample_rate_; + int sample_bits_; + + // Used by algorithm to scale output. + float playback_rate_; + + // Used to request more data. + scoped_ptr<RequestReadCallback> request_read_callback_; + + // Keeps track of the number of buffers we will have in |queue_| + // after all reads complete. Subclasses MUST decrement this after + // dequeuing. + size_t expected_queue_size_; + + // Queued audio data. + typedef std::deque< scoped_refptr<Buffer> > BufferQueue; + BufferQueue queue_; + + private: + DISALLOW_COPY_AND_ASSIGN(AudioRendererAlgorithmBase); +}; + +} // namespace media + +#endif // MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_BASE_H_ diff --git a/media/filters/audio_renderer_algorithm_default.cc b/media/filters/audio_renderer_algorithm_default.cc new file mode 100644 index 0000000..3b46af5 --- /dev/null +++ b/media/filters/audio_renderer_algorithm_default.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/filters/audio_renderer_algorithm_default.h" + +namespace media { + +AudioRendererAlgorithmDefault::AudioRendererAlgorithmDefault() + : data_offset_(0) { +} + +AudioRendererAlgorithmDefault::~AudioRendererAlgorithmDefault() { +} + +size_t AudioRendererAlgorithmDefault::Process(DataBuffer* buffer_out) { + size_t dest_written = 0; + if (playback_rate_ == 0.0f) { + return 0; + } + if (playback_rate_ == 1.0f) { + size_t dest_length = buffer_out->GetDataSize(); + uint8* dest = buffer_out->GetWritableData(dest_length); + while (dest_length > 0 && !queue_.empty()) { + scoped_refptr<Buffer> buffer = queue_.front(); + 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) { + queue_.pop_front(); + data_offset_ = 0; + } + } + } else { + // 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 = + static_cast<size_t>(dest_written * playback_rate_); + while (scaled_dest_length_remaining > 0 && !queue_.empty()) { + size_t data_length = queue_.front()->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; + queue_.pop_front(); + data_offset_ = 0; + } + } + // If we ran out, don't report we used more than we did. + if (queue_.empty()) { + dest_written -= + static_cast<size_t>(scaled_dest_length_remaining / playback_rate_); + } + } + FillQueue(); + return dest_written; +} + +} // namespace media diff --git a/media/filters/audio_renderer_algorithm_default.h b/media/filters/audio_renderer_algorithm_default.h new file mode 100644 index 0000000..073c83b --- /dev/null +++ b/media/filters/audio_renderer_algorithm_default.h @@ -0,0 +1,36 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// AudioRendererAlgorithmDefault is the default implementation of +// AudioRendererAlgorithmBase. For speeds other than 1.0f, Process() fills +// |buffer_out| with 0s and returns the expected size. As ARAB is +// thread-unsafe, so is ARAD. + +#ifndef MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_DEFAULT_H_ +#define MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_DEFAULT_H_ + +#include "base/time.h" +#include "media/base/data_buffer.h" +#include "media/filters/audio_renderer_algorithm_base.h" + +namespace media { + +class AudioRendererAlgorithmDefault : public AudioRendererAlgorithmBase { + public: + AudioRendererAlgorithmDefault(); + virtual ~AudioRendererAlgorithmDefault(); + + // AudioRendererAlgorithmBase implementation + virtual size_t Process(DataBuffer* buffer_out); + + private: + // Remembers the amount of remaining audio data for the front buffer. + size_t data_offset_; + + DISALLOW_COPY_AND_ASSIGN(AudioRendererAlgorithmDefault); +}; + +} // namespace media + +#endif // MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_DEFAULT_H_ diff --git a/media/media.gyp b/media/media.gyp index e3f3b3a..d5c1a3d 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -72,6 +72,10 @@ 'base/yuv_row_mac.cc', 'base/yuv_row_linux.cc', 'base/yuv_row.h', + 'filters/audio_renderer_algorithm_base.cc', + 'filters/audio_renderer_algorithm_base.h', + 'filters/audio_renderer_algorithm_default.cc', + 'filters/audio_renderer_algorithm_default.h', 'filters/audio_renderer_base.cc', 'filters/audio_renderer_base.h', 'filters/audio_renderer_impl.cc', |