summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/renderer')
-rw-r--r--chrome/renderer/media/ipc_video_renderer.cc183
-rw-r--r--chrome/renderer/media/ipc_video_renderer.h108
-rw-r--r--chrome/renderer/render_view.cc12
-rw-r--r--chrome/renderer/render_widget.cc10
-rw-r--r--chrome/renderer/render_widget.h2
5 files changed, 314 insertions, 1 deletions
diff --git a/chrome/renderer/media/ipc_video_renderer.cc b/chrome/renderer/media/ipc_video_renderer.cc
new file mode 100644
index 0000000..0a98489
--- /dev/null
+++ b/chrome/renderer/media/ipc_video_renderer.cc
@@ -0,0 +1,183 @@
+// Copyright (c) 2010 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 "chrome/renderer/media/ipc_video_renderer.h"
+
+#include "chrome/common/render_messages.h"
+#include "chrome/renderer/render_thread.h"
+#include "media/base/buffers.h"
+#include "media/base/media_format.h"
+
+IPCVideoRenderer::IPCVideoRenderer(
+ webkit_glue::WebMediaPlayerImpl::Proxy* proxy,
+ int routing_id)
+ : proxy_(proxy),
+ created_(false),
+ routing_id_(routing_id),
+ stopped_(false, false) {
+ // TODO(hclam): decide whether to do the following line in this thread or
+ // in the render thread.
+ proxy->SetVideoRenderer(this);
+}
+
+IPCVideoRenderer::~IPCVideoRenderer() {
+}
+
+// static
+media::FilterFactory* IPCVideoRenderer::CreateFactory(
+ webkit_glue::WebMediaPlayerImpl::Proxy* proxy,
+ int routing_id) {
+ return new media::FilterFactoryImpl2<
+ IPCVideoRenderer,
+ webkit_glue::WebMediaPlayerImpl::Proxy*,
+ int>(proxy, routing_id);
+}
+
+// static
+bool IPCVideoRenderer::IsMediaFormatSupported(
+ const media::MediaFormat& media_format) {
+ int width = 0;
+ int height = 0;
+ return ParseMediaFormat(media_format, &width, &height);
+}
+
+bool IPCVideoRenderer::OnInitialize(media::VideoDecoder* decoder) {
+ int width = 0;
+ int height = 0;
+ if (!ParseMediaFormat(decoder->media_format(), &width, &height))
+ return false;
+
+ video_size_.SetSize(width, height);
+
+ // TODO(scherkus): we're assuming YV12 here.
+ size_t size = (width * height) + ((width * height) >> 1);
+ uint32 epoch = static_cast<uint32>(reinterpret_cast<size_t>(this));
+ transport_dib_.reset(TransportDIB::Create(size, epoch));
+ CHECK(transport_dib_.get());
+
+ return true;
+}
+
+void IPCVideoRenderer::OnStop() {
+ stopped_.Signal();
+
+ proxy_->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &IPCVideoRenderer::DoDestroyVideo));
+}
+
+void IPCVideoRenderer::OnFrameAvailable() {
+ proxy_->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(this, &IPCVideoRenderer::DoUpdateVideo));
+}
+
+void IPCVideoRenderer::SetRect(const gfx::Rect& rect) {
+ DCHECK(MessageLoop::current() == proxy_->message_loop());
+
+ // TODO(scherkus): this is actually a SetSize() call... there's a pending
+ // WebKit bug to get this fixed up. It would be nice if this was a real
+ // SetRect() call so we could get the absolute coordinates instead of relying
+ // on Paint().
+}
+
+void IPCVideoRenderer::Paint(skia::PlatformCanvas* canvas,
+ const gfx::Rect& dest_rect) {
+ DCHECK(MessageLoop::current() == proxy_->message_loop());
+
+ // Copy the rect for UpdateVideo messages.
+ video_rect_ = dest_rect;
+
+ if (!created_) {
+ created_ = true;
+ Send(new ViewHostMsg_CreateVideo(routing_id_, video_size_));
+
+ // Force an update in case the first frame arrived before the first
+ // Paint() call.
+ DoUpdateVideo();
+ }
+
+ // TODO(scherkus): code to punch a hole through the backing store goes here.
+ // We don't need it right away since we don't do a proper alpha composite
+ // between the browser BackingStore and VideoLayer.
+}
+
+void IPCVideoRenderer::Send(IPC::Message* msg) {
+ DCHECK(routing_id_ != MSG_ROUTING_NONE);
+ DCHECK(routing_id_ == msg->routing_id());
+
+ bool result = RenderThread::current()->Send(msg);
+ LOG_IF(ERROR, !result) << "RenderThread::current()->Send(msg) failed";
+}
+
+void IPCVideoRenderer::DoUpdateVideo() {
+ DCHECK(MessageLoop::current() == proxy_->message_loop());
+
+ // Nothing to do if we don't know where we are positioned on the page.
+ if (!created_ || video_rect_.IsEmpty() || stopped_.IsSignaled()) {
+ return;
+ }
+
+ scoped_refptr<media::VideoFrame> frame;
+ GetCurrentFrame(&frame);
+ if (!frame) {
+ return;
+ }
+
+ media::VideoSurface surface;
+ CHECK(frame->Lock(&surface));
+ CHECK(surface.width == static_cast<size_t>(video_size_.width()));
+ CHECK(surface.height == static_cast<size_t>(video_size_.height()));
+ CHECK(surface.format == media::VideoSurface::YV12);
+ CHECK(surface.planes == 3);
+
+ uint8* dest = reinterpret_cast<uint8*>(transport_dib_->memory());
+
+ // Copy Y plane.
+ const uint8* src = surface.data[media::VideoSurface::kYPlane];
+ size_t stride = surface.strides[media::VideoSurface::kYPlane];
+ for (size_t row = 0; row < surface.height; ++row) {
+ memcpy(dest, src, surface.width);
+ dest += surface.width;
+ src += stride;
+ }
+
+ // Copy U plane.
+ src = surface.data[media::VideoSurface::kUPlane];
+ stride = surface.strides[media::VideoSurface::kUPlane];
+ for (size_t row = 0; row < surface.height / 2; ++row) {
+ memcpy(dest, src, surface.width / 2);
+ dest += surface.width / 2;
+ src += stride;
+ }
+
+ // Copy V plane.
+ src = surface.data[media::VideoSurface::kVPlane];
+ stride = surface.strides[media::VideoSurface::kVPlane];
+ for (size_t row = 0; row < surface.height / 2; ++row) {
+ memcpy(dest, src, surface.width / 2);
+ dest += surface.width / 2;
+ src += stride;
+ }
+
+ // Sanity check!
+ uint8* expected = reinterpret_cast<uint8*>(transport_dib_->memory()) +
+ transport_dib_->size();
+ CHECK(dest == expected);
+
+ Send(new ViewHostMsg_UpdateVideo(routing_id_,
+ transport_dib_->id(),
+ video_rect_));
+
+ frame->Unlock();
+}
+
+void IPCVideoRenderer::DoDestroyVideo() {
+ DCHECK(MessageLoop::current() == proxy_->message_loop());
+
+ // We shouldn't receive any more messages after the browser receives this.
+ Send(new ViewHostMsg_DestroyVideo(routing_id_));
+
+ // Detach ourselves from the proxy.
+ proxy_->SetVideoRenderer(NULL);
+ proxy_ = NULL;
+}
diff --git a/chrome/renderer/media/ipc_video_renderer.h b/chrome/renderer/media/ipc_video_renderer.h
new file mode 100644
index 0000000..839df03
--- /dev/null
+++ b/chrome/renderer/media/ipc_video_renderer.h
@@ -0,0 +1,108 @@
+// Copyright (c) 2010 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.
+
+// This video renderer implementation uses IPC to signal the browser process to
+// composite the video as a separate layer underneath the backing store.
+//
+// Extremely experimental. Use at own risk!
+
+#ifndef CHROME_RENDERER_MEDIA_IPC_VIDEO_RENDERER_H_
+#define CHROME_RENDERER_MEDIA_IPC_VIDEO_RENDERER_H_
+
+#include "base/gfx/rect.h"
+#include "base/gfx/size.h"
+#include "base/waitable_event.h"
+#include "chrome/common/transport_dib.h"
+#include "media/filters/video_renderer_base.h"
+#include "webkit/glue/media/web_video_renderer.h"
+#include "webkit/glue/webmediaplayer_impl.h"
+
+class IPCVideoRenderer : public webkit_glue::WebVideoRenderer {
+ public:
+ // WebVideoRenderer implementation.
+ virtual void SetRect(const gfx::Rect& rect);
+ virtual void Paint(skia::PlatformCanvas* canvas, const gfx::Rect& dest_rect);
+
+ void OnUpdateVideo();
+ void OnUpdateVideoAck();
+ void OnDestroyVideo();
+
+ // Static method for creating factory for this object.
+ static media::FilterFactory* CreateFactory(
+ webkit_glue::WebMediaPlayerImpl::Proxy* proxy,
+ int routing_id);
+
+ // FilterFactoryImpl2 implementation.
+ static bool IsMediaFormatSupported(const media::MediaFormat& media_format);
+
+ // TODO(scherkus): remove this mega-hack, see http://crbug.com/28207
+ class FactoryFactory : public webkit_glue::WebVideoRendererFactoryFactory {
+ public:
+ FactoryFactory(int routing_id)
+ : webkit_glue::WebVideoRendererFactoryFactory(),
+ routing_id_(routing_id) {
+ }
+
+ virtual media::FilterFactory* CreateFactory(
+ webkit_glue::WebMediaPlayerImpl::Proxy* proxy) {
+ return IPCVideoRenderer::CreateFactory(proxy, routing_id_);
+ }
+
+ private:
+ int routing_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(FactoryFactory);
+ };
+
+ protected:
+ // VideoRendererBase implementation.
+ virtual bool OnInitialize(media::VideoDecoder* decoder);
+ virtual void OnStop();
+ virtual void OnFrameAvailable();
+
+ private:
+ // Only the filter factories can create instances.
+ friend class media::FilterFactoryImpl2<
+ IPCVideoRenderer,
+ webkit_glue::WebMediaPlayerImpl::Proxy*,
+ int>;
+ IPCVideoRenderer(webkit_glue::WebMediaPlayerImpl::Proxy* proxy,
+ int routing_id);
+ virtual ~IPCVideoRenderer();
+
+ // Send an IPC message to the browser process. The routing ID of the message
+ // is assumed to match |routing_id_|.
+ void Send(IPC::Message* msg);
+
+ // Handles updating the video on the render thread.
+ void DoUpdateVideo();
+
+ // Handles destroying the video on the render thread.
+ void DoDestroyVideo();
+
+ // Pointer to our parent object that is called to request repaints.
+ scoped_refptr<webkit_glue::WebMediaPlayerImpl::Proxy> proxy_;
+
+ // The size of the video.
+ gfx::Size video_size_;
+
+ // The rect of the video.
+ gfx::Rect video_rect_;
+
+ // Whether we've created the video layer on the browser.
+ bool created_;
+
+ // Used to transporting YUV to the browser process.
+ int routing_id_;
+ scoped_ptr<TransportDIB> transport_dib_;
+
+ // Used to determine whether we've been instructed to stop.
+ // TODO(scherkus): work around because we don't have asynchronous stopping.
+ // Refer to http://crbug.com/16059
+ base::WaitableEvent stopped_;
+
+ DISALLOW_COPY_AND_ASSIGN(IPCVideoRenderer);
+};
+
+#endif // CHROME_RENDERER_MEDIA_IPC_VIDEO_RENDERER_H_
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 03c0850..b3ef04b 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -47,6 +47,7 @@
#include "chrome/renderer/geolocation_dispatcher.h"
#include "chrome/renderer/localized_error.h"
#include "chrome/renderer/media/audio_renderer_impl.h"
+#include "chrome/renderer/media/ipc_video_renderer.h"
#include "chrome/renderer/navigation_state.h"
#include "chrome/renderer/notification_provider.h"
#include "chrome/renderer/plugin_channel_host.h"
@@ -110,6 +111,7 @@
#include "webkit/glue/password_form.h"
#include "webkit/glue/plugins/plugin_list.h"
#include "webkit/glue/plugins/webplugin_delegate_impl.h"
+#include "webkit/glue/media/video_renderer_impl.h"
#include "webkit/glue/webdropdata.h"
#include "webkit/glue/webkit_glue.h"
#include "webkit/glue/webmediaplayer_impl.h"
@@ -2140,7 +2142,15 @@ WebMediaPlayer* RenderView::createMediaPlayer(
factory->AddFactory(buffered_data_source_factory);
factory->AddFactory(simple_data_source_factory);
}
- return new webkit_glue::WebMediaPlayerImpl(client, factory);
+
+ webkit_glue::WebVideoRendererFactoryFactory* factory_factory = NULL;
+ if (cmd_line->HasSwitch(switches::kEnableVideoLayering)) {
+ factory_factory = new IPCVideoRenderer::FactoryFactory(routing_id_);
+ } else {
+ factory_factory = new webkit_glue::VideoRendererImpl::FactoryFactory();
+ }
+
+ return new webkit_glue::WebMediaPlayerImpl(client, factory, factory_factory);
}
WebCookieJar* RenderView::cookieJar() {
diff --git a/chrome/renderer/render_widget.cc b/chrome/renderer/render_widget.cc
index 5212635..75cd8d2 100644
--- a/chrome/renderer/render_widget.cc
+++ b/chrome/renderer/render_widget.cc
@@ -140,6 +140,8 @@ IPC_DEFINE_MESSAGE_MAP(RenderWidget)
IPC_MESSAGE_HANDLER(ViewMsg_WasHidden, OnWasHidden)
IPC_MESSAGE_HANDLER(ViewMsg_WasRestored, OnWasRestored)
IPC_MESSAGE_HANDLER(ViewMsg_UpdateRect_ACK, OnUpdateRectAck)
+ IPC_MESSAGE_HANDLER(ViewMsg_CreateVideo_ACK, OnCreateVideoAck)
+ IPC_MESSAGE_HANDLER(ViewMsg_UpdateVideo_ACK, OnUpdateVideoAck)
IPC_MESSAGE_HANDLER(ViewMsg_HandleInputEvent, OnHandleInputEvent)
IPC_MESSAGE_HANDLER(ViewMsg_MouseCaptureLost, OnMouseCaptureLost)
IPC_MESSAGE_HANDLER(ViewMsg_SetFocus, OnSetFocus)
@@ -277,6 +279,14 @@ void RenderWidget::OnUpdateRectAck() {
CallDoDeferredUpdate();
}
+void RenderWidget::OnCreateVideoAck(int32 video_id) {
+ // TODO(scherkus): handle CreateVideo_ACK with a message filter.
+}
+
+void RenderWidget::OnUpdateVideoAck(int32 video_id) {
+ // TODO(scherkus): handle UpdateVideo_ACK with a message filter.
+}
+
void RenderWidget::OnHandleInputEvent(const IPC::Message& message) {
void* iter = NULL;
diff --git a/chrome/renderer/render_widget.h b/chrome/renderer/render_widget.h
index 571ca8b..feb3efe 100644
--- a/chrome/renderer/render_widget.h
+++ b/chrome/renderer/render_widget.h
@@ -151,6 +151,8 @@ class RenderWidget : public IPC::Channel::Listener,
virtual void OnWasHidden();
virtual void OnWasRestored(bool needs_repainting);
void OnUpdateRectAck();
+ void OnCreateVideoAck(int32 video_id);
+ void OnUpdateVideoAck(int32 video_id);
void OnRequestMoveAck();
void OnHandleInputEvent(const IPC::Message& message);
void OnMouseCaptureLost();