diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-23 00:23:05 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-23 00:23:05 +0000 |
commit | 0436b9a8aad21c877890185050433bca2401b379 (patch) | |
tree | 849b8a80cbbae70b82f1d3b446aed74a35b4f9c3 /webkit | |
parent | 21449b3dc0ac325ab90bc1418bab8a7dda947f3e (diff) | |
download | chromium_src-0436b9a8aad21c877890185050433bca2401b379.zip chromium_src-0436b9a8aad21c877890185050433bca2401b379.tar.gz chromium_src-0436b9a8aad21c877890185050433bca2401b379.tar.bz2 |
Allow <video> to read from a data URI. Data URI is now handled
by SimpleDataSource. Selection of data source is done by the
existing factory method by calling to IsMediaFormatSupported.
And each data source would determine if they support the
mentioned scheme.
BUG=24357
TEST=open a video with data:/ scheme.
Review URL: http://codereview.chromium.org/284007
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29848 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/glue/media/buffered_data_source.cc | 26 | ||||
-rw-r--r-- | webkit/glue/media/buffered_data_source.h | 4 | ||||
-rw-r--r-- | webkit/glue/media/simple_data_source.cc | 72 | ||||
-rw-r--r-- | webkit/glue/media/simple_data_source.h | 7 | ||||
-rw-r--r-- | webkit/glue/media/simple_data_source_unittest.cc | 84 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell.cc | 5 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_webview_delegate.cc | 13 |
7 files changed, 145 insertions, 66 deletions
diff --git a/webkit/glue/media/buffered_data_source.cc b/webkit/glue/media/buffered_data_source.cc index 34924c9..48df614 100644 --- a/webkit/glue/media/buffered_data_source.cc +++ b/webkit/glue/media/buffered_data_source.cc @@ -9,6 +9,7 @@ #include "base/string_util.h" #include "chrome/common/extensions/url_pattern.h" #include "media/base/filter_host.h" +#include "media/base/media_format.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" #include "net/http/http_response_headers.h" @@ -19,6 +20,7 @@ namespace { const char kHttpScheme[] = "http"; const char kHttpsScheme[] = "https"; +const char kDataScheme[] = "data"; const int64 kPositionNotSpecified = -1; const int kHttpOK = 200; const int kHttpPartialContent = 206; @@ -42,14 +44,12 @@ const int kForwardWaitThreshold = 2 * kMegabyte; // Defines how long we should wait for more data before we declare a connection // timeout and start a new request. -// TODO(hclam): Use this value when retry is implemented. // TODO(hclam): Set it to 5s, calibrate this value later. const int kTimeoutMilliseconds = 5000; // Defines how many times we should try to read from a buffered resource loader // before we declare a read error. After each failure of read from a buffered // resource loader, a new one is created to be read. -// TODO(hclam): Use this value when retry is implemented. const int kReadTrials = 3; // BufferedDataSource has an intermediate buffer, this value governs the initial @@ -62,6 +62,10 @@ bool IsHttpProtocol(const GURL& url) { return url.SchemeIs(kHttpScheme) || url.SchemeIs(kHttpsScheme); } +bool IsDataProtocol(const GURL& url) { + return url.SchemeIs(kDataScheme); +} + } // namespace namespace webkit_glue { @@ -493,6 +497,24 @@ void BufferedResourceLoader::NotifyNetworkEvent() { } ///////////////////////////////////////////////////////////////////////////// +// BufferedDataSource, static methods +bool BufferedDataSource::IsMediaFormatSupported( + const media::MediaFormat& media_format) { + std::string mime_type; + std::string url; + if (media_format.GetAsString(media::MediaFormat::kMimeType, &mime_type) && + media_format.GetAsString(media::MediaFormat::kURL, &url)) { + GURL gurl(url); + + // This data source doesn't support data:// protocol, so reject it + // explicitly. + if (IsProtocolSupportedForMedia(gurl) && !IsDataProtocol(gurl)) + return true; + } + return false; +} + +///////////////////////////////////////////////////////////////////////////// // BufferedDataSource, protected BufferedDataSource::BufferedDataSource( MessageLoop* render_loop, diff --git a/webkit/glue/media/buffered_data_source.h b/webkit/glue/media/buffered_data_source.h index dbbb54c..59c511b 100644 --- a/webkit/glue/media/buffered_data_source.h +++ b/webkit/glue/media/buffered_data_source.h @@ -216,6 +216,10 @@ class BufferedDataSource : public media::DataSource { message_loop, bridge_factory); } + // media::FilterFactoryImpl2 implementation. + static bool IsMediaFormatSupported( + const media::MediaFormat& media_format); + // media::MediaFilter implementation. virtual void Initialize(const std::string& url, media::FilterCallback* callback); diff --git a/webkit/glue/media/simple_data_source.cc b/webkit/glue/media/simple_data_source.cc index b2b9f32..ab6cfea 100644 --- a/webkit/glue/media/simple_data_source.cc +++ b/webkit/glue/media/simple_data_source.cc @@ -6,29 +6,41 @@ #include "base/process_util.h" #include "media/base/filter_host.h" #include "net/base/load_flags.h" +#include "net/base/data_url.h" #include "net/http/http_response_headers.h" #include "net/url_request/url_request_status.h" #include "webkit/glue/media/simple_data_source.h" #include "webkit/glue/resource_loader_bridge.h" +#include "webkit/glue/webkit_glue.h" namespace { const char kHttpScheme[] = "http"; const char kHttpsScheme[] = "https"; -const char kFtpScheme[] = "ftp"; +const char kDataScheme[] = "data"; // A helper method that accepts only HTTP, HTTPS and FILE protocol. -bool IsSchemeSupported(const GURL& url) { - return url.SchemeIs(kHttpScheme) || - url.SchemeIs(kHttpsScheme) || - url.SchemeIs(kFtpScheme) || - url.SchemeIsFile(); +bool IsDataProtocol(const GURL& url) { + return url.SchemeIs(kDataScheme); } } // namespace namespace webkit_glue { +bool SimpleDataSource::IsMediaFormatSupported( + const media::MediaFormat& media_format) { + std::string mime_type; + std::string url; + if (media_format.GetAsString(media::MediaFormat::kMimeType, &mime_type) && + media_format.GetAsString(media::MediaFormat::kURL, &url)) { + GURL gurl(url); + if (IsProtocolSupportedForMedia(gurl)) + return true; + } + return false; +} + SimpleDataSource::SimpleDataSource( MessageLoop* render_loop, webkit_glue::MediaResourceLoaderBridgeFactory* bridge_factory) @@ -63,15 +75,13 @@ void SimpleDataSource::Initialize(const std::string& url, // Validate the URL. SetURL(GURL(url)); - if (!url_.is_valid() || !IsSchemeSupported(url_)) { + if (!url_.is_valid() || !IsProtocolSupportedForMedia(url_)) { host()->SetError(media::PIPELINE_ERROR_NETWORK); initialize_callback_->Run(); initialize_callback_.reset(); return; } - host()->SetLoaded(url_.SchemeIsFile()); - // Post a task to the render thread to start loading the resource. render_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &SimpleDataSource::StartTask)); @@ -148,16 +158,7 @@ void SimpleDataSource::OnCompletedRequest(const URLRequestStatus& status, size_ = data_.length(); } - // We're initialized! - if (status.is_success()) { - state_ = INITIALIZED; - host()->SetTotalBytes(size_); - host()->SetBufferedBytes(size_); - } else { - host()->SetError(media::PIPELINE_ERROR_NETWORK); - } - initialize_callback_->Run(); - initialize_callback_.reset(); + DoneInitialization_Locked(status.is_success()); } std::string SimpleDataSource::GetURLForDebugging() { @@ -182,10 +183,20 @@ void SimpleDataSource::StartTask() { DCHECK_EQ(state_, INITIALIZING); - // Create our bridge and start loading the resource. - bridge_.reset(bridge_factory_->CreateBridge( - url_, net::LOAD_BYPASS_CACHE, -1, -1)); - bridge_->Start(this); + if (IsDataProtocol(url_)) { + // If this using data protocol, we just need to decode it. + std::string mime_type, charset; + bool success = net::DataURL::Parse(url_, &mime_type, &charset, &data_); + + // Don't care about the mime-type just proceed if decoding was successful. + size_ = data_.length(); + DoneInitialization_Locked(success); + } else { + // Create our bridge and start loading the resource. + bridge_.reset(bridge_factory_->CreateBridge( + url_, net::LOAD_BYPASS_CACHE, -1, -1)); + bridge_->Start(this); + } } void SimpleDataSource::CancelTask() { @@ -199,4 +210,19 @@ void SimpleDataSource::CancelTask() { } } +void SimpleDataSource::DoneInitialization_Locked(bool success) { + lock_.AssertAcquired(); + if (success) { + state_ = INITIALIZED; + host()->SetTotalBytes(size_); + host()->SetBufferedBytes(size_); + // If scheme is file or data, say we are loaded. + host()->SetLoaded(url_.SchemeIsFile() || IsDataProtocol(url_)); + } else { + host()->SetError(media::PIPELINE_ERROR_NETWORK); + } + initialize_callback_->Run(); + initialize_callback_.reset(); +} + } // namespace webkit_glue diff --git a/webkit/glue/media/simple_data_source.h b/webkit/glue/media/simple_data_source.h index e458c57..faf889d 100644 --- a/webkit/glue/media/simple_data_source.h +++ b/webkit/glue/media/simple_data_source.h @@ -34,6 +34,10 @@ class SimpleDataSource : public media::DataSource, bridge_factory); } + // media::FilterFactoryImpl2 implementation. + static bool IsMediaFormatSupported( + const media::MediaFormat& media_format); + // MediaFilter implementation. virtual void Stop(); @@ -79,6 +83,9 @@ class SimpleDataSource : public media::DataSource, // Cancels and deletes the resource loading on the render thread. void CancelTask(); + // Perform initialization completion tasks under a lock. + void DoneInitialization_Locked(bool success); + // Primarily used for asserting the bridge is loading on the render thread. MessageLoop* render_loop_; diff --git a/webkit/glue/media/simple_data_source_unittest.cc b/webkit/glue/media/simple_data_source_unittest.cc index eb5cd78..30e1403 100644 --- a/webkit/glue/media/simple_data_source_unittest.cc +++ b/webkit/glue/media/simple_data_source_unittest.cc @@ -13,6 +13,7 @@ using ::testing::_; using ::testing::DoAll; using ::testing::InSequence; using ::testing::Invoke; +using ::testing::NiceMock; using ::testing::NotNull; using ::testing::Return; using ::testing::SetArgumentPointee; @@ -23,9 +24,11 @@ namespace { const int kDataSize = 1024; const char kHttpUrl[] = "http://test"; -const char kFtpUrl[] = "ftp://test"; const char kHttpsUrl[] = "https://test"; const char kFileUrl[] = "file://test"; +const char kDataUrl[] = + "data:text/plain;base64,YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoK"; +const char kDataUrlDecoded[] = "abcdefghijklmnopqrstuvwxyz"; const char kInvalidUrl[] = "whatever://test"; } // namespace @@ -36,8 +39,8 @@ class SimpleDataSourceTest : public testing::Test { public: SimpleDataSourceTest() { bridge_factory_.reset( - new StrictMock<MockMediaResourceLoaderBridgeFactory>()); - bridge_.reset(new StrictMock<MockResourceLoaderBridge>()); + new NiceMock<MockMediaResourceLoaderBridgeFactory>()); + bridge_.reset(new NiceMock<MockResourceLoaderBridge>()); factory_ = SimpleDataSource::CreateFactory(MessageLoop::current(), bridge_factory_.get()); @@ -52,7 +55,7 @@ class SimpleDataSourceTest : public testing::Test { } } - void InitializeDataSource(const char* url, bool is_loaded) { + void InitializeDataSource(const char* url) { media::MediaFormat url_format; url_format.SetAsString(media::MediaFormat::kMimeType, media::mime_type::kURL); @@ -63,8 +66,6 @@ class SimpleDataSourceTest : public testing::Test { // There is no need to provide a message loop to data source. data_source_->set_host(&host_); - EXPECT_CALL(host_, SetLoaded(is_loaded)); - // First a bridge is created. InSequence s; EXPECT_CALL(*bridge_factory_, CreateBridge(GURL(url), _, -1, -1)) @@ -72,13 +73,12 @@ class SimpleDataSourceTest : public testing::Test { EXPECT_CALL(*bridge_, Start(data_source_.get())) .WillOnce(Return(true)); - // TODO(hclam): need to add expectations to initialization callback. data_source_->Initialize(url, callback_.NewCallback()); MessageLoop::current()->RunAllPending(); } - void RequestSucceeded() { + void RequestSucceeded(bool is_loaded) { ResourceLoaderBridge::ResponseInfo info; info.content_length = kDataSize; @@ -90,6 +90,8 @@ class SimpleDataSourceTest : public testing::Test { for (int i = 0; i < kDataSize; ++i) data_source_->OnReceivedData(data_ + i, 1); + EXPECT_CALL(host_, SetLoaded(is_loaded)); + InSequence s; EXPECT_CALL(*bridge_, OnDestroy()) .WillOnce(Invoke(this, &SimpleDataSourceTest::ReleaseBridge)); @@ -158,8 +160,8 @@ class SimpleDataSourceTest : public testing::Test { protected: scoped_ptr<MessageLoop> message_loop_; - scoped_ptr<StrictMock<MockMediaResourceLoaderBridgeFactory> > bridge_factory_; - scoped_ptr<StrictMock<MockResourceLoaderBridge> > bridge_; + scoped_ptr<NiceMock<MockMediaResourceLoaderBridgeFactory> > bridge_factory_; + scoped_ptr<NiceMock<MockResourceLoaderBridge> > bridge_; scoped_refptr<media::FilterFactory> factory_; scoped_refptr<SimpleDataSource> data_source_; StrictMock<media::MockFilterHost> host_; @@ -170,62 +172,70 @@ class SimpleDataSourceTest : public testing::Test { }; TEST_F(SimpleDataSourceTest, InitializeHTTP) { - InitializeDataSource(kHttpUrl, false); - RequestSucceeded(); + InitializeDataSource(kHttpUrl); + RequestSucceeded(false); DestroyDataSource(); } TEST_F(SimpleDataSourceTest, InitializeHTTPS) { - InitializeDataSource(kHttpsUrl, false); - RequestSucceeded(); - DestroyDataSource(); -} - -TEST_F(SimpleDataSourceTest, InitializeFTP) { - InitializeDataSource(kFtpUrl, false); - RequestSucceeded(); + InitializeDataSource(kHttpsUrl); + RequestSucceeded(false); DestroyDataSource(); } TEST_F(SimpleDataSourceTest, InitializeFile) { - InitializeDataSource(kFileUrl, true); - RequestSucceeded(); + InitializeDataSource(kFileUrl); + RequestSucceeded(true); DestroyDataSource(); } -TEST_F(SimpleDataSourceTest, InitializeInvalid) { - StrictMock<media::MockFilterCallback> callback; +TEST_F(SimpleDataSourceTest, InitializeData) { + // Bridge is not used at all. + ReleaseBridge(); + media::MediaFormat url_format; url_format.SetAsString(media::MediaFormat::kMimeType, media::mime_type::kURL); - url_format.SetAsString(media::MediaFormat::kURL, kInvalidUrl); + url_format.SetAsString(media::MediaFormat::kURL, kDataUrl); data_source_ = factory_->Create<SimpleDataSource>(url_format); CHECK(data_source_); // There is no need to provide a message loop to data source. data_source_->set_host(&host_); - EXPECT_CALL(host_, SetError(media::PIPELINE_ERROR_NETWORK)); - EXPECT_CALL(callback, OnFilterCallback()); - EXPECT_CALL(callback, OnCallbackDestroyed()); + EXPECT_CALL(host_, SetLoaded(true)); + EXPECT_CALL(host_, SetTotalBytes(sizeof(kDataUrlDecoded))); + EXPECT_CALL(host_, SetBufferedBytes(sizeof(kDataUrlDecoded))); + EXPECT_CALL(callback_, OnFilterCallback()); + EXPECT_CALL(callback_, OnCallbackDestroyed()); - data_source_->Initialize(kInvalidUrl, callback.NewCallback()); - data_source_->Stop(); + data_source_->Initialize(kDataUrl, callback_.NewCallback()); MessageLoop::current()->RunAllPending(); - EXPECT_CALL(*bridge_factory_, OnDestroy()) - .WillOnce(Invoke(this, &SimpleDataSourceTest::ReleaseBridgeFactory)); - data_source_ = NULL; + DestroyDataSource(); +} + +TEST_F(SimpleDataSourceTest, InitializeInvalid) { + // They are not used at all. + ReleaseBridge(); + ReleaseBridgeFactory(); + + media::MediaFormat url_format; + url_format.SetAsString(media::MediaFormat::kMimeType, + media::mime_type::kURL); + url_format.SetAsString(media::MediaFormat::kURL, kInvalidUrl); + data_source_ = factory_->Create<SimpleDataSource>(url_format); + EXPECT_FALSE(data_source_); } TEST_F(SimpleDataSourceTest, RequestFailed) { - InitializeDataSource(kHttpUrl, false); + InitializeDataSource(kHttpUrl); RequestFailed(); DestroyDataSource(); } TEST_F(SimpleDataSourceTest, StopWhenDownloading) { - InitializeDataSource(kHttpUrl, false); + InitializeDataSource(kHttpUrl); EXPECT_CALL(*bridge_, Cancel()); EXPECT_CALL(*bridge_, OnDestroy()) @@ -235,8 +245,8 @@ TEST_F(SimpleDataSourceTest, StopWhenDownloading) { } TEST_F(SimpleDataSourceTest, AsyncRead) { - InitializeDataSource(kFileUrl, true); - RequestSucceeded(); + InitializeDataSource(kFileUrl); + RequestSucceeded(true); AsyncRead(); DestroyDataSource(); } diff --git a/webkit/tools/test_shell/test_shell.cc b/webkit/tools/test_shell/test_shell.cc index 5c28287..6691f85 100644 --- a/webkit/tools/test_shell/test_shell.cc +++ b/webkit/tools/test_shell/test_shell.cc @@ -690,7 +690,10 @@ bool IsDefaultPluginEnabled() { } bool IsProtocolSupportedForMedia(const GURL& url) { - if (url.SchemeIsFile() || url.SchemeIs("http") || url.SchemeIs("https")) + if (url.SchemeIsFile() || + url.SchemeIs("http") || + url.SchemeIs("https") || + url.SchemeIs("data")) return true; return false; } diff --git a/webkit/tools/test_shell/test_webview_delegate.cc b/webkit/tools/test_shell/test_webview_delegate.cc index 48fe80f..a05551b 100644 --- a/webkit/tools/test_shell/test_webview_delegate.cc +++ b/webkit/tools/test_shell/test_webview_delegate.cc @@ -613,9 +613,16 @@ WebMediaPlayer* TestWebViewDelegate::createMediaPlayer( base::GetCurrentProcId(), appcache::kNoHostId, 0); - factory->AddFactory(webkit_glue::BufferedDataSource::CreateFactory( - MessageLoop::current(), bridge_factory)); - // TODO(hclam): Use command line switch to determine which data source to use. + // A simple data source that keeps all data in memory. + media::FilterFactory* simple_data_source_factory = + webkit_glue::SimpleDataSource::CreateFactory(MessageLoop::current(), + bridge_factory); + // A sophisticated data source that does memory caching. + media::FilterFactory* buffered_data_source_factory = + webkit_glue::BufferedDataSource::CreateFactory(MessageLoop::current(), + bridge_factory); + factory->AddFactory(buffered_data_source_factory); + factory->AddFactory(simple_data_source_factory); return new webkit_glue::WebMediaPlayerImpl(client, factory); } |