summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
authorhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-03 04:52:53 +0000
committerhclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-02-03 04:52:53 +0000
commitd43ed917b1f7e8f875d2ee2aa0587512e265e28e (patch)
tree64b04bda5e59e98a387235000779a2b050f9fa2b /chrome/renderer
parent08e6413a6565ba434e1054a1df1c9fb778dad352 (diff)
downloadchromium_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.cc9
-rw-r--r--chrome/renderer/media/audio_renderer_impl.h17
-rw-r--r--chrome/renderer/media/data_source_impl.cc9
-rw-r--r--chrome/renderer/media/data_source_impl.h17
-rw-r--r--chrome/renderer/media/video_renderer_impl.cc18
-rw-r--r--chrome/renderer/media/video_renderer_impl.h34
-rw-r--r--chrome/renderer/render_view.cc2
-rw-r--r--chrome/renderer/webmediaplayer_delegate_impl.cc324
-rw-r--r--chrome/renderer/webmediaplayer_delegate_impl.h169
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);
};