summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-25 01:28:39 +0000
committerwjia@chromium.org <wjia@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-25 01:28:39 +0000
commit5f04c353a604c8e3f654019c9c267529455a8fbf (patch)
treee56168cdbb4df164d4d0dd9677b94835be9bb403
parenta380186d005aaa91bf62dbefca4f6fd17329afba (diff)
downloadchromium_src-5f04c353a604c8e3f654019c9c267529455a8fbf.zip
chromium_src-5f04c353a604c8e3f654019c9c267529455a8fbf.tar.gz
chromium_src-5f04c353a604c8e3f654019c9c267529455a8fbf.tar.bz2
create a separate WebMediaPlayer for URL derived from media stream
When the "src" of <video> is derived from media stream, WebMediaPlayerMS is created. Its real time charateristics allows it to simplify some controls in WebMediaPlayer, e.g., no buffering, no preload, etc. WebMediaPlayerMS has 2 different VideoFrameProviders: LocalVideoCapture(for local preview) and RTCVideoRender(for remote view). Audio will be added in the following patches. BUG=142988,110938 TEST=turn on WebMediaPlayer_MS, run apprtc.appspot.com/?debug=loopback Review URL: https://chromiumcodereview.appspot.com/10918052 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@158490 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc1
-rw-r--r--content/content_renderer.gypi4
-rw-r--r--content/public/common/content_switches.cc4
-rw-r--r--content/public/common/content_switches.h1
-rw-r--r--content/renderer/media/local_video_capture.cc153
-rw-r--r--content/renderer/media/local_video_capture.h79
-rw-r--r--content/renderer/media/media_stream_impl.cc92
-rw-r--r--content/renderer/media/media_stream_impl.h15
-rw-r--r--content/renderer/media/rtc_video_renderer.cc107
-rw-r--r--content/renderer/media/rtc_video_renderer.h73
-rw-r--r--content/renderer/render_view_impl.cc14
-rw-r--r--media/video/capture/video_capture.h1
-rw-r--r--webkit/media/media_stream_client.h10
-rw-r--r--webkit/media/simple_video_frame_provider.cc85
-rw-r--r--webkit/media/simple_video_frame_provider.h60
-rw-r--r--webkit/media/video_frame_provider.cc13
-rw-r--r--webkit/media/video_frame_provider.h50
-rw-r--r--webkit/media/webkit_media.gypi6
-rw-r--r--webkit/media/webmediaplayer_ms.cc398
-rw-r--r--webkit/media/webmediaplayer_ms.h170
-rw-r--r--webkit/support/test_media_stream_client.cc25
-rw-r--r--webkit/support/test_media_stream_client.h21
-rw-r--r--webkit/support/webkit_support.cc11
23 files changed, 1377 insertions, 16 deletions
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index c49779b..2a8648f 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -802,6 +802,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kEnableGpuBenchmarking,
switches::kEnableLogging,
switches::kDisableMediaSource,
+ switches::kEnableWebMediaPlayerMS,
switches::kEnablePartialSwap,
switches::kEnablePerTilePainting,
switches::kEnableRendererSideMixing,
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index f41d930..6e09766 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -119,6 +119,8 @@
'renderer/media/audio_renderer_mixer_manager.h',
'renderer/media/capture_video_decoder.cc',
'renderer/media/capture_video_decoder.h',
+ 'renderer/media/local_video_capture.cc',
+ 'renderer/media/local_video_capture.h',
'renderer/media/media_stream_center.h',
'renderer/media/media_stream_dependency_factory.h',
'renderer/media/media_stream_dispatcher.h',
@@ -136,6 +138,8 @@
'renderer/media/renderer_webaudiodevice_impl.h',
'renderer/media/rtc_video_decoder.cc',
'renderer/media/rtc_video_decoder.h',
+ 'renderer/media/rtc_video_renderer.cc',
+ 'renderer/media/rtc_video_renderer.h',
'renderer/media/stream_texture_factory_impl_android.cc',
'renderer/media/stream_texture_factory_impl_android.h',
'renderer/media/video_capture_impl.cc',
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index f10405c..fc63c93 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -293,6 +293,10 @@ const char kEnableLogging[] = "enable-logging";
// Disable Media Source API on <audio>/<video> elements.
const char kDisableMediaSource[] = "disable-media-source";
+// Enables using WebMediaPlayerMS for src of <audio>/<video> derived from
+// media stream.
+const char kEnableWebMediaPlayerMS[] = "enable-web-media-player-ms";
+
// On Windows, converts the page to the currently-installed monitor profile.
// This does NOT enable color management for images. The source is still
// assumed to be sRGB.
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index b247e42..80f9123 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -104,6 +104,7 @@ extern const char kEnableGestureTapHighlight[];
extern const char kEnableGpuBenchmarking[];
CONTENT_EXPORT extern const char kEnableLogging[];
extern const char kDisableMediaSource[];
+extern const char kEnableWebMediaPlayerMS[];
extern const char kEnableMonitorProfile[];
extern const char kEnablePartialSwap[];
extern const char kEnableUIReleaseFrontSurface[];
diff --git a/content/renderer/media/local_video_capture.cc b/content/renderer/media/local_video_capture.cc
new file mode 100644
index 0000000..f9dd216
--- /dev/null
+++ b/content/renderer/media/local_video_capture.cc
@@ -0,0 +1,153 @@
+// Copyright (c) 2012 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.
+
+#include "content/renderer/media/local_video_capture.h"
+
+#include "content/renderer/media/video_capture_impl_manager.h"
+#include "media/base/video_util.h"
+#include "media/video/capture/video_capture_proxy.h"
+
+using media::CopyYPlane;
+using media::CopyUPlane;
+using media::CopyVPlane;
+
+namespace content {
+
+LocalVideoCapture::LocalVideoCapture(
+ media::VideoCaptureSessionId video_stream_id,
+ VideoCaptureImplManager* vc_manager,
+ const media::VideoCaptureCapability& capability,
+ const base::Closure& error_cb,
+ const RepaintCB& repaint_cb)
+ : video_stream_id_(video_stream_id),
+ vc_manager_(vc_manager),
+ capability_(capability),
+ error_cb_(error_cb),
+ repaint_cb_(repaint_cb),
+ capture_engine_(NULL),
+ message_loop_proxy_(base::MessageLoopProxy::current()),
+ ALLOW_THIS_IN_INITIALIZER_LIST(
+ handler_proxy_(new media::VideoCaptureHandlerProxy(
+ this, message_loop_proxy_))),
+ state_(video_capture::kStopped) {
+ DVLOG(3) << "LocalVideoCapture::ctor";
+ DCHECK(vc_manager);
+}
+
+LocalVideoCapture::~LocalVideoCapture() {
+ DVLOG(3) << "LocalVideoCapture::dtor";
+}
+
+void LocalVideoCapture::Start() {
+ DVLOG(3) << "LocalVideoCapture::Start";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK_EQ(state_, video_capture::kStopped);
+
+ capture_engine_ = vc_manager_->AddDevice(video_stream_id_, this);
+ state_ = video_capture::kStarted;
+ AddRef(); // Will be balanced in OnRemoved().
+ capture_engine_->StartCapture(handler_proxy_.get(), capability_);
+}
+
+void LocalVideoCapture::Stop() {
+ DVLOG(3) << "LocalVideoCapture::Stop";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ if (capture_engine_) {
+ state_ = video_capture::kStopping;
+ capture_engine_->StopCapture(handler_proxy_.get());
+ capture_engine_ = NULL;
+ }
+}
+
+void LocalVideoCapture::Play() {
+ DVLOG(3) << "LocalVideoCapture::Play";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ if (capture_engine_ && state_ == video_capture::kPaused) {
+ state_ = video_capture::kStarted;
+ }
+}
+
+void LocalVideoCapture::Pause() {
+ DVLOG(3) << "LocalVideoCapture::Pause";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ if (capture_engine_ && state_ == video_capture::kStarted) {
+ state_ = video_capture::kPaused;
+ }
+}
+
+void LocalVideoCapture::OnStarted(media::VideoCapture* capture) {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ NOTIMPLEMENTED();
+}
+
+void LocalVideoCapture::OnStopped(media::VideoCapture* capture) {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ NOTIMPLEMENTED();
+}
+
+void LocalVideoCapture::OnPaused(media::VideoCapture* capture) {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ NOTIMPLEMENTED();
+}
+
+void LocalVideoCapture::OnError(media::VideoCapture* capture,
+ int error_code) {
+ DVLOG(3) << "LocalVideoCapture::OnError, " << error_code;
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ error_cb_.Run();
+}
+
+void LocalVideoCapture::OnRemoved(media::VideoCapture* capture) {
+ DVLOG(3) << "LocalVideoCapture::OnRemoved";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ vc_manager_->RemoveDevice(video_stream_id_, this);
+ Release(); // Balance the AddRef() in StartCapture().
+}
+
+void LocalVideoCapture::OnDeviceInfoReceived(
+ media::VideoCapture* capture,
+ const media::VideoCaptureParams& device_info) {
+ DVLOG(3) << "LocalVideoCapture::OnDeviceInfoReceived";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+}
+
+void LocalVideoCapture::OnBufferReady(
+ media::VideoCapture* capture,
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) {
+ DVLOG(3) << "LocalVideoCapture::OnBufferReady, state:" << state_;
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK(buf);
+
+ if (state_ != video_capture::kStarted) {
+ capture->FeedBuffer(buf);
+ return;
+ }
+
+ gfx::Size natural_size(buf->width, buf->height);
+ scoped_refptr<media::VideoFrame> current_frame =
+ media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
+ natural_size, natural_size,
+ buf->timestamp - base::Time());
+ uint8* buffer = buf->memory_pointer;
+
+ // Assume YV12 format.
+ DCHECK_EQ(capability_.color, media::VideoCaptureCapability::kI420);
+ if (capability_.color != media::VideoCaptureCapability::kI420)
+ return;
+
+ int y_width = buf->width;
+ int y_height = buf->height;
+ int uv_width = buf->width / 2;
+ int uv_height = buf->height / 2;
+ CopyYPlane(buffer, y_width, y_height, current_frame);
+ buffer += y_width * y_height;
+ CopyUPlane(buffer, uv_width, uv_height, current_frame);
+ buffer += uv_width * uv_height;
+ CopyVPlane(buffer, uv_width, uv_height, current_frame);
+
+ capture->FeedBuffer(buf);
+ repaint_cb_.Run(current_frame);
+}
+
+} // namespace content
diff --git a/content/renderer/media/local_video_capture.h b/content/renderer/media/local_video_capture.h
new file mode 100644
index 0000000..bbf67dc
--- /dev/null
+++ b/content/renderer/media/local_video_capture.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2012 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.
+
+#ifndef CONTENT_RENDERER_MEDIA_LOCAL_VIDEO_CAPTURE_H_
+#define CONTENT_RENDERER_MEDIA_LOCAL_VIDEO_CAPTURE_H_
+
+#include "content/common/content_export.h"
+#include "content/common/media/video_capture.h"
+#include "media/video/capture/video_capture.h"
+#include "webkit/media/video_frame_provider.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace media {
+class VideoCaptureHandlerProxy;
+}
+
+class VideoCaptureImplManager;
+
+namespace content {
+
+// This class takes raw frames from video capture engine via VideoCaptureProxy
+// and passes them to media player as a video frame provider.
+// This class lives on main thread.
+class CONTENT_EXPORT LocalVideoCapture
+ : NON_EXPORTED_BASE(public webkit_media::VideoFrameProvider),
+ public media::VideoCapture::EventHandler {
+ public:
+ LocalVideoCapture(
+ media::VideoCaptureSessionId video_stream_id,
+ VideoCaptureImplManager* vc_manager,
+ const media::VideoCaptureCapability& capability,
+ const base::Closure& error_cb,
+ const RepaintCB& repaint_cb);
+
+ // webkit_media::VideoFrameProvider implementation.
+ virtual void Start() OVERRIDE;
+ virtual void Stop() OVERRIDE;
+ virtual void Play() OVERRIDE;
+ virtual void Pause() OVERRIDE;
+
+ // VideoCapture::EventHandler implementation.
+ virtual void OnStarted(media::VideoCapture* capture) OVERRIDE;
+ virtual void OnStopped(media::VideoCapture* capture) OVERRIDE;
+ virtual void OnPaused(media::VideoCapture* capture) OVERRIDE;
+ virtual void OnError(media::VideoCapture* capture, int error_code) OVERRIDE;
+ virtual void OnRemoved(media::VideoCapture* capture) OVERRIDE;
+ virtual void OnBufferReady(
+ media::VideoCapture* capture,
+ scoped_refptr<media::VideoCapture::VideoFrameBuffer> buf) OVERRIDE;
+ virtual void OnDeviceInfoReceived(
+ media::VideoCapture* capture,
+ const media::VideoCaptureParams& device_info) OVERRIDE;
+
+ protected:
+ virtual ~LocalVideoCapture();
+
+ private:
+ friend class LocalVideoCaptureTest;
+
+ media::VideoCaptureSessionId video_stream_id_;
+ scoped_refptr<VideoCaptureImplManager> vc_manager_;
+ media::VideoCaptureCapability capability_;
+ base::Closure error_cb_;
+ RepaintCB repaint_cb_;
+ media::VideoCapture* capture_engine_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ scoped_ptr<media::VideoCaptureHandlerProxy> handler_proxy_;
+ video_capture::State state_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocalVideoCapture);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MEDIA_LOCAL_VIDEO_CAPTURE_H_
diff --git a/content/renderer/media/media_stream_impl.cc b/content/renderer/media/media_stream_impl.cc
index 8a7180a..648fe2a 100644
--- a/content/renderer/media/media_stream_impl.cc
+++ b/content/renderer/media/media_stream_impl.cc
@@ -11,11 +11,13 @@
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "content/renderer/media/capture_video_decoder.h"
+#include "content/renderer/media/local_video_capture.h"
#include "content/renderer/media/media_stream_extra_data.h"
#include "content/renderer/media/media_stream_source_extra_data.h"
#include "content/renderer/media/media_stream_dependency_factory.h"
#include "content/renderer/media/media_stream_dispatcher.h"
#include "content/renderer/media/rtc_video_decoder.h"
+#include "content/renderer/media/rtc_video_renderer.h"
#include "content/renderer/media/video_capture_impl_manager.h"
#include "content/renderer/media/webrtc_uma_histograms.h"
#include "media/base/message_loop_factory.h"
@@ -143,6 +145,50 @@ WebKit::WebMediaStreamDescriptor MediaStreamImpl::GetMediaStream(
return WebKit::WebMediaStreamRegistry::lookupMediaStreamDescriptor(url);
}
+bool MediaStreamImpl::IsMediaStream(const GURL& url) {
+ DCHECK(CalledOnValidThread());
+ WebKit::WebMediaStreamDescriptor descriptor(GetMediaStream(url));
+
+ if (descriptor.isNull() || !descriptor.extraData())
+ return false; // This is not a valid stream.
+
+ MediaStreamExtraData* extra_data =
+ static_cast<MediaStreamExtraData*>(descriptor.extraData());
+ webrtc::MediaStreamInterface* stream = extra_data->local_stream();
+ if (stream && stream->video_tracks() && stream->video_tracks()->count() > 0)
+ return true;
+ stream = extra_data->remote_stream();
+ if (stream && stream->video_tracks() && stream->video_tracks()->count() > 0)
+ return true;
+ return false;
+}
+
+scoped_refptr<webkit_media::VideoFrameProvider>
+MediaStreamImpl::GetVideoFrameProvider(
+ const GURL& url,
+ const base::Closure& error_cb,
+ const webkit_media::VideoFrameProvider::RepaintCB& repaint_cb) {
+ DCHECK(CalledOnValidThread());
+ WebKit::WebMediaStreamDescriptor descriptor(GetMediaStream(url));
+
+ if (descriptor.isNull() || !descriptor.extraData())
+ return NULL; // This is not a valid stream.
+
+ DVLOG(1) << "MediaStreamImpl::GetVideoFrameProvider stream:"
+ << UTF16ToUTF8(descriptor.label());
+
+ MediaStreamExtraData* extra_data =
+ static_cast<MediaStreamExtraData*>(descriptor.extraData());
+ if (extra_data->local_stream())
+ return CreateLocalVideoFrameProvider(extra_data->local_stream(),
+ error_cb, repaint_cb);
+ if (extra_data->remote_stream())
+ return CreateRemoteVideoFrameProvider(extra_data->remote_stream(),
+ error_cb, repaint_cb);
+ NOTREACHED();
+ return NULL;
+}
+
scoped_refptr<media::VideoDecoder> MediaStreamImpl::GetVideoDecoder(
const GURL& url,
media::MessageLoopFactory* message_loop_factory) {
@@ -307,6 +353,52 @@ void MediaStreamImpl::FrameWillClose(WebKit::WebFrame* frame) {
}
}
+scoped_refptr<webkit_media::VideoFrameProvider>
+MediaStreamImpl::CreateLocalVideoFrameProvider(
+ webrtc::MediaStreamInterface* stream,
+ const base::Closure& error_cb,
+ const webkit_media::VideoFrameProvider::RepaintCB& repaint_cb) {
+ if (!stream->video_tracks() || stream->video_tracks()->count() == 0)
+ return NULL;
+
+ int video_session_id =
+ media_stream_dispatcher_->video_session_id(stream->label(), 0);
+ media::VideoCaptureCapability capability;
+ capability.width = kVideoCaptureWidth;
+ capability.height = kVideoCaptureHeight;
+ capability.frame_rate = kVideoCaptureFramePerSecond;
+ capability.color = media::VideoCaptureCapability::kI420;
+ capability.expected_capture_delay = 0;
+ capability.interlaced = false;
+
+ DVLOG(1) << "MediaStreamImpl::CreateLocalVideoFrameProvider video_session_id:"
+ << video_session_id;
+
+ return new content::LocalVideoCapture(
+ video_session_id,
+ vc_manager_.get(),
+ capability,
+ error_cb,
+ repaint_cb);
+}
+
+scoped_refptr<webkit_media::VideoFrameProvider>
+MediaStreamImpl::CreateRemoteVideoFrameProvider(
+ webrtc::MediaStreamInterface* stream,
+ const base::Closure& error_cb,
+ const webkit_media::VideoFrameProvider::RepaintCB& repaint_cb) {
+ if (!stream->video_tracks() || stream->video_tracks()->count() == 0)
+ return NULL;
+
+ DVLOG(1) << "MediaStreamImpl::CreateRemoteVideoFrameProvider label:"
+ << stream->label();
+
+ return new content::RTCVideoRenderer(
+ stream->video_tracks()->at(0),
+ error_cb,
+ repaint_cb);
+}
+
scoped_refptr<media::VideoDecoder> MediaStreamImpl::CreateLocalVideoDecoder(
webrtc::MediaStreamInterface* stream,
media::MessageLoopFactory* message_loop_factory) {
diff --git a/content/renderer/media/media_stream_impl.h b/content/renderer/media/media_stream_impl.h
index 7279e37..1ffca32 100644
--- a/content/renderer/media/media_stream_impl.h
+++ b/content/renderer/media/media_stream_impl.h
@@ -61,6 +61,11 @@ class CONTENT_EXPORT MediaStreamImpl
const WebKit::WebUserMediaRequest& user_media_request) OVERRIDE;
// webkit_media::MediaStreamClient implementation.
+ virtual bool IsMediaStream(const GURL& url) OVERRIDE;
+ virtual scoped_refptr<webkit_media::VideoFrameProvider> GetVideoFrameProvider(
+ const GURL& url,
+ const base::Closure& error_cb,
+ const webkit_media::VideoFrameProvider::RepaintCB& repaint_cb) OVERRIDE;
virtual scoped_refptr<media::VideoDecoder> GetVideoDecoder(
const GURL& url,
media::MessageLoopFactory* message_loop_factory) OVERRIDE;
@@ -123,6 +128,16 @@ class CONTENT_EXPORT MediaStreamImpl
typedef std::map<std::string, WebKit::WebFrame*> LocalNativeStreamMap;
typedef scoped_refptr<webrtc::LocalMediaStreamInterface> LocalNativeStreamPtr;
+ scoped_refptr<webkit_media::VideoFrameProvider>
+ CreateLocalVideoFrameProvider(
+ webrtc::MediaStreamInterface* stream,
+ const base::Closure& error_cb,
+ const webkit_media::VideoFrameProvider::RepaintCB& repaint_cb);
+ scoped_refptr<webkit_media::VideoFrameProvider>
+ CreateRemoteVideoFrameProvider(
+ webrtc::MediaStreamInterface* stream,
+ const base::Closure& error_cb,
+ const webkit_media::VideoFrameProvider::RepaintCB& repaint_cb);
scoped_refptr<media::VideoDecoder> CreateLocalVideoDecoder(
webrtc::MediaStreamInterface* stream,
media::MessageLoopFactory* message_loop_factory);
diff --git a/content/renderer/media/rtc_video_renderer.cc b/content/renderer/media/rtc_video_renderer.cc
new file mode 100644
index 0000000..14444fa
--- /dev/null
+++ b/content/renderer/media/rtc_video_renderer.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2012 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.
+
+#include "content/renderer/media/rtc_video_renderer.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/message_loop_proxy.h"
+#include "media/base/video_frame.h"
+#include "media/base/video_util.h"
+#include "third_party/libjingle/source/talk/base/timeutils.h"
+#include "third_party/libjingle/source/talk/media/base/videoframe.h"
+
+using media::CopyYPlane;
+using media::CopyUPlane;
+using media::CopyVPlane;
+
+namespace content {
+
+RTCVideoRenderer::RTCVideoRenderer(
+ webrtc::VideoTrackInterface* video_track,
+ const base::Closure& error_cb,
+ const RepaintCB& repaint_cb)
+ : error_cb_(error_cb),
+ repaint_cb_(repaint_cb),
+ message_loop_proxy_(base::MessageLoopProxy::current()),
+ state_(kStopped),
+ video_track_(video_track) {
+}
+
+RTCVideoRenderer::~RTCVideoRenderer() {
+}
+
+void RTCVideoRenderer::Start() {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ DCHECK_EQ(state_, kStopped);
+
+ if (video_track_)
+ video_track_->AddRenderer(this);
+ state_ = kStarted;
+}
+
+void RTCVideoRenderer::Stop() {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ if (video_track_) {
+ state_ = kStopped;
+ video_track_->RemoveRenderer(this);
+ video_track_ = NULL;
+ }
+}
+
+void RTCVideoRenderer::Play() {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ if (video_track_ && state_ == kPaused) {
+ state_ = kStarted;
+ }
+}
+
+void RTCVideoRenderer::Pause() {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ if (video_track_ && state_ == kStarted) {
+ state_ = kPaused;
+ }
+}
+
+void RTCVideoRenderer::SetSize(int width, int height) {
+}
+
+void RTCVideoRenderer::RenderFrame(const cricket::VideoFrame* frame) {
+ base::TimeDelta timestamp = base::TimeDelta::FromMilliseconds(
+ frame->GetTimeStamp() / talk_base::kNumNanosecsPerMillisec);
+ gfx::Size size(frame->GetWidth(), frame->GetHeight());
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
+ size,
+ size,
+ timestamp);
+
+ // Aspect ratio unsupported; DCHECK when there are non-square pixels.
+ DCHECK_EQ(frame->GetPixelWidth(), 1u);
+ DCHECK_EQ(frame->GetPixelHeight(), 1u);
+
+ int y_rows = frame->GetHeight();
+ int uv_rows = frame->GetHeight() / 2; // YV12 format.
+ CopyYPlane(frame->GetYPlane(), frame->GetYPitch(), y_rows, video_frame);
+ CopyUPlane(frame->GetUPlane(), frame->GetUPitch(), uv_rows, video_frame);
+ CopyVPlane(frame->GetVPlane(), frame->GetVPitch(), uv_rows, video_frame);
+
+ message_loop_proxy_->PostTask(
+ FROM_HERE, base::Bind(&RTCVideoRenderer::DoRenderFrameOnMainThread,
+ this, video_frame));
+}
+
+void RTCVideoRenderer::DoRenderFrameOnMainThread(
+ scoped_refptr<media::VideoFrame> video_frame) {
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+
+ if (state_ != kStarted) {
+ return;
+ }
+
+ repaint_cb_.Run(video_frame);
+}
+
+} // namespace content
diff --git a/content/renderer/media/rtc_video_renderer.h b/content/renderer/media/rtc_video_renderer.h
new file mode 100644
index 0000000..925e70b
--- /dev/null
+++ b/content/renderer/media/rtc_video_renderer.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 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.
+
+#ifndef CONTENT_RENDERER_MEDIA_LOCAL_VIDEO_RENDERER_H_
+#define CONTENT_RENDERER_MEDIA_LOCAL_VIDEO_RENDERER_H_
+
+#include "base/callback.h"
+#include "content/common/content_export.h"
+#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
+#include "ui/gfx/size.h"
+#include "webkit/media/video_frame_provider.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace content {
+
+// RTCVideoRenderer is a webkit_media::VideoFrameProvider designed for rendering
+// Video MediaStreamTracks,
+// http://dev.w3.org/2011/webrtc/editor/getusermedia.html#mediastreamtrack
+// RTCVideoRenderer implements webrtc::VideoRendererInterface in order to render
+// video frames provided from a webrtc::VideoTrackInteface.
+// RTCVideoRenderer register itself to the Video Track when the
+// VideoFrameProvider is started and deregisters itself when it is stopped.
+// Calls to webrtc::VideoTrackInterface must occur on the main thread.
+class CONTENT_EXPORT RTCVideoRenderer
+ : NON_EXPORTED_BASE(public webkit_media::VideoFrameProvider),
+ NON_EXPORTED_BASE(public webrtc::VideoRendererInterface) {
+ public:
+ RTCVideoRenderer(
+ webrtc::VideoTrackInterface* video_track,
+ const base::Closure& error_cb,
+ const RepaintCB& repaint_cb);
+
+ // webkit_media::VideoFrameProvider implementation. Called on the main thread.
+ virtual void Start() OVERRIDE;
+ virtual void Stop() OVERRIDE;
+ virtual void Play() OVERRIDE;
+ virtual void Pause() OVERRIDE;
+
+ // webrtc::VideoRendererInterface implementation. May be called on
+ // a different thread.
+ virtual void SetSize(int width, int height) OVERRIDE;
+ virtual void RenderFrame(const cricket::VideoFrame* frame) OVERRIDE;
+
+ protected:
+ virtual ~RTCVideoRenderer();
+
+ private:
+ enum State {
+ kStarted,
+ kPaused,
+ kStopped,
+ };
+
+ void DoRenderFrameOnMainThread(scoped_refptr<media::VideoFrame> video_frame);
+
+ base::Closure error_cb_;
+ RepaintCB repaint_cb_;
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ State state_;
+
+ // The video track the renderer is connected to.
+ scoped_refptr<webrtc::VideoTrackInterface> video_track_;
+
+ DISALLOW_COPY_AND_ASSIGN(RTCVideoRenderer);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_MEDIA_LOCAL_VIDEO_RENDERER_H_
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index bf8ed52..37fa6f3 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -194,6 +194,7 @@
#include "webkit/glue/weburlresponse_extradata_impl.h"
#include "webkit/gpu/webgraphicscontext3d_in_process_impl.h"
#include "webkit/media/webmediaplayer_impl.h"
+#include "webkit/media/webmediaplayer_ms.h"
#include "webkit/plugins/npapi/plugin_list.h"
#include "webkit/plugins/npapi/webplugin_delegate.h"
#include "webkit/plugins/npapi/webplugin_delegate_impl.h"
@@ -2577,8 +2578,7 @@ WebMediaPlayer* RenderViewImpl::createMediaPlayer(
}
WebGraphicsContext3DCommandBufferImpl* context3d = NULL;
- if (!CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableAcceleratedVideoDecode))
+ if (!cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
context3d = RenderThreadImpl::current()->GetGpuVDAContext3D();
if (context3d) {
scoped_refptr<base::MessageLoopProxy> factories_loop =
@@ -2604,6 +2604,16 @@ WebMediaPlayer* RenderViewImpl::createMediaPlayer(
audio_source_provider, message_loop_factory, media_stream_impl_,
render_media_log);
if (!media_player) {
+ // TODO(wjia): when all patches related to WebMediaPlayerMS have been
+ // landed, remove the switch. Refer to crbug.com/142988.
+ if (cmd_line->HasSwitch(switches::kEnableWebMediaPlayerMS)) {
+ EnsureMediaStreamImpl();
+ if (media_stream_impl_ && media_stream_impl_->IsMediaStream(url)) {
+ return new webkit_media::WebMediaPlayerMS(
+ frame, client, AsWeakPtr(), media_stream_impl_, render_media_log);
+ }
+ }
+
media_player = new webkit_media::WebMediaPlayerImpl(
frame, client, AsWeakPtr(), collection, audio_source_provider,
audio_source_provider, message_loop_factory, media_stream_impl_,
diff --git a/media/video/capture/video_capture.h b/media/video/capture/video_capture.h
index d0aef98..a63843e 100644
--- a/media/video/capture/video_capture.h
+++ b/media/video/capture/video_capture.h
@@ -43,6 +43,7 @@ class MEDIA_EXPORT VideoCapture {
};
// TODO(wjia): add error codes.
+ // TODO(wjia): support weak ptr.
// Callbacks provided by client for notification of events.
class MEDIA_EXPORT EventHandler {
public:
diff --git a/webkit/media/media_stream_client.h b/webkit/media/media_stream_client.h
index ab1e767..edbb9b8 100644
--- a/webkit/media/media_stream_client.h
+++ b/webkit/media/media_stream_client.h
@@ -5,7 +5,9 @@
#ifndef WEBKIT_MEDIA_MEDIA_STREAM_CLIENT_H_
#define WEBKIT_MEDIA_MEDIA_STREAM_CLIENT_H_
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
+#include "webkit/media/video_frame_provider.h"
class GURL;
@@ -20,6 +22,14 @@ namespace webkit_media {
// the media stream.
class MediaStreamClient {
public:
+ // Check if the |url| is derived from a media stream object.
+ virtual bool IsMediaStream(const GURL& url) = 0;
+
+ virtual scoped_refptr<VideoFrameProvider> GetVideoFrameProvider(
+ const GURL& url,
+ const base::Closure& error_cb,
+ const VideoFrameProvider::RepaintCB& repaint_cb) = 0;
+
virtual scoped_refptr<media::VideoDecoder> GetVideoDecoder(
const GURL& url,
media::MessageLoopFactory* message_loop_factory) = 0;
diff --git a/webkit/media/simple_video_frame_provider.cc b/webkit/media/simple_video_frame_provider.cc
new file mode 100644
index 0000000..afdf3f8
--- /dev/null
+++ b/webkit/media/simple_video_frame_provider.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 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.
+
+#include "webkit/media/simple_video_frame_provider.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/message_loop_proxy.h"
+#include "media/base/video_frame.h"
+
+namespace webkit_media {
+
+SimpleVideoFrameProvider::SimpleVideoFrameProvider(
+ const gfx::Size& size,
+ const base::TimeDelta& frame_duration,
+ const base::Closure& error_cb,
+ const VideoFrameProvider::RepaintCB& repaint_cb)
+ : message_loop_proxy_(base::MessageLoopProxy::current()),
+ size_(size),
+ state_(kStopped),
+ frame_duration_(frame_duration),
+ error_cb_(error_cb),
+ repaint_cb_(repaint_cb) {
+}
+
+SimpleVideoFrameProvider::~SimpleVideoFrameProvider() {}
+
+void SimpleVideoFrameProvider::Start() {
+ DVLOG(1) << "SimpleVideoFrameProvider::Start";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ state_ = kStarted;
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(&SimpleVideoFrameProvider::GenerateFrame, this));
+}
+
+void SimpleVideoFrameProvider::Stop() {
+ DVLOG(1) << "SimpleVideoFrameProvider::Stop";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ state_ = kStopped;
+}
+
+void SimpleVideoFrameProvider::Play() {
+ DVLOG(1) << "SimpleVideoFrameProvider::Play";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ if (state_ == kPaused)
+ state_ = kStarted;
+}
+
+void SimpleVideoFrameProvider::Pause() {
+ DVLOG(1) << "SimpleVideoFrameProvider::Pause";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ if (state_ == kStarted)
+ state_ = kPaused;
+}
+
+void SimpleVideoFrameProvider::GenerateFrame() {
+ DVLOG(1) << "SimpleVideoFrameProvider::GenerateFrame";
+ DCHECK(message_loop_proxy_->BelongsToCurrentThread());
+ if (state_ == kStopped)
+ return;
+
+ if (state_ == kStarted) {
+ // Always allocate a new frame.
+ scoped_refptr<media::VideoFrame> video_frame =
+ media::VideoFrame::CreateFrame(media::VideoFrame::YV12,
+ size_,
+ size_,
+ current_time_);
+
+ // TODO(wjia): set pixel data to pre-defined patterns if it's desired to
+ // verify frame content.
+
+ repaint_cb_.Run(video_frame);
+ }
+
+ current_time_ += frame_duration_;
+ message_loop_proxy_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&SimpleVideoFrameProvider::GenerateFrame, this),
+ frame_duration_);
+}
+
+} // namespace webkit_media
diff --git a/webkit/media/simple_video_frame_provider.h b/webkit/media/simple_video_frame_provider.h
new file mode 100644
index 0000000..e217fa0
--- /dev/null
+++ b/webkit/media/simple_video_frame_provider.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 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.
+
+#ifndef WEBKIT_MEDIA_SIMPLE_VIDEO_FRAME_PROVIDER_H_
+#define WEBKIT_MEDIA_SIMPLE_VIDEO_FRAME_PROVIDER_H_
+
+#include "base/time.h"
+#include "ui/gfx/size.h"
+#include "webkit/media/video_frame_provider.h"
+
+namespace base {
+class MessageLoopProxy;
+}
+
+namespace webkit_media {
+
+// A simple implementation of VideoFrameProvider generates raw frames and
+// passes them to webmediaplayer.
+class SimpleVideoFrameProvider : public VideoFrameProvider {
+ public:
+ SimpleVideoFrameProvider(
+ const gfx::Size& size,
+ const base::TimeDelta& frame_duration,
+ const base::Closure& error_cb,
+ const RepaintCB& repaint_cb);
+
+ // VideoFrameProvider implementation.
+ virtual void Start() OVERRIDE;
+ virtual void Stop() OVERRIDE;
+ virtual void Play() OVERRIDE;
+ virtual void Pause() OVERRIDE;
+
+ protected:
+ virtual ~SimpleVideoFrameProvider();
+
+ private:
+ enum State {
+ kStarted,
+ kPaused,
+ kStopped,
+ };
+
+ void GenerateFrame();
+
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ gfx::Size size_;
+ State state_;
+
+ base::TimeDelta current_time_;
+ base::TimeDelta frame_duration_;
+ base::Closure error_cb_;
+ RepaintCB repaint_cb_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleVideoFrameProvider);
+};
+
+} // namespace webkit_media
+
+#endif // WEBKIT_MEDIA_SIMPLE_VIDEO_FRAME_PROVIDER_H_
diff --git a/webkit/media/video_frame_provider.cc b/webkit/media/video_frame_provider.cc
new file mode 100644
index 0000000..40818f2
--- /dev/null
+++ b/webkit/media/video_frame_provider.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 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.
+
+#include "webkit/media/video_frame_provider.h"
+
+namespace webkit_media {
+
+VideoFrameProvider::VideoFrameProvider() {}
+
+VideoFrameProvider::~VideoFrameProvider() {}
+
+} // namespace webkit_media
diff --git a/webkit/media/video_frame_provider.h b/webkit/media/video_frame_provider.h
new file mode 100644
index 0000000..f6a15cb
--- /dev/null
+++ b/webkit/media/video_frame_provider.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 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.
+
+#ifndef WEBKIT_MEDIA_VIDEO_FRAME_PROVIDER_H_
+#define WEBKIT_MEDIA_VIDEO_FRAME_PROVIDER_H_
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+
+namespace media {
+class VideoFrame;
+}
+
+namespace webkit_media {
+
+// Define an interface to provide a sequence of video frames to clients.
+// TODO(wjia): remove ref count.
+class VideoFrameProvider
+ : public base::RefCountedThreadSafe<VideoFrameProvider> {
+ public:
+ typedef base::Callback<void(const scoped_refptr<media::VideoFrame>&)>
+ RepaintCB;
+
+ // Start to provide video frames to the caller.
+ virtual void Start() = 0;
+
+ // Stop to provide video frames to the caller.
+ virtual void Stop() = 0;
+
+ // Resume to provide video frames to the caller after being paused.
+ virtual void Play() = 0;
+
+ // Put the provider in pause state and the caller will not receive video
+ // frames, but the provider might still generate video frames which are
+ // thrown away.
+ virtual void Pause() = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<VideoFrameProvider>;
+ VideoFrameProvider();
+ virtual ~VideoFrameProvider();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(VideoFrameProvider);
+};
+
+} // namespace webkit_media
+
+#endif // WEBKIT_MEDIA_VIDEO_FRAME_PROVIDER_H_
diff --git a/webkit/media/webkit_media.gypi b/webkit/media/webkit_media.gypi
index 77bb53f..54cc585 100644
--- a/webkit/media/webkit_media.gypi
+++ b/webkit/media/webkit_media.gypi
@@ -51,11 +51,17 @@
'filter_helpers.h',
'media_stream_client.h',
'preload.h',
+ 'simple_video_frame_provider.cc',
+ 'simple_video_frame_provider.h',
'skcanvas_video_renderer.cc',
'skcanvas_video_renderer.h',
+ 'video_frame_provider.cc',
+ 'video_frame_provider.h',
'webmediaplayer_delegate.h',
'webmediaplayer_impl.cc',
'webmediaplayer_impl.h',
+ 'webmediaplayer_ms.cc',
+ 'webmediaplayer_ms.h',
'webmediaplayer_proxy.cc',
'webmediaplayer_proxy.h',
'webmediaplayer_util.cc',
diff --git a/webkit/media/webmediaplayer_ms.cc b/webkit/media/webmediaplayer_ms.cc
new file mode 100644
index 0000000..6e09d9d
--- /dev/null
+++ b/webkit/media/webmediaplayer_ms.cc
@@ -0,0 +1,398 @@
+// Copyright (c) 2012 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.
+
+#include "webkit/media/webmediaplayer_ms.h"
+
+#include <limits>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "media/base/media_log.h"
+#include "media/base/video_frame.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayerClient.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebVideoFrame.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h"
+#include "webkit/media/media_stream_client.h"
+#include "webkit/media/video_frame_provider.h"
+#include "webkit/media/webmediaplayer_delegate.h"
+#include "webkit/media/webmediaplayer_util.h"
+#include "webkit/media/webvideoframe_impl.h"
+
+using WebKit::WebCanvas;
+using WebKit::WebMediaPlayer;
+using WebKit::WebRect;
+using WebKit::WebSize;
+
+namespace webkit_media {
+
+WebMediaPlayerMS::WebMediaPlayerMS(
+ WebKit::WebFrame* frame,
+ WebKit::WebMediaPlayerClient* client,
+ base::WeakPtr<WebMediaPlayerDelegate> delegate,
+ MediaStreamClient* media_stream_client,
+ media::MediaLog* media_log)
+ : frame_(frame),
+ network_state_(WebMediaPlayer::NetworkStateEmpty),
+ ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
+ buffered_(static_cast<size_t>(1)),
+ client_(client),
+ delegate_(delegate),
+ media_stream_client_(media_stream_client),
+ video_frame_provider_started_(false),
+ paused_(true),
+ pending_repaint_(false),
+ got_first_frame_(false),
+ total_frame_count_(0),
+ dropped_frame_count_(0),
+ media_log_(media_log) {
+ DVLOG(1) << "WebMediaPlayerMS::ctor";
+ DCHECK(media_stream_client);
+ media_log_->AddEvent(
+ media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_CREATED));
+}
+
+WebMediaPlayerMS::~WebMediaPlayerMS() {
+ DVLOG(1) << "WebMediaPlayerMS::dtor";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (video_frame_provider_) {
+ video_frame_provider_->Stop();
+ }
+
+ media_log_->AddEvent(
+ media_log_->CreateEvent(media::MediaLogEvent::WEBMEDIAPLAYER_DESTROYED));
+
+ if (delegate_)
+ delegate_->PlayerGone(this);
+}
+
+void WebMediaPlayerMS::load(const WebKit::WebURL& url, CORSMode cors_mode) {
+ DVLOG(1) << "WebMediaPlayerMS::load";
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ GURL gurl(url);
+
+ setVolume(GetClient()->volume());
+ SetNetworkState(WebMediaPlayer::NetworkStateLoading);
+ SetReadyState(WebMediaPlayer::ReadyStateHaveNothing);
+ media_log_->AddEvent(media_log_->CreateLoadEvent(url.spec()));
+
+ // Check if this url is media stream.
+ video_frame_provider_ = media_stream_client_->GetVideoFrameProvider(
+ url,
+ base::Bind(&WebMediaPlayerMS::OnSourceError, AsWeakPtr()),
+ base::Bind(&WebMediaPlayerMS::OnFrameAvailable, AsWeakPtr()));
+ if (video_frame_provider_) {
+ SetNetworkState(WebMediaPlayer::NetworkStateLoaded);
+ GetClient()->sourceOpened();
+ GetClient()->setOpaque(true);
+ SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata);
+ SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData);
+ RepaintInternal();
+ } else {
+ SetNetworkState(WebMediaPlayer::NetworkStateNetworkError);
+ }
+}
+
+void WebMediaPlayerMS::cancelLoad() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void WebMediaPlayerMS::play() {
+ DVLOG(1) << "WebMediaPlayerMS::play";
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ paused_ = false;
+ if (video_frame_provider_) {
+ if (video_frame_provider_started_) {
+ video_frame_provider_->Play();
+ } else {
+ video_frame_provider_started_ = true;
+ video_frame_provider_->Start();
+ }
+ }
+ // TODO(wjia): add audio. See crbug.com/142988.
+
+ media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PLAY));
+
+ if (delegate_)
+ delegate_->DidPlay(this);
+}
+
+void WebMediaPlayerMS::pause() {
+ DVLOG(1) << "WebMediaPlayerMS::pause";
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ if (video_frame_provider_)
+ video_frame_provider_->Pause();
+ // TODO(wjia): add audio. See crbug.com/142988.
+ paused_ = true;
+
+ media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE));
+
+ if (delegate_)
+ delegate_->DidPause(this);
+}
+
+bool WebMediaPlayerMS::supportsFullscreen() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return true;
+}
+
+bool WebMediaPlayerMS::supportsSave() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return false;
+}
+
+void WebMediaPlayerMS::seek(float seconds) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void WebMediaPlayerMS::setEndTime(float seconds) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void WebMediaPlayerMS::setRate(float rate) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void WebMediaPlayerMS::setVolume(float volume) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // TODO(wjia): set audio volume. See crbug.com/142988.
+ NOTIMPLEMENTED();
+}
+
+void WebMediaPlayerMS::setVisible(bool visible) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void WebMediaPlayerMS::setPreload(WebMediaPlayer::Preload preload) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+bool WebMediaPlayerMS::totalBytesKnown() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return false;
+}
+
+bool WebMediaPlayerMS::hasVideo() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return (video_frame_provider_ != NULL);
+}
+
+bool WebMediaPlayerMS::hasAudio() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // TODO(wjia): add audio support. See crbug.com/142988.
+ return false;
+}
+
+WebKit::WebSize WebMediaPlayerMS::naturalSize() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ gfx::Size size;
+ if (current_frame_)
+ size = current_frame_->natural_size();
+ DVLOG(1) << "WebMediaPlayerMS::naturalSize, " << size.ToString();
+ return WebKit::WebSize(size);
+}
+
+bool WebMediaPlayerMS::paused() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return paused_;
+}
+
+bool WebMediaPlayerMS::seeking() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return false;
+}
+
+float WebMediaPlayerMS::duration() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return std::numeric_limits<float>::infinity();
+}
+
+float WebMediaPlayerMS::currentTime() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (current_frame_.get()) {
+ return current_frame_->GetTimestamp().InSecondsF();
+ }
+ return 0.0f;
+}
+
+int WebMediaPlayerMS::dataRate() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return 0;
+}
+
+WebMediaPlayer::NetworkState WebMediaPlayerMS::networkState() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DVLOG(1) << "WebMediaPlayerMS::networkState, state:" << network_state_;
+ return network_state_;
+}
+
+WebMediaPlayer::ReadyState WebMediaPlayerMS::readyState() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DVLOG(1) << "WebMediaPlayerMS::readyState, state:" << ready_state_;
+ return ready_state_;
+}
+
+const WebKit::WebTimeRanges& WebMediaPlayerMS::buffered() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return buffered_;
+}
+
+float WebMediaPlayerMS::maxTimeSeekable() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return 0.0f;
+}
+
+bool WebMediaPlayerMS::didLoadingProgress() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return false;
+}
+
+unsigned long long WebMediaPlayerMS::totalBytes() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return 0;
+}
+
+void WebMediaPlayerMS::setSize(const WebSize& size) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ // Don't need to do anything as we use the dimensions passed in via paint().
+}
+
+void WebMediaPlayerMS::paint(WebCanvas* canvas,
+ const WebRect& rect,
+ uint8_t alpha) {
+ DVLOG(1) << "WebMediaPlayerMS::paint";
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ video_renderer_.Paint(current_frame_, canvas, rect, alpha);
+}
+
+bool WebMediaPlayerMS::hasSingleSecurityOrigin() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return true;
+}
+
+bool WebMediaPlayerMS::didPassCORSAccessCheck() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return true;
+}
+
+WebMediaPlayer::MovieLoadType WebMediaPlayerMS::movieLoadType() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return WebMediaPlayer::MovieLoadTypeUnknown;
+}
+
+float WebMediaPlayerMS::mediaTimeForTimeValue(float timeValue) const {
+ return ConvertSecondsToTimestamp(timeValue).InSecondsF();
+}
+
+unsigned WebMediaPlayerMS::decodedFrameCount() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DVLOG(1) << "WebMediaPlayerMS::decodedFrameCount, " << total_frame_count_;
+ return total_frame_count_;
+}
+
+unsigned WebMediaPlayerMS::droppedFrameCount() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DVLOG(1) << "WebMediaPlayerMS::droppedFrameCount, " << dropped_frame_count_;
+ return dropped_frame_count_;
+}
+
+unsigned WebMediaPlayerMS::audioDecodedByteCount() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+unsigned WebMediaPlayerMS::videoDecodedByteCount() const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+WebKit::WebVideoFrame* WebMediaPlayerMS::getCurrentFrame() {
+ DVLOG(1) << "WebMediaPlayerMS::getCurrentFrame";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(!pending_repaint_);
+ pending_repaint_ = true;
+ if (current_frame_.get())
+ return new webkit_media::WebVideoFrameImpl(current_frame_);
+ return NULL;
+}
+
+void WebMediaPlayerMS::putCurrentFrame(
+ WebKit::WebVideoFrame* web_video_frame) {
+ DVLOG(1) << "WebMediaPlayerMS::putCurrentFrame";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(pending_repaint_);
+ pending_repaint_ = false;
+ if (web_video_frame) {
+ delete web_video_frame;
+ }
+}
+
+void WebMediaPlayerMS::OnFrameAvailable(
+ const scoped_refptr<media::VideoFrame>& frame) {
+ DVLOG(1) << "WebMediaPlayerMS::OnFrameAvailable";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ++total_frame_count_;
+ if (!got_first_frame_) {
+ got_first_frame_ = true;
+ start_time_ = frame->GetTimestamp();
+ }
+ current_frame_ = frame;
+ current_frame_->SetTimestamp(frame->GetTimestamp() - start_time_);
+ if (pending_repaint_) {
+ // TODO(wjia): Figure out how to calculate dropped frame count for
+ // both S/W and H/W compositing.
+ // ++dropped_frame_count_;
+ } else {
+ GetClient()->repaint();
+ }
+}
+
+void WebMediaPlayerMS::RepaintInternal() {
+ DVLOG(1) << "WebMediaPlayerMS::RepaintInternal";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (!pending_repaint_) {
+ GetClient()->repaint();
+ }
+}
+
+void WebMediaPlayerMS::OnSourceError() {
+ DVLOG(1) << "WebMediaPlayerMS::OnSourceError";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ SetNetworkState(WebMediaPlayer::NetworkStateFormatError);
+ RepaintInternal();
+}
+
+void WebMediaPlayerMS::SetNetworkState(WebMediaPlayer::NetworkState state) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ network_state_ = state;
+ // Always notify to ensure client has the latest value.
+ GetClient()->networkStateChanged();
+}
+
+void WebMediaPlayerMS::SetReadyState(WebMediaPlayer::ReadyState state) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ ready_state_ = state;
+ // Always notify to ensure client has the latest value.
+ GetClient()->readyStateChanged();
+}
+
+WebKit::WebMediaPlayerClient* WebMediaPlayerMS::GetClient() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK(client_);
+ return client_;
+}
+
+} // namespace webkit_media
diff --git a/webkit/media/webmediaplayer_ms.h b/webkit/media/webmediaplayer_ms.h
new file mode 100644
index 0000000..e49adc0
--- /dev/null
+++ b/webkit/media/webmediaplayer_ms.h
@@ -0,0 +1,170 @@
+// Copyright (c) 2012 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.
+
+#ifndef WEBKIT_MEDIA_WEBMEDIAPLAYER_MS_H_
+#define WEBKIT_MEDIA_WEBMEDIAPLAYER_MS_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "googleurl/src/gurl.h"
+#include "skia/ext/platform_canvas.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaPlayer.h"
+#include "webkit/media/skcanvas_video_renderer.h"
+
+namespace WebKit {
+class WebFrame;
+class WebMediaPlayerClient;
+}
+
+namespace media {
+class MediaLog;
+}
+
+namespace webkit_media {
+
+class MediaStreamClient;
+class VideoFrameProvider;
+class WebMediaPlayerDelegate;
+
+// WebMediaPlayerMS delegates calls from WebCore::MediaPlayerPrivate to
+// Chrome's media player when "src" is from media stream.
+//
+// WebMediaPlayerMS works with multiple objects, the most important ones are:
+//
+// VideoFrameProvider
+// provides video frames for rendering.
+//
+// TODO(wjia): add AudioPlayer.
+// AudioPlayer
+// plays audio streams.
+//
+// WebKit::WebMediaPlayerClient
+// WebKit client of this media player object.
+class WebMediaPlayerMS
+ : public WebKit::WebMediaPlayer,
+ public base::SupportsWeakPtr<WebMediaPlayerMS> {
+ public:
+ // Construct a WebMediaPlayerMS with reference to the client, and
+ // a MediaStreamClient which provides VideoFrameProvider.
+ WebMediaPlayerMS(WebKit::WebFrame* frame,
+ WebKit::WebMediaPlayerClient* client,
+ base::WeakPtr<WebMediaPlayerDelegate> delegate,
+ MediaStreamClient* media_stream_client,
+ media::MediaLog* media_log);
+ virtual ~WebMediaPlayerMS();
+
+ virtual void load(const WebKit::WebURL& url, CORSMode cors_mode) OVERRIDE;
+ virtual void cancelLoad() OVERRIDE;
+
+ // Playback controls.
+ virtual void play() OVERRIDE;
+ virtual void pause() OVERRIDE;
+ virtual bool supportsFullscreen() const OVERRIDE;
+ virtual bool supportsSave() const OVERRIDE;
+ virtual void seek(float seconds) OVERRIDE;
+ virtual void setEndTime(float seconds) OVERRIDE;
+ virtual void setRate(float rate) OVERRIDE;
+ virtual void setVolume(float volume) OVERRIDE;
+ virtual void setVisible(bool visible) OVERRIDE;
+ virtual void setPreload(WebKit::WebMediaPlayer::Preload preload) OVERRIDE;
+ virtual bool totalBytesKnown() OVERRIDE;
+ virtual const WebKit::WebTimeRanges& buffered() OVERRIDE;
+ virtual float maxTimeSeekable() const OVERRIDE;
+
+ // Methods for painting.
+ virtual void setSize(const WebKit::WebSize& size) OVERRIDE;
+
+ virtual void paint(WebKit::WebCanvas* canvas,
+ const WebKit::WebRect& rect,
+ uint8_t alpha) OVERRIDE;
+
+ // True if the loaded media has a playable video/audio track.
+ virtual bool hasVideo() const OVERRIDE;
+ virtual bool hasAudio() const OVERRIDE;
+
+ // Dimensions of the video.
+ virtual WebKit::WebSize naturalSize() const OVERRIDE;
+
+ // Getters of playback state.
+ virtual bool paused() const OVERRIDE;
+ virtual bool seeking() const OVERRIDE;
+ virtual float duration() const OVERRIDE;
+ virtual float currentTime() const OVERRIDE;
+
+ // Get rate of loading the resource.
+ virtual int32 dataRate() const OVERRIDE;
+
+ // Internal states of loading and network.
+ virtual WebKit::WebMediaPlayer::NetworkState networkState() const OVERRIDE;
+ virtual WebKit::WebMediaPlayer::ReadyState readyState() const OVERRIDE;
+
+ virtual bool didLoadingProgress() const OVERRIDE;
+ virtual unsigned long long totalBytes() const OVERRIDE;
+
+ virtual bool hasSingleSecurityOrigin() const OVERRIDE;
+ virtual bool didPassCORSAccessCheck() const OVERRIDE;
+ virtual WebKit::WebMediaPlayer::MovieLoadType movieLoadType() const OVERRIDE;
+
+ virtual float mediaTimeForTimeValue(float timeValue) const OVERRIDE;
+
+ virtual unsigned decodedFrameCount() const OVERRIDE;
+ virtual unsigned droppedFrameCount() const OVERRIDE;
+ virtual unsigned audioDecodedByteCount() const OVERRIDE;
+ virtual unsigned videoDecodedByteCount() const OVERRIDE;
+
+ virtual WebKit::WebVideoFrame* getCurrentFrame() OVERRIDE;
+ virtual void putCurrentFrame(WebKit::WebVideoFrame* web_video_frame) OVERRIDE;
+
+ private:
+ // The callback for VideoFrameProvider to signal a new frame is available.
+ void OnFrameAvailable(const scoped_refptr<media::VideoFrame>& frame);
+ // Need repaint due to state change.
+ void RepaintInternal();
+
+ // The callback for source to report error.
+ void OnSourceError();
+
+ // Helpers that set the network/ready state and notifies the client if
+ // they've changed.
+ void SetNetworkState(WebKit::WebMediaPlayer::NetworkState state);
+ void SetReadyState(WebKit::WebMediaPlayer::ReadyState state);
+
+ // Getter method to |client_|.
+ WebKit::WebMediaPlayerClient* GetClient();
+
+ WebKit::WebFrame* frame_;
+
+ WebKit::WebMediaPlayer::NetworkState network_state_;
+ WebKit::WebMediaPlayer::ReadyState ready_state_;
+
+ WebKit::WebTimeRanges buffered_;
+
+ // Used for DCHECKs to ensure methods calls executed in the correct thread.
+ base::ThreadChecker thread_checker_;
+
+ WebKit::WebMediaPlayerClient* client_;
+
+ base::WeakPtr<WebMediaPlayerDelegate> delegate_;
+
+ MediaStreamClient* media_stream_client_;
+ scoped_refptr<VideoFrameProvider> video_frame_provider_;
+ bool video_frame_provider_started_;
+ bool paused_;
+ scoped_refptr<media::VideoFrame> current_frame_;
+ bool pending_repaint_;
+ bool got_first_frame_;
+ base::TimeDelta start_time_;
+ unsigned total_frame_count_;
+ unsigned dropped_frame_count_;
+ SkCanvasVideoRenderer video_renderer_;
+
+ scoped_refptr<media::MediaLog> media_log_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerMS);
+};
+
+} // namespace webkit_media
+
+#endif // WEBKIT_MEDIA_WEBMEDIAPLAYER_MS_H_
diff --git a/webkit/support/test_media_stream_client.cc b/webkit/support/test_media_stream_client.cc
index f82b891..70bb8cb 100644
--- a/webkit/support/test_media_stream_client.cc
+++ b/webkit/support/test_media_stream_client.cc
@@ -8,11 +8,11 @@
#include "media/base/message_loop_factory.h"
#include "media/base/pipeline.h"
#include "media/filters/video_frame_generator.h"
-
#include "third_party/WebKit/Source/WebKit/chromium/public/WebMediaStreamRegistry.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStreamComponent.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebMediaStreamDescriptor.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
+#include "webkit/media/simple_video_frame_provider.h"
using namespace WebKit;
@@ -36,6 +36,29 @@ bool IsMockMediaStreamWithVideo(const WebURL& url) {
namespace webkit_support {
+TestMediaStreamClient::TestMediaStreamClient() {}
+
+TestMediaStreamClient::~TestMediaStreamClient() {}
+
+bool TestMediaStreamClient::IsMediaStream(const GURL& url) {
+ return IsMockMediaStreamWithVideo(url);
+}
+
+scoped_refptr<webkit_media::VideoFrameProvider>
+TestMediaStreamClient::GetVideoFrameProvider(
+ const GURL& url,
+ const base::Closure& error_cb,
+ const webkit_media::VideoFrameProvider::RepaintCB& repaint_cb) {
+ if (!IsMockMediaStreamWithVideo(url))
+ return NULL;
+
+ return new webkit_media::SimpleVideoFrameProvider(
+ gfx::Size(kVideoCaptureWidth, kVideoCaptureHeight),
+ base::TimeDelta::FromMilliseconds(kVideoCaptureFrameDurationMs),
+ error_cb,
+ repaint_cb);
+}
+
scoped_refptr<media::VideoDecoder> TestMediaStreamClient::GetVideoDecoder(
const GURL& url, media::MessageLoopFactory* message_loop_factory) {
// This class is installed in a chain of possible VideoDecoder creators
diff --git a/webkit/support/test_media_stream_client.h b/webkit/support/test_media_stream_client.h
index 471d0c4..500dd2a 100644
--- a/webkit/support/test_media_stream_client.h
+++ b/webkit/support/test_media_stream_client.h
@@ -9,28 +9,23 @@
#ifndef WEBKIT_SUPPORT_TEST_MEDIA_STREAM_CLIENT_H_
#define WEBKIT_SUPPORT_TEST_MEDIA_STREAM_CLIENT_H_
+#include "base/callback_forward.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h"
#include "webkit/media/media_stream_client.h"
namespace webkit_support {
-// TODO(tommyw): Remove deprecated class after corresponding
-// WebKit patch is committed.
-class MediaStreamUtil {
- public:
- virtual bool IsMockStream(const WebKit::WebURL& url) = 0;
-};
-
class TestMediaStreamClient : public webkit_media::MediaStreamClient {
public:
- // TODO(tommyw): Remove deprecated constructor after
- // corresponding WebKit patch is committed.
- explicit TestMediaStreamClient(MediaStreamUtil* media_stream_util) {}
-
- TestMediaStreamClient() {}
- virtual ~TestMediaStreamClient() {}
+ TestMediaStreamClient();
+ virtual ~TestMediaStreamClient();
// Implement webkit_media::MediaStreamClient.
+ virtual bool IsMediaStream(const GURL& url) OVERRIDE;
+ virtual scoped_refptr<webkit_media::VideoFrameProvider> GetVideoFrameProvider(
+ const GURL& url,
+ const base::Closure& error_cb,
+ const webkit_media::VideoFrameProvider::RepaintCB& repaint_cb) OVERRIDE;
virtual scoped_refptr<media::VideoDecoder> GetVideoDecoder(
const GURL& url,
media::MessageLoopFactory* message_loop_factory) OVERRIDE;
diff --git a/webkit/support/webkit_support.cc b/webkit/support/webkit_support.cc
index 435c0f4..166acab 100644
--- a/webkit/support/webkit_support.cc
+++ b/webkit/support/webkit_support.cc
@@ -61,7 +61,9 @@
#include "webkit/media/android/webmediaplayer_in_process_android.h"
#include "webkit/media/android/webmediaplayer_manager_android.h"
#endif
+#include "webkit/media/media_stream_client.h"
#include "webkit/media/webmediaplayer_impl.h"
+#include "webkit/media/webmediaplayer_ms.h"
#include "webkit/plugins/npapi/plugin_list.h"
#include "webkit/plugins/npapi/webplugin_impl.h"
#include "webkit/plugins/npapi/webplugin_page_delegate.h"
@@ -413,6 +415,15 @@ WebKit::WebMediaPlayer* CreateMediaPlayer(
scoped_ptr<media::FilterCollection> collection(
new media::FilterCollection());
+ if (media_stream_client && media_stream_client->IsMediaStream(url)) {
+ return new webkit_media::WebMediaPlayerMS(
+ frame,
+ client,
+ base::WeakPtr<webkit_media::WebMediaPlayerDelegate>(),
+ media_stream_client,
+ new media::MediaLog());
+ }
+
return new webkit_media::WebMediaPlayerImpl(
frame,
client,