diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-17 01:44:41 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-17 01:44:41 +0000 |
commit | ba4363e6ca4c3667c4640666e66fbdf5ab162dec (patch) | |
tree | 9c6a90313208612481cd7045d8100978e4672b86 /chrome | |
parent | 0e8588c1528cad6732d172775aba8e891baebdef (diff) | |
download | chromium_src-ba4363e6ca4c3667c4640666e66fbdf5ab162dec.zip chromium_src-ba4363e6ca4c3667c4640666e66fbdf5ab162dec.tar.gz chromium_src-ba4363e6ca4c3667c4640666e66fbdf5ab162dec.tar.bz2 |
Load media resource with file handle for media playback
Used ResourceDispatcher to provide resource loading mechanism for media
playback in DataSourceImpl. So now DataSourceImpl actually initialize the
resource loading in browser process using ResourceDispatcher and
IPCResourceLoaderBridge. DataSourceImpl will be using the file handle provided
in resource response for reading and listen on OnDownloadProgress for download
progress.
Review URL: http://codereview.chromium.org/39159
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11820 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/renderer/media/data_source_impl.cc | 130 | ||||
-rw-r--r-- | chrome/renderer/media/data_source_impl.h | 63 | ||||
-rw-r--r-- | chrome/renderer/webmediaplayer_delegate_impl.cc | 23 | ||||
-rw-r--r-- | chrome/renderer/webmediaplayer_delegate_impl.h | 5 |
4 files changed, 185 insertions, 36 deletions
diff --git a/chrome/renderer/media/data_source_impl.cc b/chrome/renderer/media/data_source_impl.cc index 96a253b..9993352 100644 --- a/chrome/renderer/media/data_source_impl.cc +++ b/chrome/renderer/media/data_source_impl.cc @@ -4,20 +4,26 @@ #include "base/compiler_specific.h" #include "base/message_loop.h" +#include "base/process_util.h" #include "chrome/renderer/media/data_source_impl.h" #include "chrome/renderer/render_view.h" #include "chrome/renderer/webmediaplayer_delegate_impl.h" +#include "chrome/renderer/render_thread.h" #include "media/base/filter_host.h" #include "media/base/pipeline.h" +#include "net/base/load_flags.h" #include "net/base/net_errors.h" DataSourceImpl::DataSourceImpl(WebMediaPlayerDelegateImpl* delegate) : delegate_(delegate), + render_loop_(RenderThread::current()->message_loop()), stopped_(false), download_event_(false, false), downloaded_bytes_(0), total_bytes_(0), total_bytes_known_(false), + resource_loader_bridge_(NULL), + resource_release_event_(true, false), read_event_(false, false), ALLOW_THIS_IN_INITIALIZER_LIST( read_callback_(this, &DataSourceImpl::OnDidFileStreamRead)), @@ -27,6 +33,8 @@ DataSourceImpl::DataSourceImpl(WebMediaPlayerDelegateImpl* delegate) io_loop_(delegate->view()->GetMessageLoopForIO()), close_event_(false, false), seek_event_(false, false) { + // Register ourselves with WebMediaPlayerDelgateImpl. + delegate_->SetDataSource(this); } DataSourceImpl::~DataSourceImpl() { @@ -37,13 +45,20 @@ void DataSourceImpl::Stop() { return; stopped_ = true; - // TODO(hclam): things to do here: - // 1. Call to RenderView to cancel the streaming resource request. + // 1. Cancel the resource request. + if (!resource_release_event_.IsSignaled()) { + render_loop_->PostTask(FROM_HERE, + NewRunnableMethod(this, &DataSourceImpl::ReleaseRendererResources)); + resource_release_event_.Wait(); + } + // 2. Signal download_event_. download_event_.Signal(); // Post a close file stream task to IO message loop, it will signal the read // event. + // TODO(hclam): make sure it's safe to do this during destruction of + // RenderThread. io_loop_->PostTask( FROM_HERE, NewRunnableMethod(this, &DataSourceImpl::OnCloseFileStream)); @@ -55,13 +70,11 @@ void DataSourceImpl::Stop() { } bool DataSourceImpl::Initialize(const std::string& url) { - // TODO(hclam): call to RenderView by delegate_->view() to initiate a - // streaming session in the browser process. Call to RenderView by - // delegate_->view() to initiate a streaming session in the browser process. - // We should get a call back at OnReceivedResponse(). media_format_.SetAsString(media::MediaFormat::kMimeType, media::mime_type::kApplicationOctetStream); media_format_.SetAsString(media::MediaFormat::kURL, url); + render_loop_->PostTask(FROM_HERE, + NewRunnableMethod(this, &DataSourceImpl::OnInitialize, url)); return true; } @@ -194,33 +207,104 @@ void DataSourceImpl::OnDidFileStreamRead(int size) { read_event_.Signal(); } -void DataSourceImpl::OnReceivedResponse(base::PlatformFile file, - int response_code, - int64 content_length) { - // TODO(hclam): come up with a valid set of response codes and react to the - // code properly and not just the file handle. - if (file != base::kInvalidPlatformFileValue) { +void DataSourceImpl::OnInitialize(std::string uri) { + uri_ = uri; + // Create the resource loader bridge. + resource_loader_bridge_ = + RenderThread::current()->resource_dispatcher()->CreateBridge( + "GET", + GURL(uri), + GURL(uri), + GURL(), // TODO(hclam): provide referer here. + std::string(), // Provide no header. + // Prefer to load from cache, also enable downloading the file, the + // resource will be saved to a single response data file if it's possible. + net::LOAD_PREFERRING_CACHE | net::LOAD_ENABLE_DOWNLOAD_FILE, + base::GetCurrentProcId(), + ResourceType::MEDIA, + false, + 0, + delegate_->view()->routing_id()); + // Start the resource loading. + resource_loader_bridge_->Start(this); +} + +void DataSourceImpl::ReleaseRendererResources() { + DCHECK(MessageLoop::current() == render_loop_); + if (resource_loader_bridge_) { + resource_loader_bridge_->Cancel(); + resource_loader_bridge_ = NULL; + } + resource_release_event_.Signal(); +} + +void DataSourceImpl::OnDownloadProgress(uint64 position, uint64 size) { + { + AutoLock auto_lock(lock_); + downloaded_bytes_ = position; + if (!total_bytes_known_) { + if (size == kuint64max) + total_bytes_ = position; + else { + total_bytes_ = size; + total_bytes_known_ = true; + } + } + } + download_event_.Signal(); +} + +void DataSourceImpl::OnUploadProgress(uint64 position, uint64 size) { + // We don't care about upload progress. +} + +void DataSourceImpl::OnReceivedRedirect(const GURL& new_url) { + // TODO(hclam): what to do here? fire another resource request or show an + // error? +} + +void DataSourceImpl::OnReceivedResponse( + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered) { +#if defined(OS_POSIX) + base::PlatformFile response_data_file = info.response_data_file.fd; +#elif defined(OS_WIN) + base::PlatformFile response_data_file = info.response_data_file; +#endif + + if (response_data_file != base::kInvalidPlatformFileValue) { DCHECK(!position_ && !downloaded_bytes_); - total_bytes_ = content_length; - if (content_length != 0) + if (info.content_length != -1) { total_bytes_known_ = true; + total_bytes_ = info.content_length; + } // Post a task to the IO message loop to create the file stream. - delegate_->view()->GetMessageLoopForIO()->PostTask(FROM_HERE, - NewRunnableMethod(this, &DataSourceImpl::OnCreateFileStream, file)); + io_loop_->PostTask(FROM_HERE, + NewRunnableMethod(this, &DataSourceImpl::OnCreateFileStream, + response_data_file)); } else { + // TODO(hclam): handle the fallback case of using memory buffer here. host_->Error(media::PIPELINE_ERROR_NETWORK); } } -void DataSourceImpl::OnReceivedData(size_t bytes) { - { - AutoLock auto_lock(lock_); - downloaded_bytes_ += bytes; - if (!total_bytes_known_) - total_bytes_ += bytes; +void DataSourceImpl::OnReceivedData(const char* data, int len) { + // TODO(hclam): we will get this method call when browser process fails + // to provide us with a file handle, come up with some fallback mechanism. +} + +void DataSourceImpl::OnCompletedRequest(const URLRequestStatus& status, + const std::string& security_info) { + if (status.status() != URLRequestStatus::SUCCESS) { + host_->Error(media::PIPELINE_ERROR_NETWORK); + } else { + // TODO(hclam): notify end of stream to pipeline. } - download_event_.Signal(); +} + +std::string DataSourceImpl::GetURLForDebugging() { + return uri_; } const media::MediaFormat* DataSourceImpl::GetMediaFormat() { diff --git a/chrome/renderer/media/data_source_impl.h b/chrome/renderer/media/data_source_impl.h index 95e8090..9190b25 100644 --- a/chrome/renderer/media/data_source_impl.h +++ b/chrome/renderer/media/data_source_impl.h @@ -27,12 +27,21 @@ // Render thread // +-- DataSourceImpl() // | Perform construction of this class. +// |-- static CreateFactory() +// | Called during construction of this class. +// |-- OnInitialize() +// | Task posted by Initialize() to kick start resource loading. +// |-- OnCancel() +// | Cancel the resource loading. +// |-- OnDownloadProgress() +// | Receives download progress information for the response data file. +// |-- OnUploadProgress() +// |-- OnReceivedRedirect() // |-- OnReceivedResponse() -// | Notify the response information of a progressive resource load. -// |-- OnReceivedData(); -// | Notify the progress of a progress resource load. -// \-- static CreateFactory() -// Called during construction of this class. +// |-- OnReceivedData() +// |-- OnCompletedRequest() +// |-- GetURLForDebugging() +// \-- ReleaseRendererResources(); // // Pipeline thread // +-- Initialize() @@ -77,10 +86,12 @@ #include "media/base/media_format.h" #include "net/base/completion_callback.h" #include "net/base/file_stream.h" +#include "webkit/glue/resource_loader_bridge.h" class WebMediaPlayerDelegateImpl; -class DataSourceImpl : public media::DataSource { +class DataSourceImpl : public media::DataSource, + public webkit_glue::ResourceLoaderBridge::Peer { public: // Methods called from render thread ---------------------------------------- // Static methods for creating this class. @@ -90,10 +101,28 @@ class DataSourceImpl : public media::DataSource { WebMediaPlayerDelegateImpl*>(delegate); } - // Handlers for asynchronous streaming. - void OnReceivedResponse(base::PlatformFile file, int response_cide, - int64 content_length); - void OnReceivedData(size_t size); + // webkit_glue::ResourceLoaderBridge::Peer implementations, receive events + // for resource loading. + virtual void OnDownloadProgress(uint64 position, uint64 size); + virtual void OnUploadProgress(uint64 position, uint64 size); + virtual void OnReceivedRedirect(const GURL& new_url); + virtual void OnReceivedResponse( + const webkit_glue::ResourceLoaderBridge::ResponseInfo& info, + bool content_filtered); + virtual void OnReceivedData(const char* data, int len); + virtual void OnCompletedRequest(const URLRequestStatus& status, + const std::string& security_info); + virtual std::string GetURLForDebugging(); + + // Release all resources associated with RenderView, particularly + // ResourceLoaderBridge created by ResourceDispatcher. This method should only + // be executed on render thread, we have this method standalone and public + // here because WebMediaPlayerDelegateImpl will be calling this method when + // render thread is being destroyed, and in that case we can't post tasks to + // render thread from pipeline thread anymore so we have to release resources + // manually from WebMediaPlayerDelegateImpl and we will not do the same thing + // in Stop(). + void ReleaseRendererResources(); // Methods called from pipeline thread -------------------------------------- virtual bool Initialize(const std::string& url); @@ -117,6 +146,10 @@ class DataSourceImpl : public media::DataSource { explicit DataSourceImpl(WebMediaPlayerDelegateImpl* delegate); virtual ~DataSourceImpl(); + // Tasks to be posted on render thread. + void OnInitialize(std::string uri); + void OnCancel(); + // Methods called from IO thread -------------------------------------------- // Handlers for file reading. void OnCreateFileStream(base::PlatformFile file); @@ -131,18 +164,28 @@ class DataSourceImpl : public media::DataSource { // in construction and can be accessed in all threads safely. WebMediaPlayerDelegateImpl* delegate_; + // Message loop of render thread. + MessageLoop* render_loop_; + // A common lock for protecting members accessed by multiple threads. Lock lock_; // A flag that indicates whether this object has been called to stop. bool stopped_; + // URI to the resource being downloaded. + std::string uri_; + // Members for keeping track of downloading progress. base::WaitableEvent download_event_; int64 downloaded_bytes_; int64 total_bytes_; bool total_bytes_known_; + // Members related to resource loading with RenderView. + webkit_glue::ResourceLoaderBridge* resource_loader_bridge_; + base::WaitableEvent resource_release_event_; + // Members used for reading. base::WaitableEvent read_event_; net::CompletionCallbackImpl<DataSourceImpl> read_callback_; diff --git a/chrome/renderer/webmediaplayer_delegate_impl.cc b/chrome/renderer/webmediaplayer_delegate_impl.cc index 11c2391..78dcd4c 100644 --- a/chrome/renderer/webmediaplayer_delegate_impl.cc +++ b/chrome/renderer/webmediaplayer_delegate_impl.cc @@ -46,6 +46,7 @@ WebMediaPlayerDelegateImpl::WebMediaPlayerDelegateImpl(RenderView* view) filter_factory_(new media::FilterFactoryCollection()), audio_renderer_(NULL), video_renderer_(NULL), + data_source_(NULL), web_media_player_(NULL), view_(view), tasks_(kLastTaskIndex) { @@ -273,10 +274,21 @@ void WebMediaPlayerDelegateImpl::Paint(skia::PlatformCanvas *canvas, } void WebMediaPlayerDelegateImpl::WillDestroyCurrentMessageLoop() { - if (audio_renderer_) + // Instruct the renderers and data source to release all Renderer related + // resources during destruction of render thread, because they won't have any + // chance to release these resources on render thread by posting tasks on it. + if (audio_renderer_) { audio_renderer_->ReleaseRendererResources(); - // Stop the pipeline when the main thread is being destroyed so we won't be - // posting any more messages onto it. And we just let this obejct and + audio_renderer_ = NULL; + } + + if (data_source_) { + data_source_->ReleaseRendererResources(); + data_source_ = NULL; + } + + // Stop the pipeline when the render thread is being destroyed so we won't be + // posting any more messages onto it. And we just let this object and // associated WebMediaPlayer to leak. pipeline_.Stop(); } @@ -312,6 +324,11 @@ void WebMediaPlayerDelegateImpl::SetVideoRenderer( video_renderer_ = video_renderer; } +void WebMediaPlayerDelegateImpl::SetDataSource( + DataSourceImpl* data_source) { + data_source_ = data_source; +} + void WebMediaPlayerDelegateImpl::DidTask(CancelableTask* task) { AutoLock auto_lock(task_lock_); diff --git a/chrome/renderer/webmediaplayer_delegate_impl.h b/chrome/renderer/webmediaplayer_delegate_impl.h index 4f8df38..b557393 100644 --- a/chrome/renderer/webmediaplayer_delegate_impl.h +++ b/chrome/renderer/webmediaplayer_delegate_impl.h @@ -52,6 +52,7 @@ #include "webkit/glue/webmediaplayer_delegate.h" class AudioRendererImpl; +class DataSourceImpl; class RenderView; class VideoRendererImpl; @@ -142,6 +143,7 @@ class WebMediaPlayerDelegateImpl : public webkit_glue::WebMediaPlayerDelegate, // WebMediaPlayerDelegateImpl has references to them. void SetAudioRenderer(AudioRendererImpl* audio_renderer); void SetVideoRenderer(VideoRendererImpl* video_renderer); + void SetDataSource(DataSourceImpl* data_source); // Called from VideoRenderer to fire a repaint task to main_loop_. void PostRepaintTask(); @@ -189,6 +191,9 @@ class WebMediaPlayerDelegateImpl : public webkit_glue::WebMediaPlayerDelegate, // from WebKit. scoped_refptr<VideoRendererImpl> video_renderer_; + // Pointer to DataSourceImpl so we can release render resources. + scoped_refptr<DataSourceImpl> data_source_; + webkit_glue::WebMediaPlayer* web_media_player_; RenderView* view_; |