summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--webkit/api/public/WebMediaPlayer.h9
-rw-r--r--webkit/glue/media/video_renderer_impl.cc14
-rw-r--r--webkit/glue/media/video_renderer_impl.h15
-rw-r--r--webkit/glue/webmediaplayer_impl.cc366
-rw-r--r--webkit/glue/webmediaplayer_impl.h179
5 files changed, 346 insertions, 237 deletions
diff --git a/webkit/api/public/WebMediaPlayer.h b/webkit/api/public/WebMediaPlayer.h
index 56d01e5..740b894 100644
--- a/webkit/api/public/WebMediaPlayer.h
+++ b/webkit/api/public/WebMediaPlayer.h
@@ -1,10 +1,10 @@
/*
* Copyright (C) 2009 Google Inc. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
@@ -14,7 +14,7 @@
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
@@ -67,7 +67,6 @@ namespace WebKit {
// Playback controls.
virtual void play() = 0;
virtual void pause() = 0;
- virtual void stop() = 0;
virtual void seek(float seconds) = 0;
virtual void setEndTime(float seconds) = 0;
virtual void setRate(float) = 0;
@@ -88,7 +87,7 @@ namespace WebKit {
// Dimension of the video.
virtual WebSize naturalSize() const = 0;
- // Getters fo playback state.
+ // Getters of playback state.
virtual bool paused() const = 0;
virtual bool seeking() const = 0;
virtual float duration() const = 0;
diff --git a/webkit/glue/media/video_renderer_impl.cc b/webkit/glue/media/video_renderer_impl.cc
index 9137fb3..a7dc980 100644
--- a/webkit/glue/media/video_renderer_impl.cc
+++ b/webkit/glue/media/video_renderer_impl.cc
@@ -9,12 +9,12 @@
namespace webkit_glue {
-VideoRendererImpl::VideoRendererImpl(WebMediaPlayerImpl* delegate)
- : delegate_(delegate),
+ VideoRendererImpl::VideoRendererImpl(WebMediaPlayerImpl::Proxy* proxy)
+ : proxy_(proxy),
last_converted_frame_(NULL) {
// TODO(hclam): decide whether to do the following line in this thread or
// in the render thread.
- delegate_->SetVideoRenderer(this);
+ proxy->SetVideoRenderer(this);
}
// static
@@ -25,7 +25,6 @@ bool VideoRendererImpl::IsMediaFormatSupported(
return ParseMediaFormat(media_format, &width, &height);
}
-
bool VideoRendererImpl::OnInitialize(media::VideoDecoder* decoder) {
int width = 0;
int height = 0;
@@ -44,11 +43,14 @@ bool VideoRendererImpl::OnInitialize(media::VideoDecoder* decoder) {
}
void VideoRendererImpl::OnStop() {
- delegate_->SetVideoRenderer(NULL);
+ DCHECK(proxy_);
+ proxy_->SetVideoRenderer(NULL);
+ proxy_ = NULL;
}
void VideoRendererImpl::OnFrameAvailable() {
- delegate_->PostRepaintTask();
+ DCHECK(proxy_);
+ proxy_->Repaint();
}
void VideoRendererImpl::SetRect(const gfx::Rect& rect) {
diff --git a/webkit/glue/media/video_renderer_impl.h b/webkit/glue/media/video_renderer_impl.h
index ee251a5..d57223e 100644
--- a/webkit/glue/media/video_renderer_impl.h
+++ b/webkit/glue/media/video_renderer_impl.h
@@ -22,14 +22,13 @@
#include "media/base/filters.h"
#include "media/filters/video_renderer_base.h"
#include "webkit/api/public/WebMediaPlayer.h"
+#include "webkit/glue/webmediaplayer_impl.h"
namespace webkit_glue {
-class WebMediaPlayerImpl;
-
class VideoRendererImpl : public media::VideoRendererBase {
public:
- // Methods for painting called by the WebMediaPlayerDelegateImpl
+ // Methods for painting called by the WebMediaPlayerImpl::Proxy
// This method is called with the same rect as the Paint method and could
// be used by future implementations to implement an improved color space +
@@ -42,9 +41,9 @@ class VideoRendererImpl : public media::VideoRendererBase {
virtual void Paint(skia::PlatformCanvas* canvas, const gfx::Rect& dest_rect);
// Static method for creating factory for this object.
- static media::FilterFactory* CreateFactory(WebMediaPlayerImpl* delegate) {
+ static media::FilterFactory* CreateFactory(WebMediaPlayerImpl::Proxy* proxy) {
return new media::FilterFactoryImpl1<VideoRendererImpl,
- WebMediaPlayerImpl*>(delegate);
+ WebMediaPlayerImpl::Proxy*>(proxy);
}
// FilterFactoryImpl1 implementation.
@@ -63,8 +62,8 @@ class VideoRendererImpl : public media::VideoRendererBase {
private:
// Only the filter factories can create instances.
friend class media::FilterFactoryImpl1<VideoRendererImpl,
- WebMediaPlayerImpl*>;
- explicit VideoRendererImpl(WebMediaPlayerImpl* delegate);
+ WebMediaPlayerImpl::Proxy*>;
+ explicit VideoRendererImpl(WebMediaPlayerImpl::Proxy* proxy);
virtual ~VideoRendererImpl() {}
// Determine the conditions to perform fast paint. Returns true if we can do
@@ -87,7 +86,7 @@ class VideoRendererImpl : public media::VideoRendererBase {
SkIRect* dest_rect);
// Pointer to our parent object that is called to request repaints.
- WebMediaPlayerImpl* delegate_;
+ scoped_refptr<WebMediaPlayerImpl::Proxy> proxy_;
// An RGB bitmap used to convert the video frames.
SkBitmap bitmap_;
diff --git a/webkit/glue/webmediaplayer_impl.cc b/webkit/glue/webmediaplayer_impl.cc
index d538a72..452a9e6 100644
--- a/webkit/glue/webmediaplayer_impl.cc
+++ b/webkit/glue/webmediaplayer_impl.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "webkit/glue/webmediaplayer_impl.h"
+
#include "base/command_line.h"
#include "googleurl/src/gurl.h"
#include "media/filters/ffmpeg_audio_decoder.h"
@@ -12,41 +14,148 @@
#include "webkit/api/public/WebSize.h"
#include "webkit/api/public/WebURL.h"
#include "webkit/glue/media/video_renderer_impl.h"
-#include "webkit/glue/webmediaplayer_impl.h"
using WebKit::WebCanvas;
using WebKit::WebRect;
using WebKit::WebSize;
+namespace {
+
+// Limits the maximum outstanding repaints posted on render thread.
+// This number of 50 is a guess, it does not take too much memory on the task
+// queue but gives up a pretty good latency on repaint.
+const int kMaxOutstandingRepaints = 50;
+
+} // namespace
+
namespace webkit_glue {
/////////////////////////////////////////////////////////////////////////////
-// Task to be posted on main thread that fire WebMediaPlayerClient methods.
-
-class NotifyWebMediaPlayerClientTask : public CancelableTask {
- public:
- NotifyWebMediaPlayerClientTask(WebMediaPlayerImpl* media_player,
- WebMediaPlayerClientMethod method)
- : media_player_(media_player),
- method_(method) {}
-
- virtual void Run() {
- if (media_player_) {
- (media_player_->client()->*(method_))();
- media_player_->DidTask(this);
- }
+// WebMediaPlayerImpl::Proxy implementation
+
+WebMediaPlayerImpl::Proxy::Proxy(MessageLoop* render_loop,
+ WebMediaPlayerImpl* webmediaplayer)
+ : render_loop_(render_loop),
+ webmediaplayer_(webmediaplayer),
+ outstanding_repaints_(0) {
+ DCHECK(render_loop_);
+ DCHECK(webmediaplayer_);
+}
+
+WebMediaPlayerImpl::Proxy::~Proxy() {
+ Detach();
+}
+
+void WebMediaPlayerImpl::Proxy::Repaint() {
+ AutoLock auto_lock(lock_);
+ if (outstanding_repaints_ < kMaxOutstandingRepaints) {
+ ++outstanding_repaints_;
+
+ render_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &WebMediaPlayerImpl::Proxy::RepaintTask));
+ }
+}
+
+void WebMediaPlayerImpl::Proxy::TimeChanged() {
+ render_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &WebMediaPlayerImpl::Proxy::TimeChangedTask));
+}
+
+void WebMediaPlayerImpl::Proxy::NetworkStateChanged(
+ WebKit::WebMediaPlayer::NetworkState state) {
+ render_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &WebMediaPlayerImpl::Proxy::NetworkStateChangedTask,
+ state));
+}
+
+void WebMediaPlayerImpl::Proxy::ReadyStateChanged(
+ WebKit::WebMediaPlayer::ReadyState state) {
+ render_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &WebMediaPlayerImpl::Proxy::ReadyStateChangedTask,
+ state));
+}
+
+void WebMediaPlayerImpl::Proxy::RepaintTask() {
+ DCHECK(MessageLoop::current() == render_loop_);
+ {
+ AutoLock auto_lock(lock_);
+ --outstanding_repaints_;
+ DCHECK_GE(outstanding_repaints_, 0);
+ }
+ if (webmediaplayer_)
+ webmediaplayer_->Repaint();
+}
+
+void WebMediaPlayerImpl::Proxy::TimeChangedTask() {
+ DCHECK(MessageLoop::current() == render_loop_);
+ if (webmediaplayer_)
+ webmediaplayer_->TimeChanged();
+}
+
+void WebMediaPlayerImpl::Proxy::NetworkStateChangedTask(
+ WebKit::WebMediaPlayer::NetworkState state) {
+ DCHECK(MessageLoop::current() == render_loop_);
+ if (webmediaplayer_)
+ webmediaplayer_->SetNetworkState(state);
+}
+
+void WebMediaPlayerImpl::Proxy::ReadyStateChangedTask(
+ WebKit::WebMediaPlayer::ReadyState state) {
+ DCHECK(MessageLoop::current() == render_loop_);
+ if (webmediaplayer_)
+ webmediaplayer_->SetReadyState(state);
+}
+
+void WebMediaPlayerImpl::Proxy::SetVideoRenderer(
+ VideoRendererImpl* video_renderer) {
+ video_renderer_ = video_renderer;
+}
+
+void WebMediaPlayerImpl::Proxy::Paint(skia::PlatformCanvas* canvas,
+ const gfx::Rect& dest_rect) {
+ DCHECK(MessageLoop::current() == render_loop_);
+ if (video_renderer_) {
+ video_renderer_->Paint(canvas, dest_rect);
}
+}
- virtual void Cancel() {
- media_player_ = NULL;
+void WebMediaPlayerImpl::Proxy::SetSize(const gfx::Rect& rect) {
+ DCHECK(MessageLoop::current() == render_loop_);
+ if (video_renderer_) {
+ video_renderer_->SetRect(rect);
}
+}
+
+void WebMediaPlayerImpl::Proxy::Detach() {
+ DCHECK(MessageLoop::current() == render_loop_);
+ webmediaplayer_ = NULL;
+ video_renderer_ = NULL;
+}
- private:
- WebMediaPlayerImpl* media_player_;
- WebMediaPlayerClientMethod method_;
+void WebMediaPlayerImpl::Proxy::PipelineInitializationCallback(bool success) {
+ if (success) {
+ // Since we have initialized the pipeline, say we have everything.
+ // TODO(hclam): change this to report the correct status. Should also post
+ // a task to call to |webmediaplayer_|.
+ ReadyStateChanged(WebKit::WebMediaPlayer::HaveMetadata);
+ ReadyStateChanged(WebKit::WebMediaPlayer::HaveEnoughData);
+ NetworkStateChanged(WebKit::WebMediaPlayer::Loaded);
+ } else {
+ // TODO(hclam): should use pipeline_.GetError() to determine the state
+ // properly and reports error using MediaError.
+ // WebKit uses FormatError to indicate an error for bogus URL or bad file.
+ // Since we are at the initialization stage we can safely treat every error
+ // as format error. Should post a task to call to |webmediaplayer_|.
+ NetworkStateChanged(WebKit::WebMediaPlayer::FormatError);
+ }
+}
- DISALLOW_COPY_AND_ASSIGN(NotifyWebMediaPlayerClientTask);
-};
+void WebMediaPlayerImpl::Proxy::PipelineSeekCallback(bool success) {
+ if (success)
+ TimeChanged();
+}
/////////////////////////////////////////////////////////////////////////////
// WebMediaPlayerImpl implementation
@@ -57,31 +166,27 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(WebKit::WebMediaPlayerClient* client,
ready_state_(WebKit::WebMediaPlayer::HaveNothing),
main_loop_(NULL),
filter_factory_(factory),
- video_renderer_(NULL),
- client_(client),
- tasks_(kLastTaskIndex) {
- // Add in the default filter factories.
- filter_factory_->AddFactory(media::FFmpegDemuxer::CreateFilterFactory());
- filter_factory_->AddFactory(media::FFmpegAudioDecoder::CreateFactory());
- filter_factory_->AddFactory(media::FFmpegVideoDecoder::CreateFactory());
- filter_factory_->AddFactory(media::NullAudioRenderer::CreateFilterFactory());
- filter_factory_->AddFactory(VideoRendererImpl::CreateFactory(this));
-
- DCHECK(client_);
-
+ client_(client) {
// 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);
+
+ // Creates the proxy.
+ proxy_ = new Proxy(main_loop_, this);
+
+ // Add in the default filter factories.
+ filter_factory_->AddFactory(media::FFmpegDemuxer::CreateFilterFactory());
+ filter_factory_->AddFactory(media::FFmpegAudioDecoder::CreateFactory());
+ filter_factory_->AddFactory(media::FFmpegVideoDecoder::CreateFactory());
+ filter_factory_->AddFactory(media::NullAudioRenderer::CreateFilterFactory());
+ filter_factory_->AddFactory(VideoRendererImpl::CreateFactory(proxy_));
}
WebMediaPlayerImpl::~WebMediaPlayerImpl() {
- pipeline_.Stop();
-
- // Cancel all tasks posted on the |main_loop_|.
- CancelAllTasks();
+ Destroy();
// Finally tell the |main_loop_| we don't want to be notified of destruction
// event.
@@ -91,29 +196,25 @@ WebMediaPlayerImpl::~WebMediaPlayerImpl() {
}
void WebMediaPlayerImpl::load(const WebKit::WebURL& url) {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
+ DCHECK(proxy_);
// Initialize the pipeline.
- if (network_state_ != WebKit::WebMediaPlayer::Loading) {
- network_state_ = WebKit::WebMediaPlayer::Loading;
- client_->networkStateChanged();
- }
- if (ready_state_ != WebKit::WebMediaPlayer::HaveNothing) {
- ready_state_ = WebKit::WebMediaPlayer::HaveNothing;
- client_->readyStateChanged();
- }
- pipeline_.Start(filter_factory_.get(), url.spec(),
- NewCallback(this, &WebMediaPlayerImpl::OnPipelineInitialize));
+ SetNetworkState(WebKit::WebMediaPlayer::Loading);
+ SetReadyState(WebKit::WebMediaPlayer::HaveNothing);
+ pipeline_.Start(
+ filter_factory_.get(),
+ url.spec(),
+ NewCallback(proxy_.get(),
+ &WebMediaPlayerImpl::Proxy::PipelineInitializationCallback));
}
void WebMediaPlayerImpl::cancelLoad() {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
-
- // TODO(hclam): Calls to render_view_ to stop resource load
+ DCHECK(MessageLoop::current() == main_loop_);
}
void WebMediaPlayerImpl::play() {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
// TODO(hclam): We should restore the previous playback rate rather than
// having it at 1.0.
@@ -121,69 +222,63 @@ void WebMediaPlayerImpl::play() {
}
void WebMediaPlayerImpl::pause() {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
pipeline_.SetPlaybackRate(0.0f);
}
-void WebMediaPlayerImpl::stop() {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
-
- // We can fire Stop() multiple times.
- pipeline_.Stop();
-}
-
void WebMediaPlayerImpl::seek(float seconds) {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
// Try to preserve as much accuracy as possible.
float microseconds = seconds * base::Time::kMicrosecondsPerSecond;
if (seconds != 0)
pipeline_.Seek(
base::TimeDelta::FromMicroseconds(static_cast<int64>(microseconds)),
- NewCallback(this, &WebMediaPlayerImpl::OnPipelineSeek));
+ NewCallback(proxy_.get(),
+ &WebMediaPlayerImpl::Proxy::PipelineSeekCallback));
}
void WebMediaPlayerImpl::setEndTime(float seconds) {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
// TODO(hclam): add method call when it has been implemented.
return;
}
void WebMediaPlayerImpl::setRate(float rate) {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
pipeline_.SetPlaybackRate(rate);
}
void WebMediaPlayerImpl::setVolume(float volume) {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
pipeline_.SetVolume(volume);
}
void WebMediaPlayerImpl::setVisible(bool visible) {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
// TODO(hclam): add appropriate method call when pipeline has it implemented.
return;
}
bool WebMediaPlayerImpl::setAutoBuffer(bool autoBuffer) {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
return false;
}
bool WebMediaPlayerImpl::totalBytesKnown() {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
return pipeline_.GetTotalBytes() != 0;
}
bool WebMediaPlayerImpl::hasVideo() const {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
size_t width, height;
pipeline_.GetVideoSize(&width, &height);
@@ -191,7 +286,7 @@ bool WebMediaPlayerImpl::hasVideo() const {
}
WebKit::WebSize WebMediaPlayerImpl::naturalSize() const {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
size_t width, height;
pipeline_.GetVideoSize(&width, &height);
@@ -199,44 +294,44 @@ WebKit::WebSize WebMediaPlayerImpl::naturalSize() const {
}
bool WebMediaPlayerImpl::paused() const {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
return pipeline_.GetPlaybackRate() == 0.0f;
}
bool WebMediaPlayerImpl::seeking() const {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
- return tasks_[kTimeChangedTaskIndex] != NULL;
+ return false;
}
float WebMediaPlayerImpl::duration() const {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
return static_cast<float>(pipeline_.GetDuration().InSecondsF());
}
float WebMediaPlayerImpl::currentTime() const {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
return static_cast<float>(pipeline_.GetTime().InSecondsF());
}
int WebMediaPlayerImpl::dataRate() const {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
// TODO(hclam): Add this method call if pipeline has it in the interface.
return 0;
}
float WebMediaPlayerImpl::maxTimeBuffered() const {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
return static_cast<float>(pipeline_.GetBufferedTime().InSecondsF());
}
float WebMediaPlayerImpl::maxTimeSeekable() const {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
// TODO(scherkus): move this logic down into the pipeline.
if (pipeline_.GetTotalBytes() == 0) {
@@ -249,110 +344,85 @@ float WebMediaPlayerImpl::maxTimeSeekable() const {
}
unsigned long long WebMediaPlayerImpl::bytesLoaded() const {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
return pipeline_.GetBufferedBytes();
}
unsigned long long WebMediaPlayerImpl::totalBytes() const {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
return pipeline_.GetTotalBytes();
}
void WebMediaPlayerImpl::setSize(const WebSize& size) {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
+ DCHECK(proxy_);
- if (video_renderer_) {
- // TODO(scherkus): Change API to use SetSize().
- video_renderer_->SetRect(gfx::Rect(0, 0, size.width, size.height));
- }
+ proxy_->SetSize(gfx::Rect(0, 0, size.width, size.height));
}
void WebMediaPlayerImpl::paint(WebCanvas* canvas,
const WebRect& rect) {
- DCHECK(main_loop_ && MessageLoop::current() == main_loop_);
+ DCHECK(MessageLoop::current() == main_loop_);
+ DCHECK(proxy_);
- if (video_renderer_) {
- video_renderer_->Paint(canvas, rect);
- }
+ proxy_->Paint(canvas, rect);
}
void WebMediaPlayerImpl::WillDestroyCurrentMessageLoop() {
- pipeline_.Stop();
+ Destroy();
+ main_loop_ = NULL;
}
-void WebMediaPlayerImpl::OnPipelineInitialize(bool successful) {
- WebKit::WebMediaPlayer::ReadyState old_ready_state = ready_state_;
- WebKit::WebMediaPlayer::NetworkState old_network_state = network_state_;
- if (successful) {
- // Since we have initialized the pipeline, say we have everything.
- // TODO(hclam): change this to report the correct status.
- ready_state_ = WebKit::WebMediaPlayer::HaveEnoughData;
- network_state_ = WebKit::WebMediaPlayer::Loaded;
- } else {
- // TODO(hclam): should use pipeline_.GetError() to determine the state
- // properly and reports error using MediaError.
- // WebKit uses FormatError to indicate an error for bogus URL or bad file.
- // Since we are at the initialization stage we can safely treat every error
- // as format error.
- network_state_ = WebKit::WebMediaPlayer::FormatError;
- }
-
- if (network_state_ != old_network_state) {
- PostTask(kNetworkStateTaskIndex,
- &WebKit::WebMediaPlayerClient::networkStateChanged);
- }
- if (ready_state_ != old_ready_state) {
- PostTask(kReadyStateTaskIndex,
- &WebKit::WebMediaPlayerClient::readyStateChanged);
- }
+void WebMediaPlayerImpl::Repaint() {
+ DCHECK(MessageLoop::current() == main_loop_);
+ GetClient()->repaint();
}
-void WebMediaPlayerImpl::OnPipelineSeek(bool successful) {
- PostTask(kTimeChangedTaskIndex,
- &WebKit::WebMediaPlayerClient::timeChanged);
+void WebMediaPlayerImpl::TimeChanged() {
+ DCHECK(MessageLoop::current() == main_loop_);
+ GetClient()->timeChanged();
}
-void WebMediaPlayerImpl::SetVideoRenderer(VideoRendererImpl* video_renderer) {
- video_renderer_ = video_renderer;
-}
-
-void WebMediaPlayerImpl::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;
- }
+void WebMediaPlayerImpl::SetNetworkState(
+ WebKit::WebMediaPlayer::NetworkState state) {
+ DCHECK(MessageLoop::current() == main_loop_);
+ if (network_state_ != state) {
+ network_state_ = state;
+ GetClient()->networkStateChanged();
}
- NOTREACHED();
}
-void WebMediaPlayerImpl::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 WebMediaPlayerImpl::SetReadyState(
+ WebKit::WebMediaPlayer::ReadyState state) {
+ DCHECK(MessageLoop::current() == main_loop_);
+ if (ready_state_ != state) {
+ ready_state_ = state;
+ GetClient()->readyStateChanged();
}
}
-void WebMediaPlayerImpl::PostTask(int index,
- WebMediaPlayerClientMethod method) {
- DCHECK(main_loop_);
+void WebMediaPlayerImpl::Destroy() {
+ DCHECK(MessageLoop::current() == main_loop_);
- AutoLock auto_lock(task_lock_);
- if (!tasks_[index]) {
- CancelableTask* task = new NotifyWebMediaPlayerClientTask(this, method);
- tasks_[index] = task;
- main_loop_->PostTask(FROM_HERE, task);
+ // Make sure to kill the pipeline so there's no more media threads running.
+ // TODO(hclam): stopping the pipeline is synchronous so it might block
+ // stopping for a long time.
+ pipeline_.Stop();
+
+ // And then detach the proxy, it may live on the render thread for a little
+ // longer until all the tasks are finished.
+ if (proxy_) {
+ proxy_->Detach();
+ proxy_ = NULL;
}
}
-void WebMediaPlayerImpl::PostRepaintTask() {
- PostTask(kRepaintTaskIndex, &WebKit::WebMediaPlayerClient::repaint);
+WebKit::WebMediaPlayerClient* WebMediaPlayerImpl::GetClient() {
+ DCHECK(MessageLoop::current() == main_loop_);
+ DCHECK(client_);
+ return client_;
}
} // namespace webkit_glue
diff --git a/webkit/glue/webmediaplayer_impl.h b/webkit/glue/webmediaplayer_impl.h
index d8a365c..604188c 100644
--- a/webkit/glue/webmediaplayer_impl.h
+++ b/webkit/glue/webmediaplayer_impl.h
@@ -9,28 +9,38 @@
// 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.
+// WebMediaPlayerImpl works with multiple objects, the most important ones are:
//
-// Methods that are accessed in media threads:
-// SetAudioRenderer()
-// ^--- Called during the initialization of the pipeline, essentially from the
-// the pipeline thread.
-// 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_|.
+// media::PipelineImpl
+// The media playback pipeline.
//
+// VideoRendererImpl
+// Video renderer object.
+//
+// WebMediaPlayerImpl::Proxy
+// Proxies methods calls from the media pipeline to WebKit.
+//
+// WebKit::WebMediaPlayerClient
+// WebKit client of this media player object.
+//
+// The following diagram shows the relationship of these objects:
+// (note: ref-counted reference is marked by a "r".)
+//
+// WebMediaPlayerImpl ------> PipelineImpl
+// | ^ | r
+// | | v
+// | | VideoRendererImpl
+// | | ^ r
+// | | |
+// | r | r |
+// .------> Proxy <-----.
+// |
+// |
+// v
+// WebMediaPlayerClient
+//
+// Notice that Proxy and VideoRendererImpl are referencing each other. This
+// interdependency has to be treated carefully.
//
// Other issues:
// During tear down of the whole browser or a tab, the DOM tree may not be
@@ -41,23 +51,22 @@
// list of the main thread.
#ifndef WEBKIT_GLUE_WEBMEDIAPLAYER_IMPL_H_
-#define WEBKTI_GLUE_WEBMEDIAPLAYER_IMPL_H_
+#define WEBKIT_GLUE_WEBMEDIAPLAYER_IMPL_H_
#include <vector>
#include "base/gfx/platform_canvas.h"
+#include "base/gfx/rect.h"
+#include "base/gfx/size.h"
#include "base/lock.h"
#include "base/message_loop.h"
+#include "base/ref_counted.h"
#include "media/base/filters.h"
#include "media/base/pipeline_impl.h"
#include "webkit/api/public/WebMediaPlayer.h"
#include "webkit/api/public/WebMediaPlayerClient.h"
-class AudioRendererImpl;
-class DataSourceImpl;
class GURL;
-class RenderView;
-class VideoRendererImpl;
namespace media {
class FilterFactoryCollection;
@@ -65,13 +74,75 @@ class FilterFactoryCollection;
namespace webkit_glue {
-// This typedef is used for WebMediaPlayerImpl::PostTask() and
-// NotifyWebMediaPlayerTask in the source file.
-typedef void (WebKit::WebMediaPlayerClient::*WebMediaPlayerClientMethod)();
+class VideoRendererImpl;
class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
public MessageLoop::DestructionObserver {
public:
+ // A proxy class that dispatches method calls from the media pipeline to
+ // WebKit. Since there are multiple threads in the media pipeline and there's
+ // need for the media pipeline to call to WebKit, e.g. repaint requests,
+ // initialization events, etc, we have this class to bridge all method calls
+ // from the media pipeline on different threads and serialize these calls
+ // on the render thread.
+ // Because of the nature of this object that it works with different threads,
+ // it is made ref-counted.
+ class Proxy : public base::RefCountedThreadSafe<Proxy> {
+ public:
+ Proxy(MessageLoop* render_loop,
+ WebMediaPlayerImpl* webmediaplayer);
+ virtual ~Proxy();
+
+ // Fire a repaint event to WebKit.
+ void Repaint();
+
+ // Report to WebKit that time has changed.
+ void TimeChanged();
+
+ // Report to WebKit that network state has changed.
+ void NetworkStateChanged(WebKit::WebMediaPlayer::NetworkState state);
+
+ // Report the WebKit that ready state has changed.
+ void ReadyStateChanged(WebKit::WebMediaPlayer::ReadyState state);
+
+ // Public methods to be called from video renderer.
+ void SetVideoRenderer(VideoRendererImpl* video_renderer);
+
+ private:
+ friend class WebMediaPlayerImpl;
+
+ // Invoke |webmediaplayer_| to perform a repaint.
+ void RepaintTask();
+
+ // Invoke |webmediaplayer_| to notify a time change event.
+ void TimeChangedTask();
+
+ // Saves the internal network state and notify WebKit to pick up the change.
+ void NetworkStateChangedTask(WebKit::WebMediaPlayer::NetworkState state);
+
+ // Saves the internal ready state and notify WebKit to pick the change.
+ void ReadyStateChangedTask(WebKit::WebMediaPlayer::ReadyState state);
+
+ void Paint(skia::PlatformCanvas* canvas, const gfx::Rect& dest_rect);
+
+ void SetSize(const gfx::Rect& rect);
+
+ // Detach from |webmediaplayer_|.
+ void Detach();
+
+ void PipelineInitializationCallback(bool success);
+
+ void PipelineSeekCallback(bool success);
+
+ // The render message loop where WebKit lives.
+ MessageLoop* render_loop_;
+ WebMediaPlayerImpl* webmediaplayer_;
+ scoped_refptr<VideoRendererImpl> video_renderer_;
+
+ Lock lock_;
+ int outstanding_repaints_;
+ };
+
// Construct a WebMediaPlayerImpl with reference to the client, and media
// filter factory collection. By providing the filter factory collection
// the implementor can provide more specific media filters that does resource
@@ -102,7 +173,6 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
// Playback controls.
virtual void play();
virtual void pause();
- virtual void stop();
virtual void seek(float seconds);
virtual void setEndTime(float seconds);
virtual void setRate(float rate);
@@ -152,42 +222,20 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
// to it.
virtual void WillDestroyCurrentMessageLoop();
- // Notification from |pipeline_| when initialization has finished.
- void OnPipelineInitialize(bool successful);
-
- // Notification from |pipeline_| when a seek has finished.
- void OnPipelineSeek(bool successful);
-
- // Called from tasks posted to |main_loop_| from this object to remove
- // reference of them.
- void DidTask(CancelableTask* task);
+ void Repaint();
- // Public methods to be called from renderers and data source so that
- // WebMediaPlayerImpl has references to them.
- void SetVideoRenderer(VideoRendererImpl* video_renderer);
+ void TimeChanged();
- // Called from VideoRenderer to fire a repaint task to |main_loop_|.
- void PostRepaintTask();
+ void SetNetworkState(WebKit::WebMediaPlayer::NetworkState state);
- // Inline getters.
- WebKit::WebMediaPlayerClient* client() { return client_; }
+ void SetReadyState(WebKit::WebMediaPlayer::ReadyState state);
private:
- // Methods for posting tasks and cancelling tasks. This method may lives in
- // the main thread or the media threads.
- void PostTask(int index, WebMediaPlayerClientMethod method);
-
- // Cancel all tasks currently live in |main_loop_|.
- void CancelAllTasks();
-
- // Indexes for tasks.
- enum {
- kRepaintTaskIndex = 0,
- kReadyStateTaskIndex,
- kNetworkStateTaskIndex,
- kTimeChangedTaskIndex,
- kLastTaskIndex
- };
+ // Destroy resources held.
+ void Destroy();
+
+ // Getter method to |client_|.
+ WebKit::WebMediaPlayerClient* GetClient();
// TODO(hclam): get rid of these members and read from the pipeline directly.
WebKit::WebMediaPlayer::NetworkState network_state_;
@@ -204,18 +252,9 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer,
// the same lifetime as the pipeline.
media::PipelineImpl pipeline_;
- // We have the interface to VideoRenderer to delegate paint messages to it
- // from WebKit.
- scoped_refptr<VideoRendererImpl> video_renderer_;
-
WebKit::WebMediaPlayerClient* client_;
- // 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_;
+ scoped_refptr<Proxy> proxy_;
DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl);
};