summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorvrk@google.com <vrk@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-19 19:02:53 +0000
committervrk@google.com <vrk@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-19 19:02:53 +0000
commit948d3c6675d7e22c0fdf7d80ff5a1f8b5a8f2892 (patch)
tree7123343248409e61e6afd0cdaa756baa774c7269 /media
parent976327c504a0f80b09ce7403f8cd653c4a7576ae (diff)
downloadchromium_src-948d3c6675d7e22c0fdf7d80ff5a1f8b5a8f2892.zip
chromium_src-948d3c6675d7e22c0fdf7d80ff5a1f8b5a8f2892.tar.gz
chromium_src-948d3c6675d7e22c0fdf7d80ff5a1f8b5a8f2892.tar.bz2
Consolidate AudioRendererAlgorithm classes into one class
There's no reason to have 2 derived classes of AudioRendererAlgorithmBase. This CL deletes the derived classes and pushes the behavior into the base class. It shouldn't change any existing logic; should be just pushing things around. BUG=106492 TEST=media_unittests Review URL: http://codereview.chromium.org/8879041 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@115006 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/filters/audio_renderer_algorithm_base.cc215
-rw-r--r--media/filters/audio_renderer_algorithm_base.h98
-rw-r--r--media/filters/audio_renderer_algorithm_base_unittest.cc (renamed from media/filters/audio_renderer_algorithm_ola_unittest.cc)57
-rw-r--r--media/filters/audio_renderer_algorithm_default.cc51
-rw-r--r--media/filters/audio_renderer_algorithm_default.h31
-rw-r--r--media/filters/audio_renderer_algorithm_ola.cc207
-rw-r--r--media/filters/audio_renderer_algorithm_ola.h70
-rw-r--r--media/filters/audio_renderer_base.cc5
-rw-r--r--media/media.gyp17
-rw-r--r--media/tools/wav_ola_test/wav_ola_test.cc174
10 files changed, 268 insertions, 657 deletions
diff --git a/media/filters/audio_renderer_algorithm_base.cc b/media/filters/audio_renderer_algorithm_base.cc
index affebf5..2a05a24 100644
--- a/media/filters/audio_renderer_algorithm_base.cc
+++ b/media/filters/audio_renderer_algorithm_base.cc
@@ -4,6 +4,9 @@
#include "media/filters/audio_renderer_algorithm_base.h"
+#include <algorithm>
+#include <cmath>
+
#include "base/logging.h"
#include "media/base/buffers.h"
@@ -12,10 +15,21 @@ namespace media {
// 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 int kDefaultMinQueueSizeInBytes = 65536;
-const int kDefaultMinQueueSizeInMilliseconds = 372; // ~64kb @ 44.1k stereo
-const int kDefaultMaxQueueSizeInBytes = 4608000; // 3 seconds @ 96kHz 7.1
-const int kDefaultMaxQueueSizeInMilliseconds = 3000;
+static const int kDefaultMinQueueSizeInBytes = 65536;
+// ~64kb @ 44.1k stereo.
+static const int kDefaultMinQueueSizeInMilliseconds = 372;
+// 3 seconds @ 96kHz 7.1.
+static const int kDefaultMaxQueueSizeInBytes = 4608000;
+static const int kDefaultMaxQueueSizeInMilliseconds = 3000;
+
+// Default window and crossfade lengths in seconds.
+static const double kDefaultWindowLength = 0.08;
+static const double kDefaultCrossfadeLength = 0.008;
+
+// Default mute ranges for fast/slow audio. These rates would sound better
+// under a frequency domain algorithm.
+static const float kMinRate = 0.5f;
+static const float kMaxRate = 4.0f;
AudioRendererAlgorithmBase::AudioRendererAlgorithmBase()
: channels_(0),
@@ -23,7 +37,179 @@ AudioRendererAlgorithmBase::AudioRendererAlgorithmBase()
sample_bytes_(0),
playback_rate_(0.0f),
queue_(0, kDefaultMinQueueSizeInBytes),
- max_queue_capacity_(kDefaultMaxQueueSizeInBytes) {
+ max_queue_capacity_(kDefaultMaxQueueSizeInBytes),
+ input_step_(0),
+ output_step_(0),
+ crossfade_size_(0),
+ window_size_(0) {
+}
+
+uint32 AudioRendererAlgorithmBase::FillBuffer(uint8* dest, uint32 length) {
+ if (IsQueueEmpty())
+ return 0;
+ if (playback_rate_ == 0.0f)
+ return 0;
+
+ uint32 dest_written = 0;
+
+ // Handle the simple case of normal playback.
+ if (playback_rate_ == 1.0f) {
+ if (QueueSize() < length)
+ dest_written = CopyFromInput(dest, QueueSize());
+ else
+ dest_written = CopyFromInput(dest, length);
+ AdvanceInputPosition(dest_written);
+ return dest_written;
+ }
+
+ // For other playback rates, OLA with crossfade!
+ while (true) {
+ // Mute when out of acceptable quality range or when we don't have enough
+ // data to completely finish this loop.
+ //
+ // Note: This may not play at the speed requested as we can only consume as
+ // much data as we have, and audio timestamps drive the pipeline clock.
+ //
+ // Furthermore, we won't end up scaling the very last bit of audio, but
+ // we're talking about <8ms of audio data.
+ if (playback_rate_ < kMinRate || playback_rate_ > kMaxRate ||
+ QueueSize() < window_size_) {
+ // Calculate the ideal input/output steps based on the size of the
+ // destination buffer.
+ uint32 input_step = static_cast<uint32>(ceil(
+ static_cast<float>(length * playback_rate_)));
+ uint32 output_step = length;
+
+ // If the ideal size is too big, recalculate based on how much is left in
+ // the queue.
+ if (input_step > QueueSize()) {
+ input_step = QueueSize();
+ output_step = static_cast<uint32>(ceil(
+ static_cast<float>(input_step / playback_rate_)));
+ }
+
+ // Stay aligned and sanity check before writing out zeros.
+ AlignToSampleBoundary(&input_step);
+ AlignToSampleBoundary(&output_step);
+ DCHECK_LE(output_step, length);
+ if (output_step > length) {
+ LOG(ERROR) << "OLA: output_step (" << output_step << ") calculated to "
+ << "be larger than destination length (" << length << ")";
+ output_step = length;
+ }
+
+ memset(dest, 0, output_step);
+ AdvanceInputPosition(input_step);
+ dest_written += output_step;
+ break;
+ }
+
+ // Break if we don't have enough room left in our buffer to do a full
+ // OLA iteration.
+ if (length < (output_step_ + crossfade_size_)) {
+ 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 remaining requested.
+ uint32 copied = CopyFromInput(dest, output_step_ + crossfade_size_);
+ dest_written += copied;
+ length -= copied;
+
+ // Advance pointers for crossfade.
+ dest += output_step_;
+ AdvanceInputPosition(input_step_);
+
+ // Prepare intermediate buffer.
+ uint32 crossfade_size;
+ scoped_array<uint8> src(new uint8[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_ / channels_);
+ switch (sample_bytes_) {
+ case 4:
+ Crossfade(samples,
+ reinterpret_cast<const int32*>(src.get()),
+ reinterpret_cast<int32*>(dest));
+ break;
+ case 2:
+ Crossfade(samples,
+ reinterpret_cast<const int16*>(src.get()),
+ reinterpret_cast<int16*>(dest));
+ break;
+ case 1:
+ Crossfade(samples, src.get(), dest);
+ break;
+ default:
+ NOTREACHED() << "Unsupported audio bit depth sent to OLA algorithm";
+ }
+
+ // Advance pointers again.
+ AdvanceInputPosition(crossfade_size);
+ dest += crossfade_size_;
+ }
+ return dest_written;
+}
+
+void AudioRendererAlgorithmBase::SetPlaybackRate(float new_rate) {
+ DCHECK_GE(new_rate, 0.0);
+ playback_rate_ = new_rate;
+
+ // Calculate the window size from our default length and our audio properties.
+ // Precision is not an issue because we will round this to a sample boundary.
+ // This will not overflow because each parameter is checked in Initialize().
+ window_size_ = static_cast<uint32>(
+ sample_rate_ * sample_bytes_ * channels_ * kDefaultWindowLength);
+
+ // Adjusting step sizes to accommodate requested playback rate.
+ if (playback_rate_ > 1.0f) {
+ input_step_ = window_size_;
+ output_step_ = static_cast<uint32>(ceil(
+ static_cast<float>(window_size_ / playback_rate_)));
+ } else {
+ input_step_ = static_cast<uint32>(ceil(
+ static_cast<float>(window_size_ * playback_rate_)));
+ output_step_ = window_size_;
+ }
+ AlignToSampleBoundary(&input_step_);
+ AlignToSampleBoundary(&output_step_);
+
+ // Calculate length for crossfading.
+ crossfade_size_ = static_cast<uint32>(
+ sample_rate_ * sample_bytes_ * channels_ * kDefaultCrossfadeLength);
+ AlignToSampleBoundary(&crossfade_size_);
+ if (crossfade_size_ > std::min(input_step_, output_step_)) {
+ crossfade_size_ = 0;
+ return;
+ }
+
+ // To keep true to playback rate, modify the steps.
+ input_step_ -= crossfade_size_;
+ output_step_ -= crossfade_size_;
+}
+
+void AudioRendererAlgorithmBase::AlignToSampleBoundary(uint32* value) {
+ (*value) -= ((*value) % (channels_ * sample_bytes_));
+}
+
+template <class Type>
+void AudioRendererAlgorithmBase::Crossfade(int samples, const Type* src,
+ Type* dest) {
+ Type* dest_end = dest + samples * channels_;
+ const Type* src_end = src + samples * channels_;
+ for (int i = 0; i < samples; ++i) {
+ double x_ratio = static_cast<double>(i) / static_cast<double>(samples);
+ for (int j = 0; j < channels_; ++j) {
+ DCHECK(dest < dest_end);
+ DCHECK(src < src_end);
+ (*dest) = static_cast<Type>((*dest) * (1.0 - x_ratio) +
+ (*src) * x_ratio);
+ ++src;
+ ++dest;
+ }
+ }
}
AudioRendererAlgorithmBase::~AudioRendererAlgorithmBase() {}
@@ -58,7 +244,7 @@ void AudioRendererAlgorithmBase::Initialize(
request_read_callback_ = callback;
- set_playback_rate(initial_playback_rate);
+ SetPlaybackRate(initial_playback_rate);
}
void AudioRendererAlgorithmBase::FlushBuffers() {
@@ -85,11 +271,6 @@ float AudioRendererAlgorithmBase::playback_rate() {
return playback_rate_;
}
-void AudioRendererAlgorithmBase::set_playback_rate(float new_rate) {
- DCHECK_GE(new_rate, 0.0);
- playback_rate_ = new_rate;
-}
-
bool AudioRendererAlgorithmBase::IsQueueEmpty() {
return queue_.forward_bytes() == 0;
}
@@ -125,16 +306,4 @@ uint32 AudioRendererAlgorithmBase::CopyFromInput(uint8* dest, uint32 bytes) {
return queue_.Peek(dest, bytes);
}
-int AudioRendererAlgorithmBase::channels() {
- return channels_;
-}
-
-int AudioRendererAlgorithmBase::sample_rate() {
- return sample_rate_;
-}
-
-int AudioRendererAlgorithmBase::sample_bytes() {
- return sample_bytes_;
-}
-
} // namespace media
diff --git a/media/filters/audio_renderer_algorithm_base.h b/media/filters/audio_renderer_algorithm_base.h
index af6381d..c6888c2 100644
--- a/media/filters/audio_renderer_algorithm_base.h
+++ b/media/filters/audio_renderer_algorithm_base.h
@@ -2,23 +2,22 @@
// 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 a BufferQueue which hides Buffer boundaries from
-// subclasses and allows them to access data by byte. Subclasses must implement
-// the following method:
+// AudioRendererAlgorithmBase buffers and transforms audio data. The owner of
+// this object provides audio data to the object through EnqueueBuffer() and
+// requests data from the buffer via FillBuffer(). The owner also sets the
+// playback rate, and the AudioRendererAlgorithm will stretch or compress the
+// buffered audio as necessary to match the playback rate when fulfilling
+// FillBuffer() requests. AudioRendererAlgorithm can request more data to be
+// buffered via a read callback passed in during initialization.
//
-// FillBuffer() - fills the buffer passed to it & returns how many bytes
-// copied.
+// This class is *not* thread-safe. Calls to enqueue and retrieve data must be
+// locked if called from multiple threads.
//
-// 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().
+// AudioRendererAlgorithmBase uses a simple pitch-preservation algorithm to
+// stretch and compress audio data to meet playback speeds less than and
+// greater than the natural playback of the audio stream.
//
-// 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.
+// Audio at very low or very high playback rates are muted to preserve quality.
#ifndef MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_BASE_H_
#define MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_BASE_H_
@@ -26,6 +25,7 @@
#include <deque>
#include "base/callback.h"
+#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "media/base/seekable_buffer.h"
@@ -37,48 +37,47 @@ class Buffer;
class MEDIA_EXPORT AudioRendererAlgorithmBase {
public:
AudioRendererAlgorithmBase();
- virtual ~AudioRendererAlgorithmBase();
+ ~AudioRendererAlgorithmBase();
// Checks validity of audio parameters and takes ownership of |callback|.
- virtual void Initialize(int channels,
+ void Initialize(int channels,
int sample_rate,
int sample_bits,
float initial_playback_rate,
const base::Closure& callback);
- // Implement this strategy method in derived classes. Tries to fill |length|
- // bytes of |dest| with possibly scaled data from our |queue_|. Returns the
- // number of bytes copied into |dest|.
- virtual uint32 FillBuffer(uint8* dest, uint32 length) = 0;
+ // Tries to fill |length| bytes of |dest| with possibly scaled data from
+ // our |queue_|. Returns the number of bytes copied into |dest|.
+ uint32 FillBuffer(uint8* dest, uint32 length);
// Clears |queue_|.
- virtual void FlushBuffers();
+ void FlushBuffers();
// Returns the time of the next byte in our data or kNoTimestamp if current
// time is unknown.
- virtual base::TimeDelta GetTime();
+ base::TimeDelta GetTime();
// Enqueues a buffer. It is called from the owner of the algorithm after a
// read completes.
- virtual void EnqueueBuffer(Buffer* buffer_in);
+ void EnqueueBuffer(Buffer* buffer_in);
// Getter/setter for |playback_rate_|.
- virtual float playback_rate();
- virtual void set_playback_rate(float new_rate);
+ float playback_rate();
+ void SetPlaybackRate(float new_rate);
// Returns whether |queue_| is empty.
- virtual bool IsQueueEmpty();
+ bool IsQueueEmpty();
// Returns true if we have enough data
- virtual bool IsQueueFull();
+ bool IsQueueFull();
// Returns the number of bytes left in |queue_|.
- virtual uint32 QueueSize();
+ uint32 QueueSize();
// Increase the capacity of |queue_| if possible.
- virtual void IncreaseQueueCapacity();
+ void IncreaseQueueCapacity();
- protected:
+ private:
// Advances |queue_|'s internal pointer by |bytes|.
void AdvanceInputPosition(uint32 bytes);
@@ -90,16 +89,25 @@ class MEDIA_EXPORT AudioRendererAlgorithmBase {
// the current sample rate, channel count, and bytes per sample.
int DurationToBytes(int duration_in_milliseconds) const;
- // Number of audio channels.
- virtual int channels();
-
- // Sample rate in hertz.
- virtual int sample_rate();
+ FRIEND_TEST_ALL_PREFIXES(AudioRendererAlgorithmBaseTest,
+ FillBuffer_NormalRate);
+ FRIEND_TEST_ALL_PREFIXES(AudioRendererAlgorithmBaseTest,
+ FillBuffer_DoubleRate);
+ FRIEND_TEST_ALL_PREFIXES(AudioRendererAlgorithmBaseTest,
+ FillBuffer_HalfRate);
+ FRIEND_TEST_ALL_PREFIXES(AudioRendererAlgorithmBaseTest,
+ FillBuffer_QuarterRate);
+
+ // Aligns |value| to a channel and sample boundary.
+ void AlignToSampleBoundary(uint32* value);
+
+ // 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,
+ // sizeof(one sample) == sizeof(Type) * channels.
+ template <class Type>
+ void Crossfade(int samples, const Type* src, Type* dest);
- // Number of bytes per sample per channel.
- virtual int sample_bytes();
-
- private:
// Audio properties.
int channels_;
int sample_rate_;
@@ -117,6 +125,18 @@ class MEDIA_EXPORT AudioRendererAlgorithmBase {
// Largest capacity queue_ can grow to.
size_t max_queue_capacity_;
+ // Members for ease of calculation in FillBuffer(). These members are based
+ // on |playback_rate_|, but are stored separately so they don't have to be
+ // recalculated on every call to FillBuffer().
+ uint32 input_step_;
+ uint32 output_step_;
+
+ // Length for crossfade in bytes.
+ uint32 crossfade_size_;
+
+ // Window size, in bytes (calculated from audio properties).
+ uint32 window_size_;
+
DISALLOW_COPY_AND_ASSIGN(AudioRendererAlgorithmBase);
};
diff --git a/media/filters/audio_renderer_algorithm_ola_unittest.cc b/media/filters/audio_renderer_algorithm_base_unittest.cc
index 39d89c3..489182e 100644
--- a/media/filters/audio_renderer_algorithm_ola_unittest.cc
+++ b/media/filters/audio_renderer_algorithm_base_unittest.cc
@@ -11,7 +11,7 @@
#include "base/bind.h"
#include "base/callback.h"
#include "media/base/data_buffer.h"
-#include "media/filters/audio_renderer_algorithm_ola.h"
+#include "media/filters/audio_renderer_algorithm_base.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,30 +19,16 @@ using ::testing::AnyNumber;
namespace media {
-class MockDataProvider {
- public:
- MockDataProvider() {}
-
- MOCK_METHOD0(Read, void());
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockDataProvider);
-};
-
static const int kChannels = 1;
static const int kSampleRate = 1000;
static const int kSampleBits = 8;
+static void DoNothing() {}
-TEST(AudioRendererAlgorithmOLATest, FillBuffer_NormalRate) {
+TEST(AudioRendererAlgorithmBaseTest, FillBuffer_NormalRate) {
// When playback rate == 1.0f: straight copy of whatever is in |queue_|.
- MockDataProvider mock;
- AudioRendererAlgorithmOLA algorithm;
+ AudioRendererAlgorithmBase algorithm;
algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 1.0f,
- base::Bind(&MockDataProvider::Read,
- base::Unretained(&mock)));
-
- // We won't reply to any read requests.
- EXPECT_CALL(mock, Read()).Times(AnyNumber());
+ base::Bind(&DoNothing));
// Enqueue a buffer of any size since it doesn't matter.
const size_t kDataSize = 1024;
@@ -55,16 +41,11 @@ TEST(AudioRendererAlgorithmOLATest, FillBuffer_NormalRate) {
EXPECT_EQ(0u, algorithm.QueueSize());
}
-TEST(AudioRendererAlgorithmOLATest, FillBuffer_DoubleRate) {
+TEST(AudioRendererAlgorithmBaseTest, FillBuffer_DoubleRate) {
// When playback rate > 1.0f: input is read faster than output is written.
- MockDataProvider mock;
- AudioRendererAlgorithmOLA algorithm;
+ AudioRendererAlgorithmBase algorithm;
algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 2.0f,
- base::Bind(&MockDataProvider::Read,
- base::Unretained(&mock)));
-
- // We won't reply to any read requests.
- EXPECT_CALL(mock, Read()).Times(AnyNumber());
+ base::Bind(&DoNothing));
// First parameter is the input buffer size, second parameter is how much data
// we expect to consume in order to have no data left in the |algorithm|.
@@ -92,16 +73,11 @@ TEST(AudioRendererAlgorithmOLATest, FillBuffer_DoubleRate) {
}
}
-TEST(AudioRendererAlgorithmOLATest, FillBuffer_HalfRate) {
+TEST(AudioRendererAlgorithmBaseTest, FillBuffer_HalfRate) {
// When playback rate < 1.0f: input is read slower than output is written.
- MockDataProvider mock;
- AudioRendererAlgorithmOLA algorithm;
+ AudioRendererAlgorithmBase algorithm;
algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 0.5f,
- base::Bind(&MockDataProvider::Read,
- base::Unretained(&mock)));
-
- // We won't reply to any read requests.
- EXPECT_CALL(mock, Read()).Times(AnyNumber());
+ base::Bind(&DoNothing));
// First parameter is the input buffer size, second parameter is how much data
// we expect to consume in order to have no data left in the |algorithm|.
@@ -129,16 +105,11 @@ TEST(AudioRendererAlgorithmOLATest, FillBuffer_HalfRate) {
}
}
-TEST(AudioRendererAlgorithmOLATest, FillBuffer_QuarterRate) {
+TEST(AudioRendererAlgorithmBaseTest, FillBuffer_QuarterRate) {
// When playback rate is very low the audio is simply muted.
- MockDataProvider mock;
- AudioRendererAlgorithmOLA algorithm;
+ AudioRendererAlgorithmBase algorithm;
algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 0.25f,
- base::Bind(&MockDataProvider::Read,
- base::Unretained(&mock)));
-
- // We won't reply to any read requests.
- EXPECT_CALL(mock, Read()).Times(AnyNumber());
+ base::Bind(&DoNothing));
// First parameter is the input buffer size, second parameter is how much data
// we expect to consume in order to have no data left in the |algorithm|.
diff --git a/media/filters/audio_renderer_algorithm_default.cc b/media/filters/audio_renderer_algorithm_default.cc
deleted file mode 100644
index 7ebc10e..0000000
--- a/media/filters/audio_renderer_algorithm_default.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2010 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"
-
-#include "media/base/buffers.h"
-
-namespace media {
-
-AudioRendererAlgorithmDefault::AudioRendererAlgorithmDefault() {
-}
-
-AudioRendererAlgorithmDefault::~AudioRendererAlgorithmDefault() {
-}
-
-uint32 AudioRendererAlgorithmDefault::FillBuffer(uint8* dest, uint32 length) {
- if (playback_rate() == 0.0f) {
- return 0;
- }
-
- uint32 dest_written = 0;
-
- if (playback_rate() == 1.0f) {
- // If we don't have enough data, copy what we have.
- if (QueueSize() < length)
- dest_written = CopyFromInput(dest, QueueSize());
- else
- dest_written = CopyFromInput(dest, length);
- AdvanceInputPosition(dest_written);
- } else {
- // Mute (we will write to the whole buffer, so set |dest_written| to the
- // requested size).
- dest_written = length;
- memset(dest, 0, dest_written);
-
- // Calculate the number of bytes we "used".
- uint32 scaled_dest_length =
- static_cast<uint32>(dest_written * 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;
-}
-
-} // namespace media
diff --git a/media/filters/audio_renderer_algorithm_default.h b/media/filters/audio_renderer_algorithm_default.h
deleted file mode 100644
index 7950542..0000000
--- a/media/filters/audio_renderer_algorithm_default.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2011 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, FillBuffer()
-// 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 "media/filters/audio_renderer_algorithm_base.h"
-
-namespace media {
-
-class AudioRendererAlgorithmDefault : public AudioRendererAlgorithmBase {
- public:
- AudioRendererAlgorithmDefault();
- virtual ~AudioRendererAlgorithmDefault();
-
- // AudioRendererAlgorithmBase implementation
- virtual uint32 FillBuffer(uint8* dest, uint32 length) OVERRIDE;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AudioRendererAlgorithmDefault);
-};
-
-} // namespace media
-
-#endif // MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_DEFAULT_H_
diff --git a/media/filters/audio_renderer_algorithm_ola.cc b/media/filters/audio_renderer_algorithm_ola.cc
deleted file mode 100644
index db0f348..0000000
--- a/media/filters/audio_renderer_algorithm_ola.cc
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (c) 2010 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_ola.h"
-
-#include <algorithm>
-#include <cmath>
-
-#include "base/logging.h"
-#include "media/base/buffers.h"
-
-namespace media {
-
-// Default window and crossfade lengths in seconds.
-const double kDefaultWindowLength = 0.08;
-const double kDefaultCrossfadeLength = 0.008;
-
-// Default mute ranges for fast/slow audio. These rates would sound better
-// under a frequency domain algorithm.
-const float kMinRate = 0.5f;
-const float kMaxRate = 4.0f;
-
-AudioRendererAlgorithmOLA::AudioRendererAlgorithmOLA()
- : input_step_(0),
- output_step_(0),
- crossfade_size_(0),
- window_size_(0) {
-}
-
-AudioRendererAlgorithmOLA::~AudioRendererAlgorithmOLA() {
-}
-
-uint32 AudioRendererAlgorithmOLA::FillBuffer(uint8* dest, uint32 length) {
- if (IsQueueEmpty())
- return 0;
- if (playback_rate() == 0.0f)
- return 0;
-
- uint32 dest_written = 0;
-
- // Handle the simple case of normal playback.
- if (playback_rate() == 1.0f) {
- if (QueueSize() < length)
- dest_written = CopyFromInput(dest, QueueSize());
- else
- dest_written = CopyFromInput(dest, length);
- AdvanceInputPosition(dest_written);
- return dest_written;
- }
-
- // For other playback rates, OLA with crossfade!
- while (true) {
- // Mute when out of acceptable quality range or when we don't have enough
- // data to completely finish this loop.
- //
- // Note: This may not play at the speed requested as we can only consume as
- // much data as we have, and audio timestamps drive the pipeline clock.
- //
- // Furthermore, we won't end up scaling the very last bit of audio, but
- // we're talking about <8ms of audio data.
- if (playback_rate() < kMinRate || playback_rate() > kMaxRate ||
- QueueSize() < window_size_) {
- // Calculate the ideal input/output steps based on the size of the
- // destination buffer.
- uint32 input_step = static_cast<uint32>(ceil(
- static_cast<float>(length * playback_rate())));
- uint32 output_step = length;
-
- // If the ideal size is too big, recalculate based on how much is left in
- // the queue.
- if (input_step > QueueSize()) {
- input_step = QueueSize();
- output_step = static_cast<uint32>(ceil(
- static_cast<float>(input_step / playback_rate())));
- }
-
- // Stay aligned and sanity check before writing out zeros.
- AlignToSampleBoundary(&input_step);
- AlignToSampleBoundary(&output_step);
- DCHECK_LE(output_step, length);
- if (output_step > length) {
- LOG(ERROR) << "OLA: output_step (" << output_step << ") calculated to "
- << "be larger than destination length (" << length << ")";
- output_step = length;
- }
-
- memset(dest, 0, output_step);
- AdvanceInputPosition(input_step);
- dest_written += output_step;
- break;
- }
-
- // Break if we don't have enough room left in our buffer to do a full
- // OLA iteration.
- if (length < (output_step_ + crossfade_size_)) {
- 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 remaining requested.
- uint32 copied = CopyFromInput(dest, output_step_ + crossfade_size_);
- dest_written += copied;
- length -= copied;
-
- // Advance pointers for crossfade.
- dest += output_step_;
- AdvanceInputPosition(input_step_);
-
- // Prepare intermediate buffer.
- uint32 crossfade_size;
- scoped_array<uint8> src(new uint8[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()
- / channels());
- switch (sample_bytes()) {
- case 4:
- Crossfade(samples,
- reinterpret_cast<const int32*>(src.get()),
- reinterpret_cast<int32*>(dest));
- break;
- case 2:
- Crossfade(samples,
- reinterpret_cast<const int16*>(src.get()),
- reinterpret_cast<int16*>(dest));
- break;
- case 1:
- Crossfade(samples, src.get(), dest);
- break;
- default:
- NOTREACHED() << "Unsupported audio bit depth sent to OLA algorithm";
- }
-
- // Advance pointers again.
- AdvanceInputPosition(crossfade_size);
- dest += crossfade_size_;
- }
- return dest_written;
-}
-
-void AudioRendererAlgorithmOLA::set_playback_rate(float new_rate) {
- AudioRendererAlgorithmBase::set_playback_rate(new_rate);
-
- // Calculate the window size from our default length and our audio properties.
- // Precision is not an issue because we will round this to a sample boundary.
- // This will not overflow because each parameter is checked in Initialize().
- window_size_ = static_cast<uint32>(sample_rate()
- * sample_bytes()
- * channels()
- * kDefaultWindowLength);
-
- // Adjusting step sizes to accommodate requested playback rate.
- if (playback_rate() > 1.0f) {
- input_step_ = window_size_;
- output_step_ = static_cast<uint32>(ceil(
- static_cast<float>(window_size_ / playback_rate())));
- } else {
- input_step_ = static_cast<uint32>(ceil(
- static_cast<float>(window_size_ * playback_rate())));
- output_step_ = window_size_;
- }
- AlignToSampleBoundary(&input_step_);
- AlignToSampleBoundary(&output_step_);
-
- // Calculate length for crossfading.
- crossfade_size_ = static_cast<uint32>(sample_rate()
- * sample_bytes()
- * channels()
- * kDefaultCrossfadeLength);
- AlignToSampleBoundary(&crossfade_size_);
- if (crossfade_size_ > std::min(input_step_, output_step_)) {
- crossfade_size_ = 0;
- return;
- }
-
- // To keep true to playback rate, modify the steps.
- input_step_ -= crossfade_size_;
- output_step_ -= crossfade_size_;
-}
-
-void AudioRendererAlgorithmOLA::AlignToSampleBoundary(uint32* value) {
- (*value) -= ((*value) % (channels() * sample_bytes()));
-}
-
-template <class Type>
-void AudioRendererAlgorithmOLA::Crossfade(int samples,
- const Type* src,
- Type* dest) {
- Type* dest_end = dest + samples * channels();
- const Type* src_end = src + samples * channels();
- for (int i = 0; i < samples; ++i) {
- double x_ratio = static_cast<double>(i) / static_cast<double>(samples);
- for (int j = 0; j < channels(); ++j) {
- DCHECK(dest < dest_end);
- DCHECK(src < src_end);
- (*dest) = static_cast<Type>((*dest) * (1.0 - x_ratio) +
- (*src) * x_ratio);
- ++src;
- ++dest;
- }
- }
-}
-
-} // namespace media
diff --git a/media/filters/audio_renderer_algorithm_ola.h b/media/filters/audio_renderer_algorithm_ola.h
deleted file mode 100644
index 8cefcbf..0000000
--- a/media/filters/audio_renderer_algorithm_ola.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2011 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.
-
-// 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|. ARAO will mute the audio for very high or
-// very low playback rates to preserve quality. As ARAB is thread-unsafe, so is
-// ARAO.
-
-#ifndef MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_OLA_H_
-#define MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_OLA_H_
-
-#include "base/gtest_prod_util.h"
-#include "media/filters/audio_renderer_algorithm_base.h"
-
-namespace media {
-
-class MEDIA_EXPORT AudioRendererAlgorithmOLA
- : public AudioRendererAlgorithmBase {
- public:
- AudioRendererAlgorithmOLA();
- virtual ~AudioRendererAlgorithmOLA();
-
- // AudioRendererAlgorithmBase implementation
- virtual uint32 FillBuffer(uint8* dest, uint32 length) OVERRIDE;
-
- virtual void set_playback_rate(float new_rate) OVERRIDE;
-
- private:
- FRIEND_TEST_ALL_PREFIXES(AudioRendererAlgorithmOLATest,
- FillBuffer_NormalRate);
- FRIEND_TEST_ALL_PREFIXES(AudioRendererAlgorithmOLATest,
- FillBuffer_DoubleRate);
- FRIEND_TEST_ALL_PREFIXES(AudioRendererAlgorithmOLATest,
- FillBuffer_HalfRate);
- FRIEND_TEST_ALL_PREFIXES(AudioRendererAlgorithmOLATest,
- FillBuffer_QuarterRate);
-
- // Aligns |value| to a channel and sample boundary.
- void AlignToSampleBoundary(uint32* value);
-
- // 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,
- // sizeof(one sample) == sizeof(Type) * channels.
- template <class Type>
- void Crossfade(int samples, const Type* src, Type* dest);
-
- // Members for ease of calculation in FillBuffer(). These members are based
- // on |playback_rate_|, but are stored separately so they don't have to be
- // recalculated on every call to FillBuffer().
- uint32 input_step_;
- uint32 output_step_;
-
- // Length for crossfade in bytes.
- uint32 crossfade_size_;
-
- // Window size, in bytes (calculated from audio properties).
- uint32 window_size_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioRendererAlgorithmOLA);
-};
-
-} // namespace media
-
-#endif // MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_OLA_H_
diff --git a/media/filters/audio_renderer_base.cc b/media/filters/audio_renderer_base.cc
index 7960b07..03c9ed0 100644
--- a/media/filters/audio_renderer_base.cc
+++ b/media/filters/audio_renderer_base.cc
@@ -11,7 +11,6 @@
#include "base/callback.h"
#include "base/logging.h"
#include "media/base/filter_host.h"
-#include "media/filters/audio_renderer_algorithm_ola.h"
namespace media {
@@ -103,7 +102,7 @@ void AudioRendererBase::Initialize(AudioDecoder* decoder,
base::Closure cb = base::Bind(&AudioRendererBase::ScheduleRead_Locked, this);
// Construct the algorithm.
- algorithm_.reset(new AudioRendererAlgorithmOLA());
+ algorithm_.reset(new AudioRendererAlgorithmBase());
// Initialize our algorithm with media properties, initial playback rate,
// and a callback to request more reads from the data source.
@@ -286,7 +285,7 @@ void AudioRendererBase::ScheduleRead_Locked() {
}
void AudioRendererBase::SetPlaybackRate(float playback_rate) {
- algorithm_->set_playback_rate(playback_rate);
+ algorithm_->SetPlaybackRate(playback_rate);
}
float AudioRendererBase::GetPlaybackRate() {
diff --git a/media/media.gyp b/media/media.gyp
index 3fba5d5..27b9dd2 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -175,10 +175,6 @@
'filters/audio_file_reader.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_algorithm_ola.cc',
- 'filters/audio_renderer_algorithm_ola.h',
'filters/audio_renderer_base.cc',
'filters/audio_renderer_base.h',
'filters/bitstream_converter.cc',
@@ -615,7 +611,7 @@
'base/video_util_unittest.cc',
'base/yuv_convert_unittest.cc',
'ffmpeg/ffmpeg_common_unittest.cc',
- 'filters/audio_renderer_algorithm_ola_unittest.cc',
+ 'filters/audio_renderer_algorithm_base_unittest.cc',
'filters/audio_renderer_base_unittest.cc',
'filters/bitstream_converter_unittest.cc',
'filters/chunk_demuxer_unittest.cc',
@@ -705,17 +701,6 @@
],
},
{
- 'target_name': 'wav_ola_test',
- 'type': 'executable',
- 'dependencies': [
- 'media',
- '../base/base.gyp:base',
- ],
- 'sources': [
- 'tools/wav_ola_test/wav_ola_test.cc'
- ],
- },
- {
'target_name': 'qt_faststart',
'type': 'executable',
'sources': [
diff --git a/media/tools/wav_ola_test/wav_ola_test.cc b/media/tools/wav_ola_test/wav_ola_test.cc
deleted file mode 100644
index 42517f1..0000000
--- a/media/tools/wav_ola_test/wav_ola_test.cc
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright (c) 2011 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.
-
-// This application is a test for AudioRendererAlgorithmOLA. It reads in a
-// specified wav file (so far only 8, 16 and 32 bit are supported) and uses
-// ARAO to scale the playback by a specified rate. Then it outputs the result
-// to the specified location. Command line calls should be as follows:
-//
-// wav_ola_test RATE INFILE OUTFILE
-
-#include <iostream>
-#include <string>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/file_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/string_number_conversions.h"
-#include "base/string_util.h"
-#include "base/utf_string_conversions.h"
-#include "media/base/data_buffer.h"
-#include "media/filters/audio_renderer_algorithm_ola.h"
-
-using file_util::ScopedFILE;
-using media::AudioRendererAlgorithmOLA;
-using media::DataBuffer;
-
-const double kDefaultWindowLength = 0.08;
-
-struct WavHeader {
- int32 riff;
- int32 chunk_size;
- char unused0[8];
- int32 subchunk1_size;
- int16 audio_format;
- int16 channels;
- int32 sample_rate;
- char unused1[6];
- int16 bit_rate;
- char unused2[4];
- int32 subchunk2_size;
-};
-
-// Dummy class to feed data to OLA algorithm. Necessary to create callback.
-class Dummy {
- public:
- Dummy(FILE* in, AudioRendererAlgorithmOLA* ola, size_t window_size)
- : input_(in),
- ola_(ola),
- window_size_(window_size) {
- }
-
- void ReadDataForAlg() {
- scoped_refptr<DataBuffer> buffer(new DataBuffer(window_size_));
- buffer->SetDataSize(window_size_);
- uint8* buf = buffer->GetWritableData();
- if (fread(buf, 1, window_size_, input_) > 0) {
- ola_->EnqueueBuffer(buffer.get());
- }
- }
-
- private:
- FILE* input_;
- AudioRendererAlgorithmOLA* ola_;
- size_t window_size_;
-
- DISALLOW_COPY_AND_ASSIGN(Dummy);
-};
-
-int main(int argc, const char** argv) {
- AudioRendererAlgorithmOLA ola;
- CommandLine::Init(argc, argv);
- const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
-
- const CommandLine::StringVector& filenames = cmd_line->GetArgs();
- if (filenames.empty()) {
- std::cerr << "Usage: " << argv[0] << " RATE INFILE OUTFILE\n"
- << std::endl;
- return 1;
- }
-
- // Retrieve command line options.
- FilePath in_path(filenames[1]);
- FilePath out_path(filenames[2]);
- double playback_rate = 0.0;
-
- // Determine speed of rerecord.
-#if defined(OS_WIN)
- std::string filename_str = WideToASCII(filenames[0]);
-#else
- const std::string& filename_str = filenames[0];
-#endif
- if (!base::StringToDouble(filename_str, &playback_rate))
- playback_rate = 0.0;
-
- // Open input file.
- ScopedFILE input(file_util::OpenFile(in_path, "rb"));
- if (!(input.get())) {
- LOG(ERROR) << "could not open input";
- return 1;
- }
-
- // Open output file.
- ScopedFILE output(file_util::OpenFile(out_path, "wb"));
- if (!(output.get())) {
- LOG(ERROR) << "could not open output";
- return 1;
- }
-
- // Read in header.
- WavHeader wav;
- if (fread(&wav, sizeof(wav), 1, input.get()) < 1) {
- LOG(ERROR) << "could not read WAV header";
- return 1;
- }
-
- size_t window_size = static_cast<size_t>(wav.sample_rate
- * (wav.bit_rate / 8)
- * wav.channels
- * kDefaultWindowLength);
-
- // Instantiate dummy class and callback to feed data to |ola|.
- Dummy guy(input.get(), &ola, window_size);
- base::Closure cb = base::Bind(&Dummy::ReadDataForAlg, base::Unretained(&guy));
- ola.Initialize(wav.channels,
- wav.sample_rate,
- wav.bit_rate,
- static_cast<float>(playback_rate),
- cb);
- ola.FlushBuffers();
-
- // Print out input format.
- std::cout << in_path.value() << "\n"
- << "Channels: " << wav.channels << "\n"
- << "Sample Rate: " << wav.sample_rate << "\n"
- << "Bit Rate: " << wav.bit_rate << "\n"
- << "\n"
- << "Scaling audio by " << playback_rate << "x..." << std::endl;
-
- // Write the header back out again.
- if (fwrite(&wav, sizeof(wav), 1, output.get()) < 1) {
- LOG(ERROR) << "could not write WAV header";
- return 1;
- }
-
- // Create buffer to be filled by |ola|.
- scoped_array<uint8> buf(new uint8[window_size]);
-
- CHECK(buf.get());
-
- // Keep track of bytes written to disk and bytes copied to |b|.
- size_t bytes_written = 0;
- size_t bytes;
- while ((bytes = ola.FillBuffer(buf.get(), window_size)) > 0) {
- if (fwrite(buf.get(), 1, bytes, output.get()) != bytes) {
- LOG(ERROR) << "could not write data after " << bytes_written;
- } else {
- bytes_written += bytes;
- }
- }
-
- // Seek back to the beginning of our output file and update the header.
- wav.chunk_size = 36 + bytes_written;
- wav.subchunk1_size = 16;
- wav.subchunk2_size = bytes_written;
- fseek(output.get(), 0, SEEK_SET);
- if (fwrite(&wav, sizeof(wav), 1, output.get()) < 1) {
- LOG(ERROR) << "could not write wav header.";
- return 1;
- }
- CommandLine::Reset();
- return 0;
-}