Index: media/filters/audio_renderer_algorithm_base.cc |
diff --git a/media/filters/audio_renderer_algorithm_base.cc b/media/filters/audio_renderer_algorithm_base.cc |
deleted file mode 100644 |
index 990c477727e1a8bf09f32f113bb19ffdfd349722..0000000000000000000000000000000000000000 |
--- a/media/filters/audio_renderer_algorithm_base.cc |
+++ /dev/null |
@@ -1,444 +0,0 @@ |
-// Copyright (c) 2012 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" |
- |
-#include <algorithm> |
-#include <cmath> |
- |
-#include "base/logging.h" |
-#include "base/memory/scoped_ptr.h" |
-#include "media/audio/audio_util.h" |
-#include "media/base/buffers.h" |
- |
-namespace media { |
- |
-// The starting size in bytes for |audio_buffer_|. |
-// Previous usage maintained a deque of 16 Buffers, each of size 4Kb. This |
-// worked well, so we maintain this number of bytes (16 * 4096). |
-static const int kStartingBufferSizeInBytes = 65536; |
- |
-// The maximum size in bytes for the |audio_buffer_|. Arbitrarily determined. |
-// This number represents 3 seconds of 96kHz/16 bit 7.1 surround sound. |
-static const int kMaxBufferSizeInBytes = 4608000; |
- |
-// Duration of audio segments used for crossfading (in seconds). |
-static const double kWindowDuration = 0.08; |
- |
-// Duration of crossfade between audio segments (in seconds). |
-static const double kCrossfadeDuration = 0.008; |
- |
-// Max/min supported playback rates for fast/slow audio. Audio outside of these |
-// ranges are muted. |
-// Audio at these speeds would sound better under a frequency domain algorithm. |
-static const float kMinPlaybackRate = 0.5f; |
-static const float kMaxPlaybackRate = 4.0f; |
- |
-AudioRendererAlgorithmBase::AudioRendererAlgorithmBase() |
- : channels_(0), |
- samples_per_second_(0), |
- bytes_per_channel_(0), |
- playback_rate_(0.0f), |
- audio_buffer_(0, kStartingBufferSizeInBytes), |
- bytes_in_crossfade_(0), |
- bytes_per_frame_(0), |
- index_into_window_(0), |
- crossfade_frame_number_(0), |
- muted_(false), |
- needs_more_data_(false), |
- window_size_(0) { |
-} |
- |
-AudioRendererAlgorithmBase::~AudioRendererAlgorithmBase() {} |
- |
-bool AudioRendererAlgorithmBase::ValidateConfig( |
- int channels, |
- int samples_per_second, |
- int bits_per_channel) { |
- bool status = true; |
- |
- if (channels <= 0 || channels > 8) { |
- DVLOG(1) << "We only support audio with between 1 and 8 channels."; |
- status = false; |
- } |
- |
- if (samples_per_second <= 0 || samples_per_second > 256000) { |
- DVLOG(1) << "We only support sample rates between 1 and 256000Hz."; |
- status = false; |
- } |
- |
- if (bits_per_channel != 8 && bits_per_channel != 16 && |
- bits_per_channel != 32) { |
- DVLOG(1) << "We only support 8, 16, 32 bit audio."; |
- status = false; |
- } |
- |
- return status; |
-} |
- |
-void AudioRendererAlgorithmBase::Initialize( |
- int channels, |
- int samples_per_second, |
- int bits_per_channel, |
- float initial_playback_rate, |
- const base::Closure& callback) { |
- DCHECK(!callback.is_null()); |
- DCHECK(ValidateConfig(channels, samples_per_second, bits_per_channel)); |
- |
- channels_ = channels; |
- samples_per_second_ = samples_per_second; |
- bytes_per_channel_ = bits_per_channel / 8; |
- bytes_per_frame_ = bytes_per_channel_ * channels_; |
- request_read_cb_ = callback; |
- SetPlaybackRate(initial_playback_rate); |
- |
- window_size_ = |
- samples_per_second_ * bytes_per_channel_ * channels_ * kWindowDuration; |
- AlignToFrameBoundary(&window_size_); |
- |
- bytes_in_crossfade_ = |
- samples_per_second_ * bytes_per_channel_ * channels_ * kCrossfadeDuration; |
- AlignToFrameBoundary(&bytes_in_crossfade_); |
- |
- crossfade_buffer_.reset(new uint8[bytes_in_crossfade_]); |
-} |
- |
-int AudioRendererAlgorithmBase::FillBuffer( |
- uint8* dest, int requested_frames) { |
- DCHECK_NE(bytes_per_frame_, 0); |
- |
- if (playback_rate_ == 0.0f) |
- return 0; |
- |
- int total_frames_rendered = 0; |
- uint8* output_ptr = dest; |
- while (total_frames_rendered < requested_frames) { |
- if (index_into_window_ == window_size_) |
- ResetWindow(); |
- |
- bool rendered_frame = true; |
- if (playback_rate_ > 1.0) |
- rendered_frame = OutputFasterPlayback(output_ptr); |
- else if (playback_rate_ < 1.0) |
- rendered_frame = OutputSlowerPlayback(output_ptr); |
- else |
- rendered_frame = OutputNormalPlayback(output_ptr); |
- |
- if (!rendered_frame) { |
- needs_more_data_ = true; |
- break; |
- } |
- |
- output_ptr += bytes_per_frame_; |
- total_frames_rendered++; |
- } |
- return total_frames_rendered; |
-} |
- |
-void AudioRendererAlgorithmBase::ResetWindow() { |
- DCHECK_LE(index_into_window_, window_size_); |
- index_into_window_ = 0; |
- crossfade_frame_number_ = 0; |
-} |
- |
-bool AudioRendererAlgorithmBase::OutputFasterPlayback(uint8* dest) { |
- DCHECK_LT(index_into_window_, window_size_); |
- DCHECK_GT(playback_rate_, 1.0); |
- |
- if (audio_buffer_.forward_bytes() < bytes_per_frame_) |
- return false; |
- |
- // The audio data is output in a series of windows. For sped-up playback, |
- // the window is comprised of the following phases: |
- // |
- // a) Output raw data. |
- // b) Save bytes for crossfade in |crossfade_buffer_|. |
- // c) Drop data. |
- // d) Output crossfaded audio leading up to the next window. |
- // |
- // The duration of each phase is computed below based on the |window_size_| |
- // and |playback_rate_|. |
- int input_step = window_size_; |
- int output_step = ceil(window_size_ / playback_rate_); |
- AlignToFrameBoundary(&output_step); |
- DCHECK_GT(input_step, output_step); |
- |
- int bytes_to_crossfade = bytes_in_crossfade_; |
- if (muted_ || bytes_to_crossfade > output_step) |
- bytes_to_crossfade = 0; |
- |
- // This is the index of the end of phase a, beginning of phase b. |
- int outtro_crossfade_begin = output_step - bytes_to_crossfade; |
- |
- // This is the index of the end of phase b, beginning of phase c. |
- int outtro_crossfade_end = output_step; |
- |
- // This is the index of the end of phase c, beginning of phase d. |
- // This phase continues until |index_into_window_| reaches |window_size_|, at |
- // which point the window restarts. |
- int intro_crossfade_begin = input_step - bytes_to_crossfade; |
- |
- // a) Output a raw frame if we haven't reached the crossfade section. |
- if (index_into_window_ < outtro_crossfade_begin) { |
- CopyWithAdvance(dest); |
- index_into_window_ += bytes_per_frame_; |
- return true; |
- } |
- |
- // b) Save outtro crossfade frames into intermediate buffer, but do not output |
- // anything to |dest|. |
- while (index_into_window_ < outtro_crossfade_end) { |
- if (audio_buffer_.forward_bytes() < bytes_per_frame_) |
- return false; |
- |
- // This phase only applies if there are bytes to crossfade. |
- DCHECK_GT(bytes_to_crossfade, 0); |
- uint8* place_to_copy = crossfade_buffer_.get() + |
- (index_into_window_ - outtro_crossfade_begin); |
- CopyWithAdvance(place_to_copy); |
- index_into_window_ += bytes_per_frame_; |
- } |
- |
- // c) Drop frames until we reach the intro crossfade section. |
- while (index_into_window_ < intro_crossfade_begin) { |
- if (audio_buffer_.forward_bytes() < bytes_per_frame_) |
- return false; |
- |
- DropFrame(); |
- index_into_window_ += bytes_per_frame_; |
- } |
- |
- // Return if we have run out of data after Phase c). |
- if (audio_buffer_.forward_bytes() < bytes_per_frame_) |
- return false; |
- |
- // Phase d) doesn't apply if there are no bytes to crossfade. |
- if (bytes_to_crossfade == 0) { |
- DCHECK_EQ(index_into_window_, window_size_); |
- return false; |
- } |
- |
- // d) Crossfade and output a frame. |
- DCHECK_LT(index_into_window_, window_size_); |
- int offset_into_buffer = index_into_window_ - intro_crossfade_begin; |
- memcpy(dest, crossfade_buffer_.get() + offset_into_buffer, |
- bytes_per_frame_); |
- scoped_array<uint8> intro_frame_ptr(new uint8[bytes_per_frame_]); |
- audio_buffer_.Read(intro_frame_ptr.get(), bytes_per_frame_); |
- OutputCrossfadedFrame(dest, intro_frame_ptr.get()); |
- index_into_window_ += bytes_per_frame_; |
- return true; |
-} |
- |
-bool AudioRendererAlgorithmBase::OutputSlowerPlayback(uint8* dest) { |
- DCHECK_LT(index_into_window_, window_size_); |
- DCHECK_LT(playback_rate_, 1.0); |
- DCHECK_NE(playback_rate_, 0.0); |
- |
- if (audio_buffer_.forward_bytes() < bytes_per_frame_) |
- return false; |
- |
- // The audio data is output in a series of windows. For slowed down playback, |
- // the window is comprised of the following phases: |
- // |
- // a) Output raw data. |
- // b) Output and save bytes for crossfade in |crossfade_buffer_|. |
- // c) Output* raw data. |
- // d) Output* crossfaded audio leading up to the next window. |
- // |
- // * Phases c) and d) do not progress |audio_buffer_|'s cursor so that the |
- // |audio_buffer_|'s cursor is in the correct place for the next window. |
- // |
- // The duration of each phase is computed below based on the |window_size_| |
- // and |playback_rate_|. |
- int input_step = ceil(window_size_ * playback_rate_); |
- AlignToFrameBoundary(&input_step); |
- int output_step = window_size_; |
- DCHECK_LT(input_step, output_step); |
- |
- int bytes_to_crossfade = bytes_in_crossfade_; |
- if (muted_ || bytes_to_crossfade > input_step) |
- bytes_to_crossfade = 0; |
- |
- // This is the index of the end of phase a, beginning of phase b. |
- int intro_crossfade_begin = input_step - bytes_to_crossfade; |
- |
- // This is the index of the end of phase b, beginning of phase c. |
- int intro_crossfade_end = input_step; |
- |
- // This is the index of the end of phase c, beginning of phase d. |
- // This phase continues until |index_into_window_| reaches |window_size_|, at |
- // which point the window restarts. |
- int outtro_crossfade_begin = output_step - bytes_to_crossfade; |
- |
- // a) Output a raw frame. |
- if (index_into_window_ < intro_crossfade_begin) { |
- CopyWithAdvance(dest); |
- index_into_window_ += bytes_per_frame_; |
- return true; |
- } |
- |
- // b) Save the raw frame for the intro crossfade section, then output the |
- // frame to |dest|. |
- if (index_into_window_ < intro_crossfade_end) { |
- int offset = index_into_window_ - intro_crossfade_begin; |
- uint8* place_to_copy = crossfade_buffer_.get() + offset; |
- CopyWithoutAdvance(place_to_copy); |
- CopyWithAdvance(dest); |
- index_into_window_ += bytes_per_frame_; |
- return true; |
- } |
- |
- int audio_buffer_offset = index_into_window_ - intro_crossfade_end; |
- |
- if (audio_buffer_.forward_bytes() < audio_buffer_offset + bytes_per_frame_) |
- return false; |
- |
- // c) Output a raw frame into |dest| without advancing the |audio_buffer_| |
- // cursor. See function-level comment. |
- DCHECK_GE(index_into_window_, intro_crossfade_end); |
- CopyWithoutAdvance(dest, audio_buffer_offset); |
- |
- // d) Crossfade the next frame of |crossfade_buffer_| into |dest| if we've |
- // reached the outtro crossfade section of the window. |
- if (index_into_window_ >= outtro_crossfade_begin) { |
- int offset_into_crossfade_buffer = |
- index_into_window_ - outtro_crossfade_begin; |
- uint8* intro_frame_ptr = |
- crossfade_buffer_.get() + offset_into_crossfade_buffer; |
- OutputCrossfadedFrame(dest, intro_frame_ptr); |
- } |
- |
- index_into_window_ += bytes_per_frame_; |
- return true; |
-} |
- |
-bool AudioRendererAlgorithmBase::OutputNormalPlayback(uint8* dest) { |
- if (audio_buffer_.forward_bytes() >= bytes_per_frame_) { |
- CopyWithAdvance(dest); |
- index_into_window_ += bytes_per_frame_; |
- return true; |
- } |
- return false; |
-} |
- |
-void AudioRendererAlgorithmBase::CopyWithAdvance(uint8* dest) { |
- CopyWithoutAdvance(dest); |
- DropFrame(); |
-} |
- |
-void AudioRendererAlgorithmBase::CopyWithoutAdvance(uint8* dest) { |
- CopyWithoutAdvance(dest, 0); |
-} |
- |
-void AudioRendererAlgorithmBase::CopyWithoutAdvance( |
- uint8* dest, int offset) { |
- if (muted_) { |
- memset(dest, 0, bytes_per_frame_); |
- return; |
- } |
- int copied = audio_buffer_.Peek(dest, bytes_per_frame_, offset); |
- DCHECK_EQ(bytes_per_frame_, copied); |
-} |
- |
-void AudioRendererAlgorithmBase::DropFrame() { |
- audio_buffer_.Seek(bytes_per_frame_); |
- |
- if (!IsQueueFull()) |
- request_read_cb_.Run(); |
-} |
- |
-void AudioRendererAlgorithmBase::OutputCrossfadedFrame( |
- uint8* outtro, const uint8* intro) { |
- DCHECK_LE(index_into_window_, window_size_); |
- DCHECK(!muted_); |
- |
- switch (bytes_per_channel_) { |
- case 4: |
- CrossfadeFrame<int32>(outtro, intro); |
- break; |
- case 2: |
- CrossfadeFrame<int16>(outtro, intro); |
- break; |
- case 1: |
- CrossfadeFrame<uint8>(outtro, intro); |
- break; |
- default: |
- NOTREACHED() << "Unsupported audio bit depth in crossfade."; |
- } |
-} |
- |
-template <class Type> |
-void AudioRendererAlgorithmBase::CrossfadeFrame( |
- uint8* outtro_bytes, const uint8* intro_bytes) { |
- Type* outtro = reinterpret_cast<Type*>(outtro_bytes); |
- const Type* intro = reinterpret_cast<const Type*>(intro_bytes); |
- |
- int frames_in_crossfade = bytes_in_crossfade_ / bytes_per_frame_; |
- float crossfade_ratio = |
- static_cast<float>(crossfade_frame_number_) / frames_in_crossfade; |
- for (int channel = 0; channel < channels_; ++channel) { |
- *outtro *= 1.0 - crossfade_ratio; |
- *outtro++ += (*intro++) * crossfade_ratio; |
- } |
- crossfade_frame_number_++; |
-} |
- |
-void AudioRendererAlgorithmBase::SetPlaybackRate(float new_rate) { |
- DCHECK_GE(new_rate, 0.0); |
- playback_rate_ = new_rate; |
- muted_ = |
- playback_rate_ < kMinPlaybackRate || playback_rate_ > kMaxPlaybackRate; |
- |
- ResetWindow(); |
-} |
- |
-void AudioRendererAlgorithmBase::AlignToFrameBoundary(int* value) { |
- (*value) -= ((*value) % bytes_per_frame_); |
-} |
- |
-void AudioRendererAlgorithmBase::FlushBuffers() { |
- ResetWindow(); |
- |
- // Clear the queue of decoded packets (releasing the buffers). |
- audio_buffer_.Clear(); |
- request_read_cb_.Run(); |
-} |
- |
-base::TimeDelta AudioRendererAlgorithmBase::GetTime() { |
- return audio_buffer_.current_time(); |
-} |
- |
-void AudioRendererAlgorithmBase::EnqueueBuffer(Buffer* buffer_in) { |
- DCHECK(!buffer_in->IsEndOfStream()); |
- audio_buffer_.Append(buffer_in); |
- needs_more_data_ = false; |
- |
- // If we still don't have enough data, request more. |
- if (!IsQueueFull()) |
- request_read_cb_.Run(); |
-} |
- |
-bool AudioRendererAlgorithmBase::NeedsMoreData() { |
- return needs_more_data_ || IsQueueEmpty(); |
-} |
- |
-bool AudioRendererAlgorithmBase::IsQueueEmpty() { |
- return audio_buffer_.forward_bytes() == 0; |
-} |
- |
-bool AudioRendererAlgorithmBase::IsQueueFull() { |
- return audio_buffer_.forward_bytes() >= audio_buffer_.forward_capacity(); |
-} |
- |
-int AudioRendererAlgorithmBase::QueueCapacity() { |
- return audio_buffer_.forward_capacity(); |
-} |
- |
-void AudioRendererAlgorithmBase::IncreaseQueueCapacity() { |
- audio_buffer_.set_forward_capacity( |
- std::min(2 * audio_buffer_.forward_capacity(), kMaxBufferSizeInBytes)); |
-} |
- |
-} // namespace media |