summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/base/mock_filter_host.h103
-rw-r--r--media/base/mock_pipeline.h173
-rw-r--r--media/build/media.vcproj8
-rw-r--r--media/build/media_unittests.vcproj16
-rw-r--r--media/filters/file_data_source.cc114
-rw-r--r--media/filters/file_data_source.h64
-rw-r--r--media/filters/file_data_source_unittest.cc95
-rw-r--r--media/media_lib.scons2
-rw-r--r--media/media_unittests.scons10
-rw-r--r--media/test/data/ten_byte_file1
10 files changed, 579 insertions, 7 deletions
diff --git a/media/base/mock_filter_host.h b/media/base/mock_filter_host.h
new file mode 100644
index 0000000..490587f
--- /dev/null
+++ b/media/base/mock_filter_host.h
@@ -0,0 +1,103 @@
+// 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_BASE_MOCK_FILTER_HOST_H_
+#define MEDIA_BASE_MOCK_FILTER_HOST_H_
+
+#include <string>
+
+#include "media/base/factory.h"
+#include "media/base/filter_host.h"
+#include "media/base/filters.h"
+#include "media/base/media_format.h"
+#include "media/base/mock_pipeline.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+template <class Filter, class Source>
+class MockFilterHost : public FilterHost {
+ public:
+ MockFilterHost(const MediaFormat* media_format, Source source) {
+ scoped_refptr<FilterFactory> factory = Filter::CreateFactory();
+ filter_ = factory->Create<Filter>(media_format);
+ EXPECT_TRUE(filter_.get());
+ if (filter_.get()) {
+ filter_->SetFilterHost(this);
+ filter_->Initialize(source);
+ }
+ }
+
+ virtual ~MockFilterHost() {
+ filter_->Stop();
+ }
+
+ virtual const PipelineStatus* GetPipelineStatus() const {
+ return &mock_pipeline_;
+ }
+
+ virtual void SetTimeUpdateCallback(Callback1<base::TimeDelta>::Type* cb) {
+ time_update_callback_.reset(cb);
+ }
+
+ virtual void ScheduleTimeUpdateCallback(base::TimeDelta time) {
+ // TODO(ralphl): Implement MockFilte::ScheduleTimeUpdateCallback.
+ NOTIMPLEMENTED();
+ }
+
+ virtual void InitializationComplete() {
+ EXPECT_FALSE(mock_pipeline_.IsInitialized());
+ mock_pipeline_.SetInitialized(true);
+ }
+
+ virtual void PostTask(Task* task) {
+ // TODO(ralphl): Implement MockPipeline::PostTask.
+ NOTIMPLEMENTED();
+ }
+
+ virtual void Error(PipelineError error) {
+ mock_pipeline_.Error(error);
+ }
+
+ virtual void SetTime(base::TimeDelta time) {
+ mock_pipeline_.SetTime(time);
+ }
+
+ virtual void SetDuration(base::TimeDelta duration) {
+ mock_pipeline_.SetDuration(duration);
+ }
+
+ virtual void SetBufferedTime(base::TimeDelta buffered_time) {
+ mock_pipeline_.SetBufferedTime(buffered_time);
+ }
+
+ virtual void SetTotalBytes(int64 total_bytes) {
+ mock_pipeline_.SetTotalBytes(total_bytes);
+ }
+
+ virtual void SetBufferedBytes(int64 buffered_bytes) {
+ mock_pipeline_.SetBufferedBytes(buffered_bytes);
+ }
+
+ // Sets the size of the video output in pixel units.
+ virtual void SetVideoSize(size_t width, size_t height) {
+ mock_pipeline_.SetVideoSize(width, height);
+ }
+
+ // Used by unit tests to manipulate the filter.
+ Filter* filter() const { return filter_; }
+
+ MockPipeline* mock_pipeline() const { return &mock_pipeline_; }
+
+ private:
+ MockPipeline mock_pipeline_;
+ scoped_refptr<Filter> filter_;
+ scoped_ptr<Callback1<base::TimeDelta>::Type> time_update_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockFilterHost);
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_MOCK_FILTER_HOST_H_
diff --git a/media/base/mock_pipeline.h b/media/base/mock_pipeline.h
new file mode 100644
index 0000000..d353c41
--- /dev/null
+++ b/media/base/mock_pipeline.h
@@ -0,0 +1,173 @@
+// 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_BASE_MOCK_PIPELINE_H_
+#define MEDIA_BASE_MOCK_PIPELINE_H_
+
+#include <string>
+
+#include "media/base/media_format.h"
+#include "media/base/pipeline.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+class MockPipeline : public media::Pipeline {
+ public:
+ MockPipeline() {
+ Reset(false);
+ }
+
+ virtual ~MockPipeline() {}
+
+ // Implementation of PipelineStatus interface.
+ virtual bool IsInitialized() const {
+ return initialized_;
+ }
+
+ virtual base::TimeDelta GetDuration() const {
+ return duration_;
+ }
+
+ virtual base::TimeDelta GetBufferedTime() const {
+ return buffered_time_;
+ }
+
+ virtual int64 GetTotalBytes() const {
+ return total_bytes_;
+ }
+
+ virtual int64 GetBufferedBytes() const {
+ return buffered_bytes_;
+ }
+
+ virtual void GetVideoSize(size_t* width_out, size_t* height_out) const {
+ *width_out = width_;
+ *height_out = height_;
+ }
+
+ virtual float GetVolume() const {
+ return volume_;
+ }
+
+ virtual float GetPlaybackRate() const {
+ return playback_rate_;
+ }
+
+ virtual base::TimeDelta GetTime() const {
+ return time_;
+ }
+
+ virtual base::TimeDelta GetInterpolatedTime() const {
+ return time_;
+ }
+
+ virtual PipelineError GetError() const {
+ return error_;
+ }
+
+ // Implementation of Pipeline interface.
+ virtual bool Start(FilterFactory* filter_factory,
+ const std::string& url,
+ Callback1<bool>::Type* init_complete_callback) {
+ EXPECT_FALSE(initialized_);
+ initialized_ = true;
+ if (init_complete_callback) {
+ init_complete_callback->Run(true);
+ delete init_complete_callback;
+ }
+ return true;
+ }
+
+ virtual void Stop() {
+ EXPECT_TRUE(initialized_ || error_ != media::PIPELINE_OK);
+ Reset(false);
+ }
+
+ virtual void SetPlaybackRate(float playback_rate) {
+ playback_rate_ = playback_rate;
+ }
+
+ virtual void Seek(base::TimeDelta time) {
+ time_ = time;
+ }
+
+ virtual void SetVolume(float volume) {
+ volume_ = volume;
+ }
+
+ // Public methods used by tests and by MockFilterHost to manipulate the
+ // state of the mock pipeline.
+
+ // Set the state to the same as a newly created MockPipeline. If
+ // |reset_to_initialized| is true then the pipeline's |initialized_| state
+ // will be true when this method returns.
+ void Reset(bool reset_to_initialized) {
+ error_ = media::PIPELINE_OK;
+ volume_ = 1.0f;
+ playback_rate_ = 0.0f;
+ initialized_ = reset_to_initialized;
+ time_ = base::TimeDelta();
+ duration_ = base::TimeDelta();
+ buffered_time_ = base::TimeDelta();
+ width_ = 0;
+ height_ = 0;
+ buffered_bytes_ = 0;
+ total_bytes_ = 0;
+ }
+
+ void SetInitialized(bool init_value) {
+ initialized_ = init_value;
+ }
+
+ void Error(media::PipelineError error) {
+ initialized_ = false;
+ error_ = error;
+ }
+
+ void SetTime(base::TimeDelta time) {
+ time_ = time;
+ }
+
+ virtual void SetDuration(base::TimeDelta duration) {
+ duration_ = duration;
+ }
+
+ virtual void SetBufferedTime(base::TimeDelta buffered_time) {
+ buffered_time = buffered_time;
+ }
+
+ virtual void SetTotalBytes(int64 total_bytes) {
+ total_bytes_ = total_bytes;
+ }
+
+ virtual void SetBufferedBytes(int64 buffered_bytes) {
+ buffered_bytes_ = buffered_bytes;
+ }
+
+ // Sets the size of the video output in pixel units.
+ virtual void SetVideoSize(size_t width, size_t height) {
+ width_ = width;
+ height_ = height;
+ }
+
+ private:
+ PipelineError error_;
+ float volume_;
+ float playback_rate_;
+ bool initialized_;
+ base::TimeDelta time_;
+ base::TimeDelta duration_;
+ base::TimeDelta buffered_time_;
+ size_t width_;
+ size_t height_;
+ int64 buffered_bytes_;
+ int64 total_bytes_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockPipeline);
+};
+
+} // namespace media
+
+#endif // MEDIA_BASE_MOCK_PIPELINE_H_
diff --git a/media/build/media.vcproj b/media/build/media.vcproj
index c15fc81..8f9ce19 100644
--- a/media/build/media.vcproj
+++ b/media/build/media.vcproj
@@ -196,6 +196,14 @@
RelativePath="..\filters\audio_renderer_impl.h"
>
</File>
+ <File
+ RelativePath="..\filters\file_data_source.cc"
+ >
+ </File>
+ <File
+ RelativePath="..\filters\file_data_source.h"
+ >
+ </File>
</Filter>
<Filter
Name="audio"
diff --git a/media/build/media_unittests.vcproj b/media/build/media_unittests.vcproj
index a565c33..90c9cd9 100644
--- a/media/build/media_unittests.vcproj
+++ b/media/build/media_unittests.vcproj
@@ -160,10 +160,18 @@
>
</File>
<File
+ RelativePath="..\base\mock_filter_host.h"
+ >
+ </File>
+ <File
RelativePath="..\base\mock_media_filters.h"
>
</File>
<File
+ RelativePath="..\base\mock_pipeline.h"
+ >
+ </File>
+ <File
RelativePath="..\base\pipeline_impl_unittest.cc"
>
</File>
@@ -176,6 +184,14 @@
>
</File>
</Filter>
+ <Filter
+ Name="filters"
+ >
+ <File
+ RelativePath="..\filters\file_data_source_unittest.cc"
+ >
+ </File>
+ </Filter>
</Filter>
</Files>
<Globals>
diff --git a/media/filters/file_data_source.cc b/media/filters/file_data_source.cc
new file mode 100644
index 0000000..95b0ec0
--- /dev/null
+++ b/media/filters/file_data_source.cc
@@ -0,0 +1,114 @@
+// 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 "base/file_util.h"
+#include "base/string_util.h"
+#include "media/base/filter_host.h"
+#include "media/base/filters.h"
+#include "media/base/pipeline.h"
+#include "media/filters/file_data_source.h"
+
+namespace media {
+
+FileDataSource::FileDataSource()
+ : file_(NULL),
+ file_size_(0) {
+}
+
+FileDataSource::~FileDataSource() {
+ Stop();
+}
+
+bool FileDataSource::Initialize(const std::string& url) {
+ DCHECK(!file_);
+#if defined(OS_WIN)
+ FilePath file_path(UTF8ToWide(url));
+#else
+ FilePath file_path(url);
+#endif
+ if (file_util::GetFileSize(file_path, &file_size_)) {
+ file_ = file_util::OpenFile(file_path, "rb");
+ }
+ if (!file_) {
+ file_size_ = 0;
+ host_->Error(PIPELINE_ERROR_NETWORK);
+ return false;
+ }
+ media_format_.SetAsString(MediaFormat::kMimeType,
+ mime_type::kApplicationOctetStream);
+ media_format_.SetAsString(MediaFormat::kURL, url);
+ host_->SetTotalBytes(file_size_);
+ host_->SetBufferedBytes(file_size_);
+ host_->InitializationComplete();
+ return true;
+}
+
+void FileDataSource::Stop() {
+ AutoLock l(lock_);
+ if (file_) {
+ file_util::CloseFile(file_);
+ file_ = NULL;
+ file_size_ = 0;
+ }
+}
+
+const MediaFormat* FileDataSource::GetMediaFormat() {
+ return &media_format_;
+}
+
+size_t FileDataSource::Read(char* data, size_t size) {
+ DCHECK(file_);
+ AutoLock l(lock_);
+ if (file_) {
+ size_t size_read = fread(data, 1, size, file_);
+ if (size_read == size || !ferror(file_)) {
+ return size_read;
+ }
+ }
+ return kReadError;
+}
+
+bool FileDataSource::GetPosition(int64* position_out) {
+ DCHECK(position_out);
+ DCHECK(file_);
+ AutoLock l(lock_);
+ if (!file_) {
+ *position_out = 0;
+ return false;
+ }
+// Linux and mac libraries don't seem to support 64 versions of seek and
+// ftell. TODO(ralph): Try to figure out how to enable int64 versions on
+// these platforms.
+#if defined(OS_WIN)
+ *position_out = _ftelli64(file_);
+#else
+ *position_out = ftell(file_);
+#endif
+ return true;
+}
+
+bool FileDataSource::SetPosition(int64 position) {
+ DCHECK(file_);
+ AutoLock l(lock_);
+#if defined(OS_WIN)
+ if (file_ && 0 == _fseeki64(file_, position, SEEK_SET)) {
+ return true;
+ }
+#else
+ if (file_ && 0 == fseek(file_, static_cast<int32>(position), SEEK_SET)) {
+ return true;
+ }
+#endif
+ return false;
+}
+
+bool FileDataSource::GetSize(int64* size_out) {
+ DCHECK(size_out);
+ DCHECK(file_);
+ AutoLock l(lock_);
+ *size_out = file_size_;
+ return (NULL != file_);
+}
+
+} // namespace media
diff --git a/media/filters/file_data_source.h b/media/filters/file_data_source.h
new file mode 100644
index 0000000..9caa435
--- /dev/null
+++ b/media/filters/file_data_source.h
@@ -0,0 +1,64 @@
+// 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_FILE_DATA_SOURCE_H_
+#define MEDIA_FILTERS_FILE_DATA_SOURCE_H_
+
+#include <string>
+
+#include "base/lock.h"
+#include "media/base/filters.h"
+
+namespace media {
+
+// Basic data source that treats the URL as a file path, and uses the file
+// system to read data for a media pipeline.
+// TODO(ralph): We will add a pure virtual interface so that the chrome
+// media player delegate can give us the file handle, bytes downloaded so far,
+// and file size.
+class FileDataSource : public DataSource {
+ public:
+ // Public method to get a filter factory for the FileDataSource.
+ static FilterFactory* CreateFactory() {
+ return new FilterFactoryImpl0<FileDataSource>();
+ }
+
+ // Implementation of MediaFilter.
+ virtual void Stop();
+
+ // Implementation of DataSource.
+ virtual bool Initialize(const std::string& url);
+ virtual const MediaFormat* GetMediaFormat();
+ virtual size_t Read(char* data, size_t size);
+ virtual bool GetPosition(int64* position_out);
+ virtual bool SetPosition(int64 position);
+ virtual bool GetSize(int64* size_out);
+
+ private:
+ friend class FilterFactoryImpl0<FileDataSource>;
+ FileDataSource();
+ virtual ~FileDataSource();
+
+ // File handle. Null if not initialized or an error occurs.
+ FILE* file_;
+
+ // Size of the file in bytes.
+ int64 file_size_;
+
+ // Media format handed out by the DataSource::GetMediaFormat method.
+ MediaFormat media_format_;
+
+ // Critical section that protects all of the DataSource methods to prevent
+ // a Stop from happening while in the middle of a file I/O operation.
+ // TODO(ralphl): Ideally this would use asynchronous I/O or we will know
+ // that we will block for a short period of time in reads. Othewise, we can
+ // hang the pipeline Stop.
+ Lock lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileDataSource);
+};
+
+} // namespace media
+
+#endif // MEDIA_FILTERS_FILE_DATA_SOURCE_H_
diff --git a/media/filters/file_data_source_unittest.cc b/media/filters/file_data_source_unittest.cc
new file mode 100644
index 0000000..3006454
--- /dev/null
+++ b/media/filters/file_data_source_unittest.cc
@@ -0,0 +1,95 @@
+// 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 <string>
+
+#include "base/base_paths.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/string_util.h"
+#include "base/task.h"
+#include "base/waitable_event.h"
+#include "media/base/buffers.h"
+#include "media/base/pipeline_impl.h"
+#include "media/base/media_format.h"
+#include "media/base/filters.h"
+#include "media/base/factory.h"
+#include "media/base/filter_host.h"
+#include "media/base/mock_filter_host.h"
+#include "media/filters/file_data_source.h"
+#include "media/base/mock_media_filters.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using media::FileDataSource;
+using media::FilterFactoryCollection;
+using media::InitializationHelper;
+using media::MediaFormat;
+using media::MockDemuxer;
+using media::MockAudioDecoder;
+using media::MockAudioRenderer;
+using media::MockFilterHost;
+using media::PipelineImpl;
+
+std::string TestFileURL() {
+ FilePath data_dir;
+ EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &data_dir));
+ data_dir = data_dir.Append(FILE_PATH_LITERAL("media"))
+ .Append(FILE_PATH_LITERAL("test"))
+ .Append(FILE_PATH_LITERAL("data"))
+ .Append(FILE_PATH_LITERAL("ten_byte_file"));
+#if defined (OS_WIN)
+ return WideToUTF8(data_dir.value());
+#else
+ return data_dir.value();
+#endif
+}
+
+// Use the "real" pipeline to open the file.
+TEST(FileDataSourceTest, OpenFile) {
+ PipelineImpl pipeline;
+ scoped_refptr<FilterFactoryCollection> c = new FilterFactoryCollection();
+ c->AddFactory(FileDataSource::CreateFactory());
+ c->AddFactory(MockDemuxer::CreateFactory());
+ c->AddFactory(MockAudioDecoder::CreateFactory());
+ c->AddFactory(MockAudioRenderer::CreateFactory());
+ InitializationHelper h;
+ h.Start(&pipeline, c, TestFileURL());
+ h.Wait();
+ EXPECT_EQ(pipeline.GetError(), media::PIPELINE_OK);
+ EXPECT_EQ(pipeline.GetTotalBytes(), 10);
+ EXPECT_EQ(pipeline.GetBufferedBytes(), 10);
+ pipeline.Stop();
+}
+
+// Use the mock filter host to directly call the Read and GetPosition methods.
+TEST(FileDataSourceTest, ReadData) {
+ MediaFormat url_format;
+ int64 position;
+ int64 size;
+ char ten_bytes[10];
+ std::string url = TestFileURL();
+ url_format.SetAsString(MediaFormat::kMimeType, media::mime_type::kURL);
+ url_format.SetAsString(MediaFormat::kURL, url);
+ MockFilterHost<FileDataSource, std::string> mock_host(&url_format, url);
+
+ EXPECT_TRUE(mock_host.filter()->GetSize(&size));
+ EXPECT_EQ(10, size);
+
+ EXPECT_TRUE(mock_host.filter()->GetPosition(&position));
+ EXPECT_EQ(0, position);
+
+ EXPECT_EQ(10u, mock_host.filter()->Read(ten_bytes, sizeof(ten_bytes)));
+ EXPECT_EQ('0', ten_bytes[0]);
+ EXPECT_EQ('5', ten_bytes[5]);
+ EXPECT_EQ('9', ten_bytes[9]);
+ EXPECT_TRUE(mock_host.filter()->GetPosition(&position));
+ EXPECT_EQ(10, position);
+ EXPECT_EQ(0u, mock_host.filter()->Read(ten_bytes, sizeof(ten_bytes)));
+
+ EXPECT_TRUE(mock_host.filter()->SetPosition(5));
+ EXPECT_EQ(5u, mock_host.filter()->Read(ten_bytes, sizeof(ten_bytes)));
+ EXPECT_EQ('5', ten_bytes[0]);
+ EXPECT_TRUE(mock_host.filter()->GetPosition(&position));
+ EXPECT_EQ(10, position);
+}
diff --git a/media/media_lib.scons b/media/media_lib.scons
index 51676b1..73badec 100644
--- a/media/media_lib.scons
+++ b/media/media_lib.scons
@@ -44,6 +44,8 @@ input_files = ChromeFileList([
MSVSFilter('filters', [
'filters/audio_renderer_impl.cc',
'filters/audio_renderer_impl.h',
+ 'filters/file_data_source.cc',
+ 'filters/file_data_source.h',
]),
MSVSFilter('audio', [
'audio/win/audio_manager_win.h',
diff --git a/media/media_unittests.scons b/media/media_unittests.scons
index 3ce9f68..7ae0b95 100644
--- a/media/media_unittests.scons
+++ b/media/media_unittests.scons
@@ -46,13 +46,6 @@ if env.Bit('windows'):
],
)
-input_files = [
- 'base/data_buffer_unittest.cc',
- 'base/mock_media_filters.h',
- 'base/pipeline_impl_unittest.cc',
- 'base/run_all_unittests.cc',
-]
-
input_files = ChromeFileList([
# TODO(sgk): violate standard indentation so we don't have to
# reindent too much when we remove the explicit MSVSFilter() calls
@@ -65,6 +58,9 @@ input_files = ChromeFileList([
'base/data_buffer_unittest.cc',
'base/pipeline_impl_unittest.cc',
]),
+ MSVSFilter('filters', [
+ 'filters/file_data_source_unittest.cc',
+ ]),
MSVSFilter('audio', [
'audio/win/audio_output_win_unittest.cc',
]),
diff --git a/media/test/data/ten_byte_file b/media/test/data/ten_byte_file
new file mode 100644
index 0000000..ad47100
--- /dev/null
+++ b/media/test/data/ten_byte_file
@@ -0,0 +1 @@
+0123456789 \ No newline at end of file