diff options
author | ralphl@chromium.org <ralphl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-12 03:49:11 +0000 |
---|---|---|
committer | ralphl@chromium.org <ralphl@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-12 03:49:11 +0000 |
commit | 84dd17ec3f2b4ccd2bec330596bb1aa912ae78d7 (patch) | |
tree | bad98923f3e52e2e7f5f6e07e94dd557cb672715 /media/filters | |
parent | a90bb01b260de37d4390af4721960e63095b991c (diff) | |
download | chromium_src-84dd17ec3f2b4ccd2bec330596bb1aa912ae78d7.zip chromium_src-84dd17ec3f2b4ccd2bec330596bb1aa912ae78d7.tar.gz chromium_src-84dd17ec3f2b4ccd2bec330596bb1aa912ae78d7.tar.bz2 |
A very basic implementation of a data source, which opens a file. Implementation of the DataSource media filter interface.
Review URL: http://codereview.chromium.org/21111
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9642 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/filters')
-rw-r--r-- | media/filters/file_data_source.cc | 114 | ||||
-rw-r--r-- | media/filters/file_data_source.h | 64 | ||||
-rw-r--r-- | media/filters/file_data_source_unittest.cc | 95 |
3 files changed, 273 insertions, 0 deletions
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); +} |