summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/build/media.vcproj8
-rw-r--r--media/filters/null_audio_renderer.cc132
-rw-r--r--media/filters/null_audio_renderer.h85
-rw-r--r--media/media_lib.scons2
4 files changed, 227 insertions, 0 deletions
diff --git a/media/build/media.vcproj b/media/build/media.vcproj
index 8f9ce19..5b1dff7 100644
--- a/media/build/media.vcproj
+++ b/media/build/media.vcproj
@@ -204,6 +204,14 @@
RelativePath="..\filters\file_data_source.h"
>
</File>
+ <File
+ RelativePath="..\filters\null_audio_renderer.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\filters\null_audio_renderer.h"
+ >
+ </File>
</Filter>
<Filter
Name="audio"
diff --git a/media/filters/null_audio_renderer.cc b/media/filters/null_audio_renderer.cc
new file mode 100644
index 0000000..f136991
--- /dev/null
+++ b/media/filters/null_audio_renderer.cc
@@ -0,0 +1,132 @@
+// 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/base/filter_host.h"
+#include "media/filters/null_audio_renderer.h"
+
+namespace media {
+
+// The number of reads to perform during initialization for preroll purposes.
+static const size_t kInitialReads = 16;
+
+// The number of buffers we consume before sleeping. By doing so we can sleep
+// for longer, reducing CPU load and avoiding situations where audio samples
+// are so short that the OS sleeps our thread for too long.
+static const size_t kBuffersPerSleep = 4;
+
+NullAudioRenderer::NullAudioRenderer()
+ : decoder_(NULL),
+ playback_rate_(0.0f),
+ thread_(NULL),
+ initialized_(false),
+ shutdown_(false) {
+}
+
+NullAudioRenderer::~NullAudioRenderer() {
+ Stop();
+}
+
+// static
+bool NullAudioRenderer::IsMediaFormatSupported(
+ const MediaFormat* media_format) {
+ DCHECK(media_format);
+ std::string mime_type;
+ return media_format->GetAsString(MediaFormat::kMimeType, &mime_type) &&
+ mime_type.compare(mime_type::kUncompressedAudio) == 0;
+}
+
+void NullAudioRenderer::Stop() {
+ shutdown_ = true;
+ if (thread_)
+ PlatformThread::Join(thread_);
+}
+
+void NullAudioRenderer::SetPlaybackRate(float playback_rate) {
+ playback_rate_ = playback_rate;
+}
+
+bool NullAudioRenderer::Initialize(AudioDecoder* decoder) {
+ DCHECK(decoder);
+ decoder_ = decoder;
+
+ // It's safe to start the thread now because it simply sleeps when playback
+ // rate is 0.0f.
+ if (!PlatformThread::Create(0, this, &thread_))
+ return false;
+
+ // Schedule our initial reads.
+ for (size_t i = 0; i < kInitialReads; ++i) {
+ ScheduleRead();
+ }
+
+ // Defer initialization until all scheduled reads have completed.
+ return true;
+}
+
+void NullAudioRenderer::SetVolume(float volume) {
+ // Do nothing.
+}
+
+void NullAudioRenderer::OnAssignment(Buffer* buffer_in) {
+ bool initialized = false;
+ {
+ AutoLock auto_lock(input_lock_);
+ buffer_in->AddRef();
+ input_queue_.push_back(buffer_in);
+ DCHECK(input_queue_.size() <= kInitialReads);
+
+ // See if we're finally initialized.
+ // TODO(scherkus): handle end of stream.
+ initialized = !initialized_ && input_queue_.size() == kInitialReads;
+ }
+
+ if (initialized) {
+ initialized_ = true;
+ host_->InitializationComplete();
+ }
+}
+
+void NullAudioRenderer::ThreadMain() {
+ // Loop until we're signaled to stop.
+ while (!shutdown_) {
+ base::TimeDelta timestamp;
+ base::TimeDelta duration;
+ int sleep_ms = 0;
+ int released_buffers = 0;
+
+ // Only consume buffers when actually playing.
+ if (playback_rate_ > 0.0f) {
+ AutoLock auto_lock(input_lock_);
+ for (size_t i = 0; i < kBuffersPerSleep && !input_queue_.empty(); ++i) {
+ scoped_refptr<Buffer> buffer = input_queue_.front();
+ input_queue_.pop_front();
+ buffer->Release();
+ timestamp = buffer->GetTimestamp();
+ duration += buffer->GetDuration();
+ ++released_buffers;
+ }
+ // Apply the playback rate to our sleep duration.
+ sleep_ms =
+ static_cast<int>(floor(duration.InMillisecondsF() / playback_rate_));
+ }
+
+ // Schedule reads for every released buffer to maintain "playback".
+ for (int i = 0; i < released_buffers; ++i) {
+ ScheduleRead();
+ }
+
+ // Sleep and update the clock when we wake up.
+ PlatformThread::Sleep(sleep_ms);
+ if (timestamp.InMicroseconds() > 0) {
+ host_->SetTime(timestamp);
+ }
+ }
+}
+
+void NullAudioRenderer::ScheduleRead() {
+ host_->PostTask(NewRunnableMethod(decoder_, &AudioDecoder::Read,
+ new AssignableBuffer<NullAudioRenderer, Buffer>(this)));
+}
+
+} // namespace media
diff --git a/media/filters/null_audio_renderer.h b/media/filters/null_audio_renderer.h
new file mode 100644
index 0000000..821e059
--- /dev/null
+++ b/media/filters/null_audio_renderer.h
@@ -0,0 +1,85 @@
+// 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.
+
+#ifndef MEDIA_FILTERS_NULL_AUDIO_RENDERER_H_
+#define MEDIA_FILTERS_NULL_AUDIO_RENDERER_H_
+
+// NullAudioRenderer effectively uses an extra thread to "throw away" the
+// audio data at a rate resembling normal playback speed. It's just like
+// decoding to /dev/null!
+//
+// NullAudioRenderer can also be used in situations where the client has no
+// audio device or we haven't written an audio implementation for a particular
+// platform yet.
+//
+// It supports any type of MediaFormat as long as the mime type has been set to
+// audio/x-uncompressed. Playback rate is also supported and NullAudioRenderer
+// will slow down and speed up accordingly.
+
+#include <deque>
+
+#include "base/lock.h"
+#include "base/platform_thread.h"
+#include "media/base/buffers.h"
+#include "media/base/factory.h"
+#include "media/base/filters.h"
+
+namespace media {
+
+class NullAudioRenderer : public AudioRenderer, PlatformThread::Delegate {
+ public:
+ static FilterFactory* CreateFilterFactory() {
+ return new FilterFactoryImpl0<NullAudioRenderer>();
+ }
+
+ // Compatible with any audio/x-uncompressed MediaFormat.
+ static bool IsMediaFormatSupported(const MediaFormat* media_format);
+
+ // MediaFilter implementation.
+ virtual void Stop();
+ virtual void SetPlaybackRate(float playback_rate);
+
+ // AudioRenderer implementation.
+ virtual bool Initialize(AudioDecoder* decoder);
+ virtual void SetVolume(float volume);
+
+ // AssignableBuffer<NullAudioRenderer, BufferInterface> implementation.
+ void OnAssignment(Buffer* buffer_in);
+
+ // PlatformThread::Delegate implementation.
+ virtual void ThreadMain();
+
+ private:
+ friend class FilterFactoryImpl0<NullAudioRenderer>;
+ NullAudioRenderer();
+ virtual ~NullAudioRenderer();
+
+ // Posts a task on the pipeline thread to read a sample from the decoder.
+ // Safe to call on any thread.
+ void ScheduleRead();
+
+ // Audio decoder.
+ AudioDecoder* decoder_;
+
+ // Current playback rate.
+ float playback_rate_;
+
+ // Queued audio data.
+ typedef std::deque<Buffer*> BufferQueue;
+ BufferQueue input_queue_;
+ Lock input_lock_;
+
+ // Seperate thread used to throw away data.
+ PlatformThreadHandle thread_;
+
+ // Various state flags.
+ bool initialized_;
+ bool shutdown_;
+
+ DISALLOW_COPY_AND_ASSIGN(NullAudioRenderer);
+};
+
+} // namespace media
+
+#endif // MEDIA_FILTERS_NULL_AUDIO_RENDERER_H_
diff --git a/media/media_lib.scons b/media/media_lib.scons
index 73badec..1f88e35 100644
--- a/media/media_lib.scons
+++ b/media/media_lib.scons
@@ -46,6 +46,8 @@ input_files = ChromeFileList([
'filters/audio_renderer_impl.h',
'filters/file_data_source.cc',
'filters/file_data_source.h',
+ 'filters/null_audio_renderer.cc',
+ 'filters/null_audio_renderer.h',
]),
MSVSFilter('audio', [
'audio/win/audio_manager_win.h',