diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-03 04:52:53 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-03 04:52:53 +0000 |
commit | d43ed917b1f7e8f875d2ee2aa0587512e265e28e (patch) | |
tree | 64b04bda5e59e98a387235000779a2b050f9fa2b /chrome/renderer | |
parent | 08e6413a6565ba434e1054a1df1c9fb778dad352 (diff) | |
download | chromium_src-d43ed917b1f7e8f875d2ee2aa0587512e265e28e.zip chromium_src-d43ed917b1f7e8f875d2ee2aa0587512e265e28e.tar.gz chromium_src-d43ed917b1f7e8f875d2ee2aa0587512e265e28e.tar.bz2 |
Merged with latest media pipeline and cleaned up some style stuff.
Changed WebMediaPlayerDelegateImpl to contains a PipelineImpl object rather keeping a pointer to Pipeline interface. Also added code for task coordination between pipeline thread and main thread.
Review URL: http://codereview.chromium.org/19481
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@9069 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/media/audio_renderer_impl.cc | 9 | ||||
-rw-r--r-- | chrome/renderer/media/audio_renderer_impl.h | 17 | ||||
-rw-r--r-- | chrome/renderer/media/data_source_impl.cc | 9 | ||||
-rw-r--r-- | chrome/renderer/media/data_source_impl.h | 17 | ||||
-rw-r--r-- | chrome/renderer/media/video_renderer_impl.cc | 18 | ||||
-rw-r--r-- | chrome/renderer/media/video_renderer_impl.h | 34 | ||||
-rw-r--r-- | chrome/renderer/render_view.cc | 2 | ||||
-rw-r--r-- | chrome/renderer/webmediaplayer_delegate_impl.cc | 324 | ||||
-rw-r--r-- | chrome/renderer/webmediaplayer_delegate_impl.h | 169 |
9 files changed, 489 insertions, 110 deletions
diff --git a/chrome/renderer/media/audio_renderer_impl.cc b/chrome/renderer/media/audio_renderer_impl.cc index ab59833..113d700 100644 --- a/chrome/renderer/media/audio_renderer_impl.cc +++ b/chrome/renderer/media/audio_renderer_impl.cc @@ -4,7 +4,8 @@ #include "chrome/renderer/media/audio_renderer_impl.h" -AudioRendererImpl::AudioRendererImpl() { +AudioRendererImpl::AudioRendererImpl(WebMediaPlayerDelegateImpl* delegate) + : delegate_(delegate) { } AudioRendererImpl::~AudioRendererImpl() { @@ -25,3 +26,9 @@ void AudioRendererImpl::SetVolume(float volume) { // TODO(scherkus): implement SetVolume. NOTIMPLEMENTED(); } + +bool AudioRendererImpl::IsMediaFormatSupported( + const media::MediaFormat* format) { + // TODO(hclam): check the format correct. + return true; +} diff --git a/chrome/renderer/media/audio_renderer_impl.h b/chrome/renderer/media/audio_renderer_impl.h index 94cb048..e76bf64 100644 --- a/chrome/renderer/media/audio_renderer_impl.h +++ b/chrome/renderer/media/audio_renderer_impl.h @@ -5,11 +5,14 @@ #ifndef CHROME_RENDERER_MEDIA_AUDIO_RENDERER_IMPL_H_ #define CHROME_RENDERER_MEDIA_AUDIO_RENDERER_IMPL_H_ +#include "media/base/factory.h" #include "media/base/filters.h" +class WebMediaPlayerDelegateImpl; + class AudioRendererImpl : public media::AudioRenderer { public: - AudioRendererImpl(); + AudioRendererImpl(WebMediaPlayerDelegateImpl* delegate); // media::MediaFilter implementation. virtual void Stop(); @@ -18,10 +21,22 @@ class AudioRendererImpl : public media::AudioRenderer { virtual bool Initialize(media::AudioDecoder* decoder); virtual void SetVolume(float volume); + // Static method for creating factory for this object. + static media::FilterFactory* CreateFactory( + WebMediaPlayerDelegateImpl* delegate) { + return new media::FilterFactoryImpl1<AudioRendererImpl, + WebMediaPlayerDelegateImpl*>(delegate); + } + + // Answers question from the factory to see if we accept |format|. + static bool IsMediaFormatSupported(const media::MediaFormat* format); + protected: virtual ~AudioRendererImpl(); private: + WebMediaPlayerDelegateImpl* delegate_; + DISALLOW_COPY_AND_ASSIGN(AudioRendererImpl); }; diff --git a/chrome/renderer/media/data_source_impl.cc b/chrome/renderer/media/data_source_impl.cc index 7193fcc..24dc4d2 100644 --- a/chrome/renderer/media/data_source_impl.cc +++ b/chrome/renderer/media/data_source_impl.cc @@ -4,7 +4,8 @@ #include "chrome/renderer/media/data_source_impl.h" -DataSourceImpl::DataSourceImpl() { +DataSourceImpl::DataSourceImpl(WebMediaPlayerDelegateImpl* delegate) + : delegate_(delegate) { } DataSourceImpl::~DataSourceImpl() { @@ -50,3 +51,9 @@ bool DataSourceImpl::GetSize(int64* size_out) { NOTIMPLEMENTED(); return false; } + +bool DataSourceImpl::IsMediaFormatSupported(const media::MediaFormat* format) { + // TODO(hclam: implement this. + NOTIMPLEMENTED(); + return true; +} diff --git a/chrome/renderer/media/data_source_impl.h b/chrome/renderer/media/data_source_impl.h index fe5bab8..33cbadf 100644 --- a/chrome/renderer/media/data_source_impl.h +++ b/chrome/renderer/media/data_source_impl.h @@ -7,12 +7,15 @@ #include <string> +#include "media/base/factory.h" #include "media/base/filters.h" #include "media/base/media_format.h" +class WebMediaPlayerDelegateImpl; + class DataSourceImpl : public media::DataSource { public: - DataSourceImpl(); + DataSourceImpl(WebMediaPlayerDelegateImpl* delegate); // media::MediaFilter implementation. virtual void Stop(); @@ -25,10 +28,22 @@ class DataSourceImpl : public media::DataSource { virtual bool SetPosition(int64 position); virtual bool GetSize(int64* size_out); + // Static method for creating factory for this object. + static media::FilterFactory* CreateFactory( + WebMediaPlayerDelegateImpl* delegate) { + return new media::FilterFactoryImpl1<DataSourceImpl, + WebMediaPlayerDelegateImpl*>(delegate); + } + + // Answers question from the factory to see if we accept |format|. + static bool IsMediaFormatSupported(const media::MediaFormat* format); + protected: virtual ~DataSourceImpl(); private: + WebMediaPlayerDelegateImpl* delegate_; + DISALLOW_COPY_AND_ASSIGN(DataSourceImpl); }; diff --git a/chrome/renderer/media/video_renderer_impl.cc b/chrome/renderer/media/video_renderer_impl.cc index 77d9d90..8159f00 100644 --- a/chrome/renderer/media/video_renderer_impl.cc +++ b/chrome/renderer/media/video_renderer_impl.cc @@ -4,7 +4,8 @@ #include "chrome/renderer/media/video_renderer_impl.h" -VideoRendererImpl::VideoRendererImpl() { +VideoRendererImpl::VideoRendererImpl(WebMediaPlayerDelegateImpl* delegate) + : delegate_(delegate) { } VideoRendererImpl::~VideoRendererImpl() { @@ -20,3 +21,18 @@ bool VideoRendererImpl::Initialize(media::VideoDecoder* decoder) { NOTIMPLEMENTED(); return false; } + +bool VideoRendererImpl::IsMediaFormatSupported( + const media::MediaFormat* format) { + // TODO(hclam): check the format correctly. + return true; +} + +void VideoRendererImpl::Paint(skia::PlatformCanvas *canvas, + const gfx::Rect& rect) { + // TODO(hclam): add stuff here. +} + +void VideoRendererImpl::SetRect(const gfx::Rect& rect) { + // TODO(hclam): add stuff here. +} diff --git a/chrome/renderer/media/video_renderer_impl.h b/chrome/renderer/media/video_renderer_impl.h index 9b58266..38a7124 100644 --- a/chrome/renderer/media/video_renderer_impl.h +++ b/chrome/renderer/media/video_renderer_impl.h @@ -1,15 +1,29 @@ // 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. +// +// The video renderer implementation to be use by the media pipeline. It lives +// inside video renderer thread and also WebKit's main thread. We need to be +// extra careful about members shared by two different threads, especially +// video frame buffers. +// +// Methods called from WebKit's main thread: +// Paint() +// SetRect() #ifndef CHROME_RENDERER_MEDIA_VIDEO_RENDERER_H_ #define CHROME_RENDERER_MEDIA_VIDEO_RENDERER_H_ +#include "base/gfx/platform_canvas.h" +#include "base/gfx/rect.h" +#include "media/base/factory.h" #include "media/base/filters.h" +class WebMediaPlayerDelegateImpl; + class VideoRendererImpl : public media::VideoRenderer { public: - VideoRendererImpl(); + VideoRendererImpl(WebMediaPlayerDelegateImpl* delegate); // media::MediaFilter implementation. virtual void Stop(); @@ -17,10 +31,28 @@ class VideoRendererImpl : public media::VideoRenderer { // media::VideoRenderer implementation. virtual bool Initialize(media::VideoDecoder* decoder); + // Called from WebMediaPlayerDelegateImpl from WebKit's main thread. + void Paint(skia::PlatformCanvas* canvas, const gfx::Rect& rect); + + // Called from WebMediaPlayerDelegateImpl from WebKit's main thread. + void SetRect(const gfx::Rect& rect); + + // Static method for creating factory for this object. + static media::FilterFactory* CreateFactory( + WebMediaPlayerDelegateImpl* delegate) { + return new media::FilterFactoryImpl1< + VideoRendererImpl, WebMediaPlayerDelegateImpl*>(delegate); + } + + // Answers question from the factory to see if we accept |format|. + static bool IsMediaFormatSupported(const media::MediaFormat* format); + protected: virtual ~VideoRendererImpl(); private: + WebMediaPlayerDelegateImpl* delegate_; + DISALLOW_COPY_AND_ASSIGN(VideoRendererImpl); }; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index 24ec3cf..932e042 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -1927,7 +1927,7 @@ WebPluginDelegate* RenderView::CreatePluginDelegate( } webkit_glue::WebMediaPlayerDelegate* RenderView::CreateMediaPlayerDelegate() { - return new WebMediaPlayerDelegateImpl(); + return new WebMediaPlayerDelegateImpl(this); } void RenderView::OnMissingPluginStatus(WebPluginDelegate* delegate, diff --git a/chrome/renderer/webmediaplayer_delegate_impl.cc b/chrome/renderer/webmediaplayer_delegate_impl.cc index 516a9c9..4eb3317 100644 --- a/chrome/renderer/webmediaplayer_delegate_impl.cc +++ b/chrome/renderer/webmediaplayer_delegate_impl.cc @@ -5,131 +5,337 @@ #include "chrome/renderer/media/audio_renderer_impl.h" #include "chrome/renderer/media/data_source_impl.h" #include "chrome/renderer/media/video_renderer_impl.h" +#include "chrome/renderer/render_view.h" #include "chrome/renderer/webmediaplayer_delegate_impl.h" +#include "googleurl/src/gurl.h" -WebMediaPlayerDelegateImpl::WebMediaPlayerDelegateImpl() - : bytes_loaded_(0), - current_time_(0.0f), - data_rate_(0), - duration_(0.0f), - height_(0), - network_state_(webkit_glue::WebMediaPlayer::EMPTY), - paused_(true), - playback_rate_(0.0f), +///////////////////////////////////////////////////////////////////////////// +// Task to be posted on main thread that fire WebMediaPlayer methods. + +class NotifyWebMediaPlayerTask : public CancelableTask { + public: + NotifyWebMediaPlayerTask(webkit_glue::WebMediaPlayer* web_media_player_, + WebMediaPlayerMethod method) + : method_(method) {} + + virtual void Run() { + if (web_media_player_) { + (web_media_player_->*(method_))(); + } + } + + virtual void Cancel() { + web_media_player_ = NULL; + } + + private: + webkit_glue::WebMediaPlayer* web_media_player_; + WebMediaPlayerMethod method_; + + DISALLOW_COPY_AND_ASSIGN(NotifyWebMediaPlayerTask); +}; + +///////////////////////////////////////////////////////////////////////////// +// WebMediaPlayerDelegateImpl implementation + +WebMediaPlayerDelegateImpl::WebMediaPlayerDelegateImpl(RenderView* render_view) + : network_state_(webkit_glue::WebMediaPlayer::EMPTY), ready_state_(webkit_glue::WebMediaPlayer::DATA_UNAVAILABLE), - seeking_(false), - total_bytes_(0), - video_(false), - visible_(false), - volume_(0.0f), + main_loop_(NULL), + filter_factory_(new media::FilterFactoryCollection()), web_media_player_(NULL), - width_(0) { - // TODO(hclam): initialize the media player here - - // TODO(scherkus): remove these when actually in use -- right now I declare - // these to force compiler/linker errors to reveal themselves. - scoped_refptr<AudioRendererImpl> audio_renderer; - audio_renderer = new AudioRendererImpl(); - scoped_refptr<DataSourceImpl> data_source; - data_source = new DataSourceImpl(); - scoped_refptr<VideoRendererImpl> video_renderer; - video_renderer = new VideoRendererImpl(); + render_view_(render_view), + tasks_(kLastTaskIndex) { + // TODO(hclam): Add filter factory for demuxer and decoders. + filter_factory_->AddFactory(AudioRendererImpl::CreateFactory(this)); + filter_factory_->AddFactory(VideoRendererImpl::CreateFactory(this)); + filter_factory_->AddFactory(DataSourceImpl::CreateFactory(this)); } WebMediaPlayerDelegateImpl::~WebMediaPlayerDelegateImpl() { - // TODO(hclam): do the following things here: - // 1. Destroy the internal media player - // 2. Destroy the associated WebMediaPlayer + // Stop the pipeline in the first place so we won't receive any more method + // calls from it. + pipeline_.Stop(); + + // Cancel all tasks posted on the main_loop_. + CancelAllTasks(); + + // After cancelling all tasks, we are sure there will be no calls to + // web_media_player_, so we are safe to delete it. + if (web_media_player_) { + delete web_media_player_; + } + + // Finally tell the main_loop_ we don't want to be notified of destruction + // event. + if (main_loop_) { + main_loop_->RemoveDestructionObserver(this); + } } void WebMediaPlayerDelegateImpl::Initialize( webkit_glue::WebMediaPlayer* media_player) { + DCHECK(!web_media_player_); web_media_player_ = media_player; + + // Saves the current message loop. + DCHECK(!main_loop_); + main_loop_ = MessageLoop::current(); + + // Also we want to be notified of main_loop_ destruction. + main_loop_->AddDestructionObserver(this); } void WebMediaPlayerDelegateImpl::Load(const GURL& url) { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + // Initialize the pipeline + pipeline_.Start(filter_factory_.get(), url.spec(), + NewCallback(this, &WebMediaPlayerDelegateImpl::DidInitializePipeline)); + + // TODO(hclam): Calls to render_view_ to kick start a resource load. } void WebMediaPlayerDelegateImpl::CancelLoad() { - // TODO(hclam): delegate to google's media player + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + // TODO(hclam): Calls to render_view_ to stop resource load } void WebMediaPlayerDelegateImpl::Play() { - // TODO(hclam): delegate to google's media player + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + // TODO(hclam): We should restore the previous playback rate rather than + // having it at 1.0. + pipeline_.SetPlaybackRate(1.0f); } void WebMediaPlayerDelegateImpl::Pause() { - // TODO(hclam): delegate to google's media player + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + pipeline_.SetPlaybackRate(0.0f); } void WebMediaPlayerDelegateImpl::Stop() { - // TODO(hclam): delegate to google's media player + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + // We can fire Stop() multiple times. + pipeline_.Stop(); } void WebMediaPlayerDelegateImpl::Seek(float time) { - // TODO(hclam): delegate to google's media player + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + pipeline_.Seek(base::TimeDelta::FromMilliseconds(static_cast<int64>(time))); } void WebMediaPlayerDelegateImpl::SetEndTime(float time) { - // TODO(hclam): delegate to google's media player + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + // TODO(hclam): add method call when it has been implemented. + return; } - + void WebMediaPlayerDelegateImpl::SetPlaybackRate(float rate) { - // TODO(hclam): delegate to google's media player + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + pipeline_.SetPlaybackRate(rate); } void WebMediaPlayerDelegateImpl::SetVolume(float volume) { - // TODO(hclam): delegate to google's media player + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + pipeline_.SetVolume(volume); } void WebMediaPlayerDelegateImpl::SetVisible(bool visible) { - // TODO(hclam): delegate to google's media player + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + // TODO(hclam): add appropriate method call when pipeline has it implemented. + return; } - + bool WebMediaPlayerDelegateImpl::IsTotalBytesKnown() { - // TODO(hclam): delegate to google's media player + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + return pipeline_.GetTotalBytes() != 0; +} + +bool WebMediaPlayerDelegateImpl::IsVideo() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + size_t width, height; + pipeline_.GetVideoSize(&width, &height); + return width != 0 && height != 0; +} + +size_t WebMediaPlayerDelegateImpl::GetWidth() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + size_t width, height; + pipeline_.GetVideoSize(&width, &height); + return width; +} + +size_t WebMediaPlayerDelegateImpl::GetHeight() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + size_t width, height; + pipeline_.GetVideoSize(&width, &height); + return height; +} + +bool WebMediaPlayerDelegateImpl::IsPaused() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + return pipeline_.GetPlaybackRate() == 0.0f; +} + +bool WebMediaPlayerDelegateImpl::IsSeeking() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + // TODO(hclam): Add this method call if pipeline has it in the interface. return false; } +float WebMediaPlayerDelegateImpl::GetDuration() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + return static_cast<float>(pipeline_.GetDuration().InSecondsF()); +} + +float WebMediaPlayerDelegateImpl::GetCurrentTime() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + return static_cast<float>(pipeline_.GetTime().InSecondsF()); +} + + +float WebMediaPlayerDelegateImpl::GetPlayBackRate() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + return pipeline_.GetPlaybackRate(); +} + +float WebMediaPlayerDelegateImpl::GetVolume() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + return pipeline_.GetVolume(); +} + +int WebMediaPlayerDelegateImpl::GetDataRate() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + // TODO(hclam): Add this method call if pipeline has it in the interface. + return 0; +} + float WebMediaPlayerDelegateImpl::GetMaxTimeBuffered() const { - // TODO(hclam): delegate to google's media player - return 0.0f; + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + return static_cast<float>(pipeline_.GetBufferedTime().InSecondsF()); } float WebMediaPlayerDelegateImpl::GetMaxTimeSeekable() const { - // TODO(hclam): delegate to google's media player + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + // TODO(hclam): add this method when pipeline has this method implemented. return 0.0f; } +int64 WebMediaPlayerDelegateImpl::GetBytesLoaded() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + return pipeline_.GetBufferedBytes(); +} + +int64 WebMediaPlayerDelegateImpl::GetTotalBytes() const { + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + return pipeline_.GetTotalBytes(); +} + void WebMediaPlayerDelegateImpl::SetRect(const gfx::Rect& rect) { - // TODO(hclam): Figure out what to do here.. + DCHECK(main_loop_ && MessageLoop::current() == main_loop_); + + if (video_renderer_) { + video_renderer_->SetRect(rect); + } } void WebMediaPlayerDelegateImpl::Paint(skia::PlatformCanvas *canvas, const gfx::Rect& rect) { - // TODO(hclam): grab a frame from the internal player and draw it. + if (video_renderer_) { + video_renderer_->Paint(canvas, rect); + } } -void WebMediaPlayerDelegateImpl::WillSendRequest(WebRequest& request, - const WebResponse& response) { - // TODO(hclam): do we need to change the request? +void WebMediaPlayerDelegateImpl::WillDestroyCurrentMessageLoop() { + // 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 + // associated WebMediaPlayer to leak. + pipeline_.Stop(); } -void WebMediaPlayerDelegateImpl::DidReceiveResponse( - const WebResponse& response) { - // TODO(hclam): tell the video piepline to prepare for arriving bytes. +void WebMediaPlayerDelegateImpl::DidInitializePipeline(bool successful) { + if (successful) { + // Since we have initialized the pipeline, we should be able to play it. + // And we skip LOADED_METADATA state and starting with LOADED_FIRST_FRAME. + ready_state_ = webkit_glue::WebMediaPlayer::CAN_PLAY; + network_state_ = webkit_glue::WebMediaPlayer::LOADED_FIRST_FRAME; + } else { + // TODO(hclam): should use pipeline_.GetError() to determine the state + // properly and reports error using MediaError. + ready_state_ = webkit_glue::WebMediaPlayer::DATA_UNAVAILABLE; + network_state_ = webkit_glue::WebMediaPlayer::LOAD_FAILED; + } + + PostTask(kNetworkStateTaskIndex, + &webkit_glue::WebMediaPlayer::NotifyNetworkStateChange); + PostTask(kReadyStateTaskIndex, + &webkit_glue::WebMediaPlayer::NotifyReadyStateChange); } -void WebMediaPlayerDelegateImpl::DidReceiveData(const char* buf, size_t size) { - // TODO(hclam): direct the data to video pipeline's data source +void WebMediaPlayerDelegateImpl::SetVideoRenderer( + VideoRendererImpl* video_renderer) { + DCHECK(!video_renderer_); + video_renderer_ = video_renderer; } -void WebMediaPlayerDelegateImpl::DidFinishLoading() { - // TODO(hclam): do appropriate actions related to load. We should wait - // for video pipeline to be initialized and fire a LOADED event. +void WebMediaPlayerDelegateImpl::DidTask(CancelableTask* task) { + AutoLock auto_lock(task_lock_); + + for (size_t i = 0; i < tasks_.size(); ++i) { + if (tasks_[i] == task) { + tasks_[i] = NULL; + return; + } + } + NOTREACHED(); +} + +void WebMediaPlayerDelegateImpl::CancelAllTasks() { + AutoLock auto_lock(task_lock_); + // Loop through the list of tasks and cancel tasks that are still alive. + for (size_t i = 0; i < tasks_.size(); ++i) { + if (tasks_[i]) + tasks_[i]->Cancel(); + } +} + +void WebMediaPlayerDelegateImpl::PostTask(int index, + WebMediaPlayerMethod method) { + DCHECK(main_loop_); + + AutoLock auto_lock(task_lock_); + if(!tasks_[index]) { + CancelableTask* task = new NotifyWebMediaPlayerTask(web_media_player_, + method); + tasks_[index] = task; + main_loop_->PostTask(FROM_HERE, task); + } } -void WebMediaPlayerDelegateImpl::DidFail(const WebError& error) { - // Simply fires a LOAD_FAILED event. - // TODO(hclam): will also need to fire a MediaError event. +void WebMediaPlayerDelegateImpl::PostRepaintTask() { + PostTask(kRepaintTaskIndex, &webkit_glue::WebMediaPlayer::Repaint); } diff --git a/chrome/renderer/webmediaplayer_delegate_impl.h b/chrome/renderer/webmediaplayer_delegate_impl.h index 8da1889..7e62b16 100644 --- a/chrome/renderer/webmediaplayer_delegate_impl.h +++ b/chrome/renderer/webmediaplayer_delegate_impl.h @@ -3,25 +3,67 @@ // LICENSE file. // // Delegate calls from WebCore::MediaPlayerPrivate to google's video player. -// It is a friend of VideoStackMediaPlayer, which is the actual media player -// VideoStackMediaPlayer will use WebMediaPlayer to create a resource loader -// and bridges the WebCore::ResourceHandle and media::DataSource, so that -// VideoStackMediaPlayer would have no knowledge of WebCore::ResourceHandle. +// It contains PipelineImpl which is the actual media player pipeline, it glues +// the media player pipeline, data source, audio renderer and renderer. +// PipelineImpl would creates multiple threads and access some public methods +// of this class, so we need to be extra careful about concurrent access of +// methods and members. +// +// Properties that are shared by main thread and media threads: +// CancelableTaskList tasks_; +// ^--- This property is shared for keeping records of the tasks posted to +// make sure there will be only one task for each task type that can +// exist in the main thread. +// +// Methods that are accessed in media threads: +// SetVideoRenderer() +// ^--- Called during the initialization of the pipeline, essentially from the +// the pipeline thread. +// PostRepaintTask() +// ^--- Called from the video renderer thread to notify a video frame has +// been prepared. +// PostTask() +// ^--- A method that helps posting tasks to the main thread, it is +// accessed from main thread and media threads, it access the |tasks_| +// internally. Needs locking inside to avoid concurrent access to +// |tasks_|. +// +// +// Other issues: +// During tear down of the whole browser or a tab, the DOM tree may not be +// destructed nicely, and there will be some dangling media threads trying to +// the main thread, so we need this class to listen to destruction event of the +// main thread and cleanup the media threads when the even is received. Also +// at destruction of this class we will need to unhook it from destruction event +// list of the main thread. #ifndef CHROME_RENDERER_WEBMEDIAPLAYER_DELEGATE_IMPL_H_ #define CHROME_RENDERER_WEBMEDIAPLAYER_DELEGATE_IMPL_H_ +#include <vector> + +#include "base/lock.h" +#include "base/message_loop.h" +#include "media/base/factory.h" +#include "media/base/filters.h" +#include "media/base/pipeline_impl.h" #include "webkit/glue/webmediaplayer_delegate.h" -namespace media { -class VideoStackMediaPlayer; -} +class RenderView; +class VideoRendererImpl; + +// This typedef is used for WebMediaPlayerDelegateImpl::PostTask() and +// NotifyWebMediaPlayerTask in the source file. +typedef void (webkit_glue::WebMediaPlayer::*WebMediaPlayerMethod)(); -class WebMediaPlayerDelegateImpl : public webkit_glue::WebMediaPlayerDelegate { +class WebMediaPlayerDelegateImpl : public webkit_glue::WebMediaPlayerDelegate, + public MessageLoop::DestructionObserver { public: - WebMediaPlayerDelegateImpl(); + explicit WebMediaPlayerDelegateImpl(RenderView* render_view); virtual ~WebMediaPlayerDelegateImpl(); + // Implementations of WebMediaPlayerDelegate, theses following methods are + // called from the WebKit, essentially lives inside the main thread. virtual void Initialize(webkit_glue::WebMediaPlayer* media_player); virtual void Load(const GURL& url); @@ -44,26 +86,28 @@ class WebMediaPlayerDelegateImpl : public webkit_glue::WebMediaPlayerDelegate { virtual void Paint(skia::PlatformCanvas *canvas, const gfx::Rect& rect); // True if a video is loaded. - virtual bool IsVideo() const { return video_; } + virtual bool IsVideo() const; // Dimension of the video. - virtual size_t GetWidth() const { return width_; } - virtual size_t GetHeight() const { return height_; } - - // Getters fo playback state. - virtual bool IsPaused() const { return paused_; } - virtual bool IsSeeking() const { return seeking_; } - virtual float GetDuration() const { return duration_; } - virtual float GetCurrentTime() const { return current_time_; } - virtual float GetPlayBackRate() const { return playback_rate_; } - virtual float GetVolume() const { return volume_; } + virtual size_t GetWidth() const; + virtual size_t GetHeight() const; + + // Getters of playback state. + virtual bool IsPaused() const; + virtual bool IsSeeking() const; + virtual float GetDuration() const; + virtual float GetCurrentTime() const; + virtual float GetPlayBackRate() const; + virtual float GetVolume() const; virtual float GetMaxTimeBuffered() const; virtual float GetMaxTimeSeekable() const; // Get rate of loading the resource. - virtual int32 GetDataRate() const { return data_rate_; } + virtual int32 GetDataRate() const; // Internal states of loading and network. + // TODO(hclam): Ask the pipeline about the state rather than having reading + // them from members which would cause race conditions. virtual webkit_glue::WebMediaPlayer::NetworkState GetNetworkState() const { return network_state_; } @@ -71,38 +115,75 @@ class WebMediaPlayerDelegateImpl : public webkit_glue::WebMediaPlayerDelegate { return ready_state_; } - virtual int64 GetBytesLoaded() const { return bytes_loaded_; } - virtual int64 GetTotalBytes() const { return total_bytes_; } + virtual int64 GetBytesLoaded() const; + virtual int64 GetTotalBytes() const; - // Data handlers. - virtual void WillSendRequest(WebRequest& request, - const WebResponse& response); - virtual void DidReceiveResponse(const WebResponse& response); - virtual void DidReceiveData(const char* buf, size_t size); - virtual void DidFinishLoading(); - virtual void DidFail(const WebError& error); + // As we are closing the tab or even the browser, main_loop_ is destroyed + // even before this object gets destructed, so we need to know when + // main_loop_ is being destroyed and we can stop posting repaint task + // to it. + virtual void WillDestroyCurrentMessageLoop(); + + // Callbacks. + void DidInitializePipeline(bool successful); // Inline getters. webkit_glue::WebMediaPlayer* web_media_player() { return web_media_player_; } + // Called from tasks posted to main_loop_ from this object to remove + // reference of them. + void DidTask(CancelableTask* task); + + // Public methods to be called from renderers and data source. + void SetVideoRenderer(VideoRendererImpl* video_renderer); + + // Called from VideoRenderer to fire a repaint task to main_loop_. + void PostRepaintTask(); + private: - int64 bytes_loaded_; - float current_time_; - int32 data_rate_; - float duration_; - size_t height_; + // Methods for posting tasks and cancelling tasks. This method may lives in + // the main thread or the media threads. + void PostTask(int index, WebMediaPlayerMethod method); + + // Cancel all tasks currently lives in |main_loop_|. + void CancelAllTasks(); + + // Indexes for tasks. + enum { + kRepaintTaskIndex = 0, + kReadyStateTaskIndex, + kNetworkStateTaskIndex, + kLastTaskIndex + }; + + // TODO(hclam): get rid of these members and read from the pipeline directly. webkit_glue::WebMediaPlayer::NetworkState network_state_; - bool paused_; - float playback_rate_; webkit_glue::WebMediaPlayer::ReadyState ready_state_; - bool seeking_; - int64 total_bytes_; - bool video_; - media::VideoStackMediaPlayer* video_stack_media_player_; - bool visible_; - float volume_; + + // Message loops for posting tasks between Chrome's main thread. Also used + // for DCHECKs so methods calls won't execute in the wrong thread. + MessageLoop* main_loop_; + + // A collection of factories for creating filters. + scoped_refptr<media::FilterFactoryCollection> filter_factory_; + + // The actual pipeline. We do it a composition here because we expect to have + // the same lifetime as the pipeline. + media::PipelineImpl pipeline_; + + // We have the interface to VideoRenderer to delegate paint messages to it + // from WebKit. + VideoRendererImpl* video_renderer_; + webkit_glue::WebMediaPlayer* web_media_player_; - size_t width_; + RenderView* render_view_; + + // List of tasks for holding pointers to all tasks currently in the + // |main_loop_|. |tasks_| can be access from main thread or the media threads + // we need a lock for protecting it. + Lock task_lock_; + typedef std::vector<CancelableTask*> CancelableTaskList; + CancelableTaskList tasks_; DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerDelegateImpl); }; |