diff options
author | fbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-23 22:56:35 +0000 |
---|---|---|
committer | fbarchard@chromium.org <fbarchard@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-04-23 22:56:35 +0000 |
commit | 32a61d0268edcef77e2d4300c9287414ecc52fe6 (patch) | |
tree | fcae08e54b86ecf58686150a6b0a60a2368ef766 /media | |
parent | 1ed60a369d47c7fce9a92d52513486960f63506d (diff) | |
download | chromium_src-32a61d0268edcef77e2d4300c9287414ecc52fe6.zip chromium_src-32a61d0268edcef77e2d4300c9287414ecc52fe6.tar.gz chromium_src-32a61d0268edcef77e2d4300c9287414ecc52fe6.tar.bz2 |
Prototype audio time shift.
Review URL: http://codereview.chromium.org/92007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@14366 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/audio/win/waveout_output_win.cc | 5 | ||||
-rw-r--r-- | media/base/filter_host_impl.cc | 2 | ||||
-rw-r--r-- | media/filters/audio_renderer_base.cc | 100 | ||||
-rw-r--r-- | media/filters/audio_renderer_base.h | 2 | ||||
-rw-r--r-- | media/filters/audio_renderer_impl.cc | 22 | ||||
-rw-r--r-- | media/filters/audio_renderer_impl.h | 5 | ||||
-rw-r--r-- | media/filters/null_audio_renderer.cc | 2 |
7 files changed, 82 insertions, 56 deletions
diff --git a/media/audio/win/waveout_output_win.cc b/media/audio/win/waveout_output_win.cc index 9a3f581..2f5d8ab 100644 --- a/media/audio/win/waveout_output_win.cc +++ b/media/audio/win/waveout_output_win.cc @@ -218,8 +218,8 @@ void PCMWaveOutAudioOutputStream::GetVolume(double* left_level, HandleError(res); return; } - *left_level = double(LOWORD(volume_packed)) / kMaxVolumeLevel; - *right_level = double(HIWORD(volume_packed)) / kMaxVolumeLevel; + *left_level = static_cast<double>(LOWORD(volume_packed)) / kMaxVolumeLevel; + *right_level = static_cast<double>(HIWORD(volume_packed)) / kMaxVolumeLevel; } size_t PCMWaveOutAudioOutputStream::GetNumBuffers() { @@ -234,6 +234,7 @@ void PCMWaveOutAudioOutputStream::HandleError(MMRESULT error) { void PCMWaveOutAudioOutputStream::QueueNextPacket(WAVEHDR *buffer) { // Call the source which will fill our buffer with pleasant sounds and // return to us how many bytes were used. + // TODO(fbarchard): Handle used 0 by queueing more. size_t used = callback_->OnMoreData(this, buffer->lpData, buffer_size_); if (used <= buffer_size_) { buffer->dwBufferLength = used; diff --git a/media/base/filter_host_impl.cc b/media/base/filter_host_impl.cc index cba2eb1..6cf39cd 100644 --- a/media/base/filter_host_impl.cc +++ b/media/base/filter_host_impl.cc @@ -45,7 +45,7 @@ void FilterHostImpl::ScheduleTimeUpdateCallback(base::TimeDelta time) { time -= pipeline()->GetInterpolatedTime(); int delay = static_cast<int>(time.InMilliseconds()); float rate = pipeline()->GetPlaybackRate(); - if (rate != 1.0f && rate != 0.0f) { + if (rate > 0.0f) { delay = static_cast<int>(delay / rate); } if (delay > 0) { diff --git a/media/filters/audio_renderer_base.cc b/media/filters/audio_renderer_base.cc index 01a8737..28acd82 100644 --- a/media/filters/audio_renderer_base.cc +++ b/media/filters/audio_renderer_base.cc @@ -79,54 +79,71 @@ void AudioRendererBase::OnReadComplete(Buffer* buffer_in) { } } -size_t AudioRendererBase::FillBuffer(uint8* dest, size_t len) { +size_t AudioRendererBase::FillBuffer(uint8* dest, size_t dest_len, + float rate) { // Update the pipeline's time. host_->SetTime(last_fill_buffer_time_); - size_t result = 0; size_t buffers_released = 0; - { - AutoLock auto_lock(lock_); - // Loop until the buffer has been filled. - while (len > 0 && !queue_.empty()) { - Buffer* buffer = queue_.front(); + size_t dest_written = 0; - // Determine how much to copy. - const uint8* data = buffer->GetData() + data_offset_; - size_t data_len = buffer->GetDataSize() - data_offset_; - data_len = std::min(len, data_len); + AutoLock auto_lock(lock_); + // Loop until the buffer has been filled. + while (dest_len > 0 && !queue_.empty()) { + Buffer* buffer = queue_.front(); + + // Determine how much to copy. + const uint8* data = buffer->GetData() + data_offset_; + size_t data_len = buffer->GetDataSize() - data_offset_; + + // New scaled packet size aligned to 16 to ensure its on a + // channel/sample boundary. Only guaranteed to works for power of 2 + // number of channels and sample size. + size_t scaled_data_len = (rate <= 0.0f) ? 0 : + static_cast<size_t>(data_len / rate) & ~15; + if (scaled_data_len > dest_len) { + data_len = (data_len * dest_len / scaled_data_len) & ~15; + scaled_data_len = dest_len; + } - // Copy into buffer. + if (rate >= 1.0f) { // Speed up. + memcpy(dest, data, scaled_data_len); + } else if (rate >= 0.5) { // Slow down. memcpy(dest, data, data_len); - len -= data_len; - dest += data_len; - data_offset_ += data_len; - result += data_len; - + memcpy(dest + data_len, data, scaled_data_len - data_len); + } else { // Pause. + memset(dest, 0, data_len); + } + dest += scaled_data_len; + dest_len -= scaled_data_len; + dest_written += scaled_data_len; + + data_offset_ += data_len; + + if (rate == 0.0f) + return 0; + + // Check to see if we're finished with the front buffer. + if (buffer->GetDataSize() - data_offset_ < 16) { + // Update the time. If this is the last buffer in the queue, we'll + // drop out of the loop before len == 0, so we need to always update + // the time here. + last_fill_buffer_time_ = buffer->GetTimestamp() + buffer->GetDuration(); + + // Dequeue the buffer. + queue_.pop_front(); + buffer->Release(); + ++buffers_released; + + // Reset our offset into the front buffer. + data_offset_ = 0; + } else { // If we're done with the read, compute the time. - if (len == 0) { - // Integer divide so multiply before divide to work properly. - int64 us_written = (buffer->GetDuration().InMicroseconds() * - data_offset_) / buffer->GetDataSize(); - last_fill_buffer_time_ = buffer->GetTimestamp() + - base::TimeDelta::FromMicroseconds(us_written); - } - - // Check to see if we're finished with the front buffer. - if (data_offset_ == buffer->GetDataSize()) { - // Update the time. If this is the last buffer in the queue, we'll - // drop out of the loop before len == 0, so we need to always update - // the time here. - last_fill_buffer_time_ = buffer->GetTimestamp() + buffer->GetDuration(); - - // Dequeue the buffer. - queue_.pop_front(); - buffer->Release(); - ++buffers_released; - - // Reset our offset into the front buffer. - data_offset_ = 0; - } + // Integer divide so multiply before divide to work properly. + int64 us_written = (buffer->GetDuration().InMicroseconds() * + data_offset_) / buffer->GetDataSize(); + last_fill_buffer_time_ = buffer->GetTimestamp() + + base::TimeDelta::FromMicroseconds(us_written); } } @@ -134,8 +151,7 @@ size_t AudioRendererBase::FillBuffer(uint8* dest, size_t len) { for (size_t i = 0; i < buffers_released; ++i) { ScheduleRead(); } - - return result; + return dest_written; } void AudioRendererBase::ScheduleRead() { diff --git a/media/filters/audio_renderer_base.h b/media/filters/audio_renderer_base.h index 6659fa1..5536a5d 100644 --- a/media/filters/audio_renderer_base.h +++ b/media/filters/audio_renderer_base.h @@ -66,7 +66,7 @@ class AudioRendererBase : public AudioRenderer { // of their buffer to playback silence. // // Safe to call on any thread. - size_t FillBuffer(uint8* dest, size_t len); + size_t FillBuffer(uint8* dest, size_t len, float rate); // Helper to parse a media format and return whether we were successful // retrieving all the information we care about. diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc index 55a1096..95e1401 100644 --- a/media/filters/audio_renderer_impl.cc +++ b/media/filters/audio_renderer_impl.cc @@ -9,10 +9,11 @@ namespace media { // We'll try to fill 4096 samples per buffer, which is roughly ~92ms of audio // data for a 44.1kHz audio source. -static const size_t kSamplesPerBuffer = 4096; +static const size_t kSamplesPerBuffer = 8*1024; AudioRendererImpl::AudioRendererImpl() : AudioRendererBase(kDefaultMaxQueueSize), + playback_rate_(0.0f), stream_(NULL) { } @@ -33,14 +34,15 @@ bool AudioRendererImpl::IsMediaFormatSupported( ParseMediaFormat(media_format, &channels, &sample_rate, &sample_bits); } -void AudioRendererImpl::SetPlaybackRate(float playback_rate) { +void AudioRendererImpl::SetPlaybackRate(float rate) { DCHECK(stream_); - // TODO(scherkus): handle playback rates not equal to 1.0. - if (playback_rate == 1.0f) { + + // TODO(fbarchard): limit rate to reasonable values + playback_rate_ = rate; + + static bool started = false; + if (rate > 0.0f && !started) stream_->Start(this); - } else { - NOTIMPLEMENTED(); - } } void AudioRendererImpl::SetVolume(float volume) { @@ -52,8 +54,10 @@ size_t AudioRendererImpl::OnMoreData(AudioOutputStream* stream, void* dest_void, // TODO(scherkus): handle end of stream. DCHECK(stream_ == stream); - // TODO(scherkus): maybe change OnMoreData to pass in char/uint8 or similar. - return FillBuffer(reinterpret_cast<uint8*>(dest_void), len); + // TODO(scherkus): Maybe change OnMoreData to pass in char/uint8 or similar. + // TODO(fbarchard): Waveout_output_win.h should handle zero length buffers + // without clicking. + return FillBuffer(static_cast<uint8*>(dest_void), len, playback_rate_); } void AudioRendererImpl::OnClose(AudioOutputStream* stream) { diff --git a/media/filters/audio_renderer_impl.h b/media/filters/audio_renderer_impl.h index b7e551b..e0804ce 100644 --- a/media/filters/audio_renderer_impl.h +++ b/media/filters/audio_renderer_impl.h @@ -53,6 +53,11 @@ class AudioRendererImpl : public AudioRendererBase, virtual void OnStop(); private: + // Playback rate + // 0.0f is paused, 0.5f is half speed, 1.0f is normal, 2.0f is double speed. + // Rate should normally be any value between 0.5 and 3.0. + float playback_rate_; + // Audio output stream device. AudioOutputStream* stream_; diff --git a/media/filters/null_audio_renderer.cc b/media/filters/null_audio_renderer.cc index 1d50e69..74604f8 100644 --- a/media/filters/null_audio_renderer.cc +++ b/media/filters/null_audio_renderer.cc @@ -51,7 +51,7 @@ void NullAudioRenderer::ThreadMain() { // Only consume buffers when actually playing. if (playback_rate_ > 0.0f) { - size_t bytes = FillBuffer(buffer_.get(), buffer_size_); + size_t bytes = FillBuffer(buffer_.get(), buffer_size_, playback_rate_); // Calculate our sleep duration, taking playback rate into consideration. sleep_in_milliseconds = |