diff options
-rw-r--r-- | chrome/renderer/render_view.cc | 21 | ||||
-rw-r--r-- | chrome/renderer/renderer_glue.cc | 1 | ||||
-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 |
9 files changed, 159 insertions, 74 deletions
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 89d67f8..31c449b 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -1789,15 +1789,20 @@ WebMediaPlayer* RenderView::createMediaPlayer( appcache::kNoHostId, routing_id()); - if (!cmd_line->HasSwitch(switches::kSimpleDataSource)) { - // Add the chrome specific media data source. - factory->AddFactory( - webkit_glue::BufferedDataSource::CreateFactory(MessageLoop::current(), - bridge_factory)); + // 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); + if (cmd_line->HasSwitch(switches::kSimpleDataSource)) { + factory->AddFactory(simple_data_source_factory); + factory->AddFactory(buffered_data_source_factory); } else { - factory->AddFactory( - webkit_glue::SimpleDataSource::CreateFactory(MessageLoop::current(), - bridge_factory)); + factory->AddFactory(buffered_data_source_factory); + factory->AddFactory(simple_data_source_factory); } return new webkit_glue::WebMediaPlayerImpl(client, factory); } diff --git a/chrome/renderer/renderer_glue.cc b/chrome/renderer/renderer_glue.cc index 1410376..43012e9 100644 --- a/chrome/renderer/renderer_glue.cc +++ b/chrome/renderer/renderer_glue.cc @@ -218,6 +218,7 @@ bool IsProtocolSupportedForMedia(const GURL& url) { // validated accordingly in the media engine. if (url.SchemeIsFile() || url.SchemeIs(chrome::kHttpScheme) || url.SchemeIs(chrome::kHttpsScheme) || + url.SchemeIs(chrome::kDataScheme) || url.SchemeIs(chrome::kExtensionScheme)) return true; return false; 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); } |