diff options
33 files changed, 785 insertions, 37 deletions
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc index 73148c8..793abd4 100644 --- a/chrome/browser/renderer_host/browser_render_process_host.cc +++ b/chrome/browser/renderer_host/browser_render_process_host.cc @@ -541,6 +541,7 @@ void BrowserRenderProcessHost::PropagateBrowserCommandLineToRenderer( switches::kEnableGeolocation, switches::kShowPaintRects, switches::kEnableOpenMax, + switches::kEnableVideoLayering, // We propagate the Chrome Frame command line here as well in case the // renderer is not run in the sandbox. switches::kChromeFrame, diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc index ec43fe9..b54fb96 100644 --- a/chrome/browser/renderer_host/render_widget_host.cc +++ b/chrome/browser/renderer_host/render_widget_host.cc @@ -14,6 +14,7 @@ #include "chrome/browser/renderer_host/render_widget_helper.h" #include "chrome/browser/renderer_host/render_widget_host_painting_observer.h" #include "chrome/browser/renderer_host/render_widget_host_view.h" +#include "chrome/browser/renderer_host/video_layer.h" #include "chrome/common/notification_service.h" #include "chrome/common/render_messages.h" #include "webkit/glue/webcursor.h" @@ -127,6 +128,9 @@ void RenderWidgetHost::OnMessageReceived(const IPC::Message &msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_Close, OnMsgClose) IPC_MESSAGE_HANDLER(ViewHostMsg_RequestMove, OnMsgRequestMove) IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateRect, OnMsgUpdateRect) + IPC_MESSAGE_HANDLER(ViewHostMsg_CreateVideo, OnMsgCreateVideo) + IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateVideo, OnMsgUpdateVideo) + IPC_MESSAGE_HANDLER(ViewHostMsg_DestroyVideo, OnMsgDestroyVideo) IPC_MESSAGE_HANDLER(ViewHostMsg_HandleInputEvent_ACK, OnMsgInputEventAck) IPC_MESSAGE_HANDLER(ViewHostMsg_Focus, OnMsgFocus) IPC_MESSAGE_HANDLER(ViewHostMsg_Blur, OnMsgBlur) @@ -769,6 +773,27 @@ void RenderWidgetHost::OnMsgUpdateRect( UMA_HISTOGRAM_TIMES("MPArch.RWH_OnMsgUpdateRect", delta); } +void RenderWidgetHost::OnMsgCreateVideo(const gfx::Size& size) { + DCHECK(!video_layer_.get()); + + video_layer_.reset(view_->AllocVideoLayer(size)); + + // TODO(scherkus): support actual video ids! + Send(new ViewMsg_CreateVideo_ACK(routing_id_, -1)); +} + +void RenderWidgetHost::OnMsgUpdateVideo(TransportDIB::Id bitmap, + const gfx::Rect& bitmap_rect) { + PaintVideoLayer(bitmap, bitmap_rect); + + // TODO(scherkus): support actual video ids! + Send(new ViewMsg_UpdateVideo_ACK(routing_id_, -1)); +} + +void RenderWidgetHost::OnMsgDestroyVideo() { + video_layer_.reset(); +} + void RenderWidgetHost::OnMsgInputEventAck(const IPC::Message& message) { // Log the time delta for processing an input event. TimeDelta delta = TimeTicks::Now() - input_event_start_time_; @@ -987,6 +1012,26 @@ void RenderWidgetHost::ScrollBackingStoreRect(int dx, int dy, backing_store->ScrollBackingStore(dx, dy, clip_rect, view_size); } +void RenderWidgetHost::PaintVideoLayer(TransportDIB::Id bitmap, + const gfx::Rect& bitmap_rect) { + if (is_hidden_ || !video_layer_.get()) + return; + + video_layer_->CopyTransportDIB(process(), bitmap, bitmap_rect); + + // Don't update the view if we're hidden or if the view has been destroyed. + if (is_hidden_ || !view_) + return; + + // Trigger a paint for the updated video layer bitmap. + std::vector<gfx::Rect> copy_rects; + copy_rects.push_back(bitmap_rect); + + view_being_painted_ = true; + view_->DidPaintBackingStoreRects(copy_rects); + view_being_painted_ = false; +} + void RenderWidgetHost::ToggleSpellPanel(bool is_currently_visible) { Send(new ViewMsg_ToggleSpellPanel(routing_id(), is_currently_visible)); } diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h index e96eae7..f1b402e 100644 --- a/chrome/browser/renderer_host/render_widget_host.h +++ b/chrome/browser/renderer_host/render_widget_host.h @@ -38,6 +38,7 @@ class RenderProcessHost; class RenderWidgetHostView; class RenderWidgetHostPaintingObserver; class TransportDIB; +class VideoLayer; class WebCursor; struct ViewHostMsg_ShowPopup_Params; struct ViewHostMsg_UpdateRect_Params; @@ -220,6 +221,9 @@ class RenderWidgetHost : public IPC::Channel::Listener, // renderer to send another paint. void DonePaintingToBackingStore(); + // Returns the video layer if it exists, NULL otherwise. + VideoLayer* const video_layer() { return video_layer_.get(); } + // Checks to see if we can give up focus to this widget through a JS call. virtual bool CanBlur() const { return true; } @@ -427,6 +431,9 @@ class RenderWidgetHost : public IPC::Channel::Listener, void OnMsgClose(); void OnMsgRequestMove(const gfx::Rect& pos); void OnMsgUpdateRect(const ViewHostMsg_UpdateRect_Params& params); + void OnMsgCreateVideo(const gfx::Size& size); + void OnMsgUpdateVideo(TransportDIB::Id bitmap, const gfx::Rect& bitmap_rect); + void OnMsgDestroyVideo(); void OnMsgInputEventAck(const IPC::Message& message); void OnMsgFocus(); void OnMsgBlur(); @@ -476,6 +483,12 @@ class RenderWidgetHost : public IPC::Channel::Listener, void ScrollBackingStoreRect(int dx, int dy, const gfx::Rect& clip_rect, const gfx::Size& view_size); + // Paints the entire given bitmap into the current video layer, if it exists. + // |bitmap_rect| specifies the destination size and absolute location of the + // bitmap on the backing store. + void PaintVideoLayer(TransportDIB::Id bitmap, + const gfx::Rect& bitmap_rect); + // Called by OnMsgInputEventAck() to process a keyboard event ack message. void ProcessKeyboardEventAck(int type, bool processed); @@ -613,6 +626,9 @@ class RenderWidgetHost : public IPC::Channel::Listener, // changed. bool suppress_next_char_events_; + // Optional video YUV layer for used for out-of-process compositing. + scoped_ptr<VideoLayer> video_layer_; + DISALLOW_COPY_AND_ASSIGN(RenderWidgetHost); }; diff --git a/chrome/browser/renderer_host/render_widget_host_view.h b/chrome/browser/renderer_host/render_widget_host_view.h index f6f8788..339c6aa 100644 --- a/chrome/browser/renderer_host/render_widget_host_view.h +++ b/chrome/browser/renderer_host/render_widget_host_view.h @@ -26,6 +26,7 @@ class Message; class BackingStore; class RenderProcessHost; class RenderWidgetHost; +class VideoLayer; class WebCursor; struct WebMenuItem; @@ -153,6 +154,9 @@ class RenderWidgetHostView { // Allocate a backing store for this view virtual BackingStore* AllocBackingStore(const gfx::Size& size) = 0; + // Allocate a video layer for this view. + virtual VideoLayer* AllocVideoLayer(const gfx::Size& size) = 0; + #if defined(OS_MACOSX) // Display a native control popup menu for WebKit. virtual void ShowPopupWithItems(gfx::Rect bounds, diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc index e237071..338e960 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.cc @@ -30,6 +30,7 @@ #include "chrome/browser/renderer_host/gtk_im_context_wrapper.h" #include "chrome/browser/renderer_host/gtk_key_bindings_handler.h" #include "chrome/browser/renderer_host/render_widget_host.h" +#include "chrome/browser/renderer_host/video_layer_x.h" #include "chrome/common/gtk_util.h" #include "chrome/common/native_web_keyboard_event.h" #include "chrome/common/x11_util.h" @@ -635,6 +636,17 @@ BackingStore* RenderWidgetHostViewGtk::AllocBackingStore( gtk_widget_get_visual(view_.get())->depth); } +VideoLayer* RenderWidgetHostViewGtk::AllocVideoLayer(const gfx::Size& size) { + if (kUseGPURendering) { + NOTIMPLEMENTED(); + return NULL; + } + + return new VideoLayerX(host_, size, + x11_util::GetVisualFromGtkWidget(view_.get()), + gtk_widget_get_visual(view_.get())->depth); +} + void RenderWidgetHostViewGtk::SetBackground(const SkBitmap& background) { RenderWidgetHostView::SetBackground(background); host_->Send(new ViewMsg_SetBackground(host_->routing_id(), background)); @@ -675,6 +687,14 @@ void RenderWidgetHostViewGtk::Paint(const gfx::Rect& damage_rect) { // we don't need to double buffer. backing_store->XShowRect( paint_rect, x11_util::GetX11WindowFromGtkWidget(view_.get())); + + // Paint the video layer using XCopyArea. + // TODO(scherkus): implement VideoLayerX::CairoShow() for grey + // blending. + VideoLayerX* video_layer = static_cast<VideoLayerX*>( + host_->video_layer()); + if (video_layer) + video_layer->XShow(x11_util::GetX11WindowFromGtkWidget(view_.get())); } else { // If the grey blend is showing, we make two drawing calls. Use double // buffering to prevent flicker. Use CairoShowRect because XShowRect diff --git a/chrome/browser/renderer_host/render_widget_host_view_gtk.h b/chrome/browser/renderer_host/render_widget_host_view_gtk.h index d17743a..974a4eb 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_gtk.h +++ b/chrome/browser/renderer_host/render_widget_host_view_gtk.h @@ -68,6 +68,7 @@ class RenderWidgetHostViewGtk : public RenderWidgetHostView { virtual void SelectionChanged(const std::string& text); virtual void ShowingContextMenu(bool showing); virtual BackingStore* AllocBackingStore(const gfx::Size& size); + virtual VideoLayer* AllocVideoLayer(const gfx::Size& size); virtual void SetBackground(const SkBitmap& background); virtual void CreatePluginContainer(gfx::PluginWindowHandle id); virtual void DestroyPluginContainer(gfx::PluginWindowHandle id); diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h index db0c381..f9d0c92 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -105,6 +105,7 @@ class RenderWidgetHostViewMac : public RenderWidgetHostView { virtual void Destroy(); virtual void SetTooltipText(const std::wstring& tooltip_text); virtual BackingStore* AllocBackingStore(const gfx::Size& size); + virtual VideoLayer* AllocVideoLayer(const gfx::Size& size); virtual void ShowPopupWithItems(gfx::Rect bounds, int item_height, int selected_item, diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.mm b/chrome/browser/renderer_host/render_widget_host_view_mac.mm index 79beb00..1f19167 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.mm +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.mm @@ -425,6 +425,12 @@ BackingStore* RenderWidgetHostViewMac::AllocBackingStore( return new BackingStoreMac(render_widget_host_, size); } +VideoLayer* RenderWidgetHostViewMac::AllocVideoLayer( + const gfx::Size& size) { + NOTIMPLEMENTED(); + return NULL; +} + // Display a popup menu for WebKit using Cocoa widgets. void RenderWidgetHostViewMac::ShowPopupWithItems( gfx::Rect bounds, diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.cc b/chrome/browser/renderer_host/render_widget_host_view_win.cc index 8e2ae47..923eab3 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.cc +++ b/chrome/browser/renderer_host/render_widget_host_view_win.cc @@ -751,6 +751,12 @@ BackingStore* RenderWidgetHostViewWin::AllocBackingStore( return new BackingStoreWin(render_widget_host_, size); } +VideoLayer* RenderWidgetHostViewWin::AllocVideoLayer( + const gfx::Size& size) { + NOTIMPLEMENTED(); + return NULL; +} + void RenderWidgetHostViewWin::SetBackground(const SkBitmap& background) { RenderWidgetHostView::SetBackground(background); Send(new ViewMsg_SetBackground(render_widget_host_->routing_id(), diff --git a/chrome/browser/renderer_host/render_widget_host_view_win.h b/chrome/browser/renderer_host/render_widget_host_view_win.h index 881b425..f43dd0f 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_win.h +++ b/chrome/browser/renderer_host/render_widget_host_view_win.h @@ -136,6 +136,7 @@ class RenderWidgetHostViewWin virtual void Destroy(); virtual void SetTooltipText(const std::wstring& tooltip_text); virtual BackingStore* AllocBackingStore(const gfx::Size& size); + virtual VideoLayer* AllocVideoLayer(const gfx::Size& size); virtual void SetBackground(const SkBitmap& background); virtual bool ContainsNativeView(gfx::NativeView native_view) const; virtual void SetVisuallyDeemphasized(bool deemphasized); diff --git a/chrome/browser/renderer_host/test/test_render_view_host.cc b/chrome/browser/renderer_host/test/test_render_view_host.cc index 91b7b914..1269c7b 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.cc +++ b/chrome/browser/renderer_host/test/test_render_view_host.cc @@ -79,6 +79,12 @@ BackingStore* TestRenderWidgetHostView::AllocBackingStore( return new TestBackingStore(rwh_, size); } +VideoLayer* TestRenderWidgetHostView::AllocVideoLayer( + const gfx::Size& size) { + NOTIMPLEMENTED(); + return NULL; +} + #if defined(OS_MACOSX) gfx::Rect TestRenderWidgetHostView::GetWindowRect() { return gfx::Rect(); diff --git a/chrome/browser/renderer_host/test/test_render_view_host.h b/chrome/browser/renderer_host/test/test_render_view_host.h index fbeb388..2d8025b 100644 --- a/chrome/browser/renderer_host/test/test_render_view_host.h +++ b/chrome/browser/renderer_host/test/test_render_view_host.h @@ -69,6 +69,7 @@ class TestRenderWidgetHostView : public RenderWidgetHostView { virtual void PrepareToDestroy() {} virtual void SetTooltipText(const std::wstring& tooltip_text) {} virtual BackingStore* AllocBackingStore(const gfx::Size& size); + virtual VideoLayer* AllocVideoLayer(const gfx::Size& size); #if defined(OS_MACOSX) virtual void ShowPopupWithItems(gfx::Rect bounds, int item_height, diff --git a/chrome/browser/renderer_host/video_layer.cc b/chrome/browser/renderer_host/video_layer.cc new file mode 100644 index 0000000..1555060 --- /dev/null +++ b/chrome/browser/renderer_host/video_layer.cc @@ -0,0 +1,13 @@ +// 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/browser/renderer_host/video_layer.h" + +VideoLayer::VideoLayer(RenderWidgetHost* widget, const gfx::Size& size) + : render_widget_host_(widget), + size_(size) { +} + +VideoLayer::~VideoLayer() { +} diff --git a/chrome/browser/renderer_host/video_layer.h b/chrome/browser/renderer_host/video_layer.h new file mode 100644 index 0000000..66a084f --- /dev/null +++ b/chrome/browser/renderer_host/video_layer.h @@ -0,0 +1,51 @@ +// 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. + +#ifndef CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_H_ +#define CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_H_ + +#include "base/gfx/size.h" +#include "base/scoped_ptr.h" +#include "chrome/common/transport_dib.h" + +class RenderProcessHost; +class RenderWidgetHost; + +namespace gfx { +class Rect; +} + +// Represents a layer of YUV data owned by RenderWidgetHost and composited with +// the backing store. VideoLayer is responsible for converting to RGB as +// needed. +class VideoLayer { + public: + virtual ~VideoLayer(); + + RenderWidgetHost* render_widget_host() const { return render_widget_host_; } + const gfx::Size& size() { return size_; } + + // Copy the incoming bitmap into this video layer. |bitmap| contains YUV + // pixel data in YV12 format and must be the same dimensions as this video + // layer. |bitmap_rect| specifies the absolute position and destination size + // of the bitmap on the backing store. + virtual void CopyTransportDIB(RenderProcessHost* process, + TransportDIB::Id bitmap, + const gfx::Rect& bitmap_rect) = 0; + + protected: + // Can only be constructed via subclasses. + VideoLayer(RenderWidgetHost* widget, const gfx::Size& size); + + private: + // The owner of this video layer. + RenderWidgetHost* render_widget_host_; + + // The size of the video layer. + gfx::Size size_; + + DISALLOW_COPY_AND_ASSIGN(VideoLayer); +}; + +#endif // CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_H_ diff --git a/chrome/browser/renderer_host/video_layer_x.cc b/chrome/browser/renderer_host/video_layer_x.cc new file mode 100644 index 0000000..ddd2c21 --- /dev/null +++ b/chrome/browser/renderer_host/video_layer_x.cc @@ -0,0 +1,101 @@ +// 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/browser/renderer_host/video_layer_x.h" + +#include "chrome/browser/renderer_host/render_process_host.h" +#include "chrome/common/x11_util_internal.h" +#include "media/base/yuv_convert.h" + +VideoLayerX::VideoLayerX(RenderWidgetHost* widget, + const gfx::Size& size, + void* visual, + int depth) + : VideoLayer(widget, size), + visual_(visual), + depth_(depth), + display_(x11_util::GetXDisplay()) { + DCHECK(!size.IsEmpty()); + + // Create our pixmap + GC representing an RGB version of a video frame. + pixmap_ = XCreatePixmap(display_, x11_util::GetX11RootWindow(), + size.width(), size.height(), depth_); + pixmap_gc_ = XCreateGC(display_, pixmap_, 0, NULL); + pixmap_bpp_ = x11_util::BitsPerPixelForPixmapDepth(display_, depth_); +} + +VideoLayerX::~VideoLayerX() { + // In unit tests, |display_| may be NULL. + if (!display_) + return; + + XFreePixmap(display_, pixmap_); + XFreeGC(display_, static_cast<GC>(pixmap_gc_)); +} + +void VideoLayerX::CopyTransportDIB(RenderProcessHost* process, + TransportDIB::Id bitmap, + const gfx::Rect& bitmap_rect) { + if (!display_) + return; + + if (bitmap_rect.IsEmpty()) + return; + + if (bitmap_rect.size() != size()) { + LOG(ERROR) << "Scaled video layer not supported."; + return; + } + + // Save location and size of destination bitmap. + rgb_rect_ = bitmap_rect; + + // Lazy allocate |rgb_frame_|. + if (!rgb_frame_.get()) { + // TODO(scherkus): handle changing dimensions and re-allocating. + CHECK(size() == rgb_rect_.size()); + + rgb_frame_.reset(new uint8[rgb_rect_.width() * rgb_rect_.height() * 4]); + } + + const int width = bitmap_rect.width(); + const int height = bitmap_rect.height(); + // Assume that somewhere along the line, someone will do width * height * 4 + // with signed numbers. If the maximum value is 2**31, then 2**31 / 4 = + // 2**29 and floor(sqrt(2**29)) = 23170. + if (width > 23170 || height > 23170) + return; + + TransportDIB* dib = process->GetTransportDIB(bitmap); + if (!dib) + return; + + // Perform colour space conversion. + const uint8* y_plane = reinterpret_cast<uint8*>(dib->memory()); + const uint8* u_plane = y_plane + width * height; + const uint8* v_plane = u_plane + ((width * height) >> 2); + media::ConvertYUVToRGB32(y_plane, + u_plane, + v_plane, + rgb_frame_.get(), + width, + height, + width, + width / 2, + width * 4, + media::YV12); + + // Draw ARGB frame onto our pixmap. + x11_util::PutARGBImage(display_, visual_, depth_, pixmap_, pixmap_gc_, + rgb_frame_.get(), width, height); +} + +void VideoLayerX::XShow(XID target) { + if (rgb_rect_.IsEmpty()) + return; + + XCopyArea(display_, pixmap_, target, static_cast<GC>(pixmap_gc_), + 0, 0, rgb_rect_.width(), rgb_rect_.height(), + rgb_rect_.x(), rgb_rect_.y()); +} diff --git a/chrome/browser/renderer_host/video_layer_x.h b/chrome/browser/renderer_host/video_layer_x.h new file mode 100644 index 0000000..fbe45cc --- /dev/null +++ b/chrome/browser/renderer_host/video_layer_x.h @@ -0,0 +1,50 @@ +// 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. + +#ifndef CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_X_ +#define CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_X_ + +#include "chrome/browser/renderer_host/video_layer.h" +#include "chrome/common/x11_util.h" + +// Implements a YUV data layer using X to hold the RGB data. +class VideoLayerX : public VideoLayer { + public: + VideoLayerX(RenderWidgetHost* widget, const gfx::Size& size, void* visual, + int depth); + virtual ~VideoLayerX(); + + virtual void CopyTransportDIB(RenderProcessHost* process, + TransportDIB::Id bitmap, + const gfx::Rect& bitmap_rect); + + // Copy from the server-side video layer to the target window. + // Unlike BackingStore, we maintain the absolute position and destination + // size so passing in a rect is not required. + void XShow(XID target); + + private: + // X Visual to get RGB mask information. + void* const visual_; + // Depth of the target window. + int depth_; + // Connection to the X server where this video layer will be displayed. + Display* const display_; + + // Handle to the server side pixmap which is our video layer. + XID pixmap_; + // Graphics context for painting our video layer. + void* pixmap_gc_; + // Server side bits-per-pixel for |pixmap_|. + int pixmap_bpp_; + + // Most recently converted frame stored as 32-bit ARGB. + scoped_array<uint8> rgb_frame_; + // Destination size and absolution position of the converted frame. + gfx::Rect rgb_rect_; + + DISALLOW_COPY_AND_ASSIGN(VideoLayerX); +}; + +#endif // CHROME_BROWSER_RENDERER_HOST_VIDEO_LAYER_X_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 0616843..461fa04 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1649,8 +1649,12 @@ 'browser/renderer_host/socket_stream_host.h', 'browser/renderer_host/sync_resource_handler.cc', 'browser/renderer_host/sync_resource_handler.h', - 'browser/renderer_host/translation_service.h', 'browser/renderer_host/translation_service.cc', + 'browser/renderer_host/translation_service.h', + 'browser/renderer_host/video_layer.cc', + 'browser/renderer_host/video_layer.h', + 'browser/renderer_host/video_layer_x.cc', + 'browser/renderer_host/video_layer_x.h', 'browser/renderer_host/web_cache_manager.cc', 'browser/renderer_host/web_cache_manager.h', 'browser/renderer_host/x509_user_cert_resource_handler.cc', diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index 155c8d2..7acf628 100755 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -59,6 +59,8 @@ 'renderer/loadtimes_extension_bindings.cc', 'renderer/media/audio_renderer_impl.cc', 'renderer/media/audio_renderer_impl.h', + 'renderer/media/ipc_video_renderer.cc', + 'renderer/media/ipc_video_renderer.h', 'renderer/net/render_dns_master.cc', 'renderer/net/render_dns_master.h', 'renderer/net/render_dns_queue.cc', diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 29e22c4..505b07b 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -292,6 +292,10 @@ const char kEnableUserDataDirProfiles[] = "enable-udd-profiles"; // browser window. const char kEnableVerticalTabs[] = "enable-vertical-tabs"; +// Enables video layering where video is rendered as a separate layer outside +// of the backing store. +const char kEnableVideoLayering[] = "enable-video-layering"; + // Spawn threads to watch for excessive delays in specified message loops. // User should set breakpoints on Alarm() to examine problematic thread. // Usage: -enable-watchdog=[ui][io] diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 5ab8178..9af1ec9 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -101,6 +101,7 @@ extern const char kEnableSyncBookmarks[]; extern const char kEnableSyncPreferences[]; extern const char kEnableUserDataDirProfiles[]; extern const char kEnableVerticalTabs[]; +extern const char kEnableVideoLayering[]; extern const char kEnableWatchdog[]; extern const char kExperimentalSpellcheckerFeatures[]; extern const char kExplicitlyAllowedPorts[]; diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index be83c9a8..bc8aefe 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -143,6 +143,12 @@ IPC_BEGIN_MESSAGES(View) // This signals the render view that it can send another UpdateRect message. IPC_MESSAGE_ROUTED0(ViewMsg_UpdateRect_ACK) + // Replies to creating and updating videos. + IPC_MESSAGE_ROUTED1(ViewMsg_CreateVideo_ACK, + int32 /* video_id */) + IPC_MESSAGE_ROUTED1(ViewMsg_UpdateVideo_ACK, + int32 /* video_id */) + // Message payload includes: // 1. A blob that should be cast to WebInputEvent // 2. An optional boolean value indicating if a RawKeyDown event is associated @@ -1091,6 +1097,14 @@ IPC_BEGIN_MESSAGES(ViewHost) IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateRect, ViewHostMsg_UpdateRect_Params) + // Sent to create, update and destroy video layers. + IPC_MESSAGE_ROUTED1(ViewHostMsg_CreateVideo, + gfx::Size /* size */) + IPC_MESSAGE_ROUTED2(ViewHostMsg_UpdateVideo, + TransportDIB::Id /* bitmap */, + gfx::Rect /* bitmap_rect */) + IPC_MESSAGE_ROUTED0(ViewHostMsg_DestroyVideo) + // Acknowledges receipt of a ViewMsg_HandleInputEvent message. // Payload is a WebInputEvent::Type which is the type of the event, followed // by an optional WebInputEvent which is provided only if the event was not 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(); diff --git a/webkit/glue/media/video_renderer_impl.cc b/webkit/glue/media/video_renderer_impl.cc index a7dc980..ba06d1c 100644 --- a/webkit/glue/media/video_renderer_impl.cc +++ b/webkit/glue/media/video_renderer_impl.cc @@ -18,6 +18,13 @@ namespace webkit_glue { } // static +media::FilterFactory* VideoRendererImpl::CreateFactory( + WebMediaPlayerImpl::Proxy* proxy) { + return new media::FilterFactoryImpl1<VideoRendererImpl, + WebMediaPlayerImpl::Proxy*>(proxy); +} + +// static bool VideoRendererImpl::IsMediaFormatSupported( const media::MediaFormat& media_format) { int width = 0; diff --git a/webkit/glue/media/video_renderer_impl.h b/webkit/glue/media/video_renderer_impl.h index b0fde12..4bc7210 100644 --- a/webkit/glue/media/video_renderer_impl.h +++ b/webkit/glue/media/video_renderer_impl.h @@ -6,10 +6,6 @@ // inside video renderer thread and also WebKit's main thread. We need to be // extra careful about members shared by two different threads, especially // video frame buffers. -// -// Methods called from WebKit's main thread: -// Paint() -// SetRect() #ifndef WEBKIT_GLUE_MEDIA_VIDEO_RENDERER_IMPL_H_ #define WEBKIT_GLUE_MEDIA_VIDEO_RENDERER_IMPL_H_ @@ -17,38 +13,41 @@ #include "base/gfx/rect.h" #include "base/gfx/size.h" #include "media/base/buffers.h" -#include "media/base/factory.h" #include "media/base/filters.h" #include "media/filters/video_renderer_base.h" #include "skia/ext/platform_canvas.h" #include "third_party/WebKit/WebKit/chromium/public/WebMediaPlayer.h" +#include "webkit/glue/media/web_video_renderer.h" #include "webkit/glue/webmediaplayer_impl.h" namespace webkit_glue { -class VideoRendererImpl : public media::VideoRendererBase { +class VideoRendererImpl : public WebVideoRenderer { public: - // 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 + - // scale code on a separate thread. Since we always do the stretch on the - // same thread as the Paint method, we just ignore the call for now. + // WebVideoRenderer implementation. virtual void SetRect(const gfx::Rect& rect); - - // Paint the current front frame on the |canvas| stretching it to fit the - // |dest_rect| virtual void Paint(skia::PlatformCanvas* canvas, const gfx::Rect& dest_rect); // Static method for creating factory for this object. - static media::FilterFactory* CreateFactory(WebMediaPlayerImpl::Proxy* proxy) { - return new media::FilterFactoryImpl1<VideoRendererImpl, - WebMediaPlayerImpl::Proxy*>(proxy); - } + static media::FilterFactory* CreateFactory(WebMediaPlayerImpl::Proxy* proxy); // FilterFactoryImpl1 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() : webkit_glue::WebVideoRendererFactoryFactory() {} + + virtual media::FilterFactory* CreateFactory( + webkit_glue::WebMediaPlayerImpl::Proxy* proxy) { + return VideoRendererImpl::CreateFactory(proxy); + } + + private: + DISALLOW_COPY_AND_ASSIGN(FactoryFactory); + }; + protected: // Method called by VideoRendererBase during initialization. virtual bool OnInitialize(media::VideoDecoder* decoder); diff --git a/webkit/glue/media/web_video_renderer.h b/webkit/glue/media/web_video_renderer.h new file mode 100644 index 0000000..8bafb1a --- /dev/null +++ b/webkit/glue/media/web_video_renderer.h @@ -0,0 +1,39 @@ +// 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. + +#ifndef WEBKIT_GLUE_MEDIA_WEB_VIDEO_RENDERER_H_ +#define WEBKIT_GLUE_MEDIA_WEB_VIDEO_RENDERER_H_ + +#include "media/filters/video_renderer_base.h" + +namespace webkit_glue { + +// A specialized version of a VideoRenderer designed to be used inside WebKit. +class WebVideoRenderer : public media::VideoRendererBase { + public: + WebVideoRenderer() : media::VideoRendererBase() {} + virtual ~WebVideoRenderer() {} + + // 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 + + // scale code on a separate thread. Since we always do the stretch on the + // same thread as the Paint method, we just ignore the call for now. + // + // Method called on the render thread. + virtual void SetRect(const gfx::Rect& rect) = 0; + + // Paint the current front frame on the |canvas| stretching it to fit the + // |dest_rect|. + // + // Method called on the render thread. + virtual void Paint(skia::PlatformCanvas* canvas, + const gfx::Rect& dest_rect) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(WebVideoRenderer); +}; + +} // namespace webkit_glue + +#endif // WEBKIT_GLUE_MEDIA_WEB_VIDEO_RENDERER_H_ diff --git a/webkit/glue/webmediaplayer_impl.cc b/webkit/glue/webmediaplayer_impl.cc index da4339a..8dd46b5 100644 --- a/webkit/glue/webmediaplayer_impl.cc +++ b/webkit/glue/webmediaplayer_impl.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2008-2009 The Chromium Authors. All rights reserved. +// 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. @@ -18,6 +18,7 @@ #include "third_party/WebKit/WebKit/chromium/public/WebSize.h" #include "third_party/WebKit/WebKit/chromium/public/WebURL.h" #include "webkit/glue/media/video_renderer_impl.h" +#include "webkit/glue/media/web_video_renderer.h" using WebKit::WebCanvas; using WebKit::WebRect; @@ -80,7 +81,7 @@ void WebMediaPlayerImpl::Proxy::Repaint() { } void WebMediaPlayerImpl::Proxy::SetVideoRenderer( - VideoRendererImpl* video_renderer) { + WebVideoRenderer* video_renderer) { video_renderer_ = video_renderer; } @@ -181,7 +182,9 @@ void WebMediaPlayerImpl::Proxy::NetworkEventTask() { // WebMediaPlayerImpl implementation WebMediaPlayerImpl::WebMediaPlayerImpl(WebKit::WebMediaPlayerClient* client, - media::FilterFactoryCollection* factory) + media::FilterFactoryCollection* factory, + WebVideoRendererFactoryFactory* + video_renderer_factory) : network_state_(WebKit::WebMediaPlayer::Empty), ready_state_(WebKit::WebMediaPlayer::HaveNothing), main_loop_(NULL), @@ -194,6 +197,10 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(WebKit::WebMediaPlayerClient* client, DCHECK(!main_loop_); main_loop_ = MessageLoop::current(); + // Make sure this gets deleted. + scoped_ptr<WebVideoRendererFactoryFactory> + scoped_video_renderer_factory(video_renderer_factory); + // Create the pipeline and its thread. if (!pipeline_thread_.Start()) { NOTREACHED() << "Could not start PipelineThread"; @@ -225,7 +232,7 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(WebKit::WebMediaPlayerClient* client, } filter_factory_->AddFactory(media::FFmpegVideoDecoder::CreateFactory()); filter_factory_->AddFactory(media::NullAudioRenderer::CreateFilterFactory()); - filter_factory_->AddFactory(VideoRendererImpl::CreateFactory(proxy_)); + filter_factory_->AddFactory(video_renderer_factory->CreateFactory(proxy_)); } WebMediaPlayerImpl::~WebMediaPlayerImpl() { diff --git a/webkit/glue/webmediaplayer_impl.h b/webkit/glue/webmediaplayer_impl.h index 7e2d8b2..b44cc62 100644 --- a/webkit/glue/webmediaplayer_impl.h +++ b/webkit/glue/webmediaplayer_impl.h @@ -1,7 +1,7 @@ -// Copyright (c) 2008-2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be found -// in the LICENSE file. -// +// 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. + // Delegate calls from WebCore::MediaPlayerPrivate to Chrome's video player. // It contains PipelineImpl which is the actual media player pipeline, it glues // the media player pipeline, data source, audio renderer and renderer. @@ -14,7 +14,7 @@ // media::PipelineImpl // The media playback pipeline. // -// VideoRendererImpl +// WebVideoRenderer // Video renderer object. // // WebMediaPlayerImpl::Proxy @@ -29,7 +29,7 @@ // WebMediaPlayerImpl ------> PipelineImpl // | ^ | r // | | v -// | | VideoRendererImpl +// | | WebVideoRenderer // | | ^ r // | | | // | r | r | @@ -39,7 +39,7 @@ // v // WebMediaPlayerClient // -// Notice that Proxy and VideoRendererImpl are referencing each other. This +// Notice that Proxy and WebVideoRenderer are referencing each other. This // interdependency has to be treated carefully. // // Other issues: @@ -60,6 +60,7 @@ #include "base/lock.h" #include "base/message_loop.h" #include "base/ref_counted.h" +#include "ipc/ipc_message.h" #include "media/base/filters.h" #include "media/base/pipeline_impl.h" #include "skia/ext/platform_canvas.h" @@ -74,7 +75,8 @@ class FilterFactoryCollection; namespace webkit_glue { -class VideoRendererImpl; +class WebVideoRenderer; +class WebVideoRendererFactoryFactory; class WebMediaPlayerImpl : public WebKit::WebMediaPlayer, public MessageLoop::DestructionObserver { @@ -94,7 +96,7 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer, // Public methods called from the video renderer. void Repaint(); - void SetVideoRenderer(VideoRendererImpl* video_renderer); + void SetVideoRenderer(WebVideoRenderer* video_renderer); // Public methods called from WebMediaPlayerImpl. void Paint(skia::PlatformCanvas* canvas, const gfx::Rect& dest_rect); @@ -109,6 +111,9 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer, void PipelineErrorCallback(); void NetworkEventCallback(); + // Returns the message loop used by the proxy. + MessageLoop* message_loop() { return render_loop_; } + private: friend class base::RefCountedThreadSafe<Proxy>; @@ -135,7 +140,7 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer, // The render message loop where WebKit lives. MessageLoop* render_loop_; WebMediaPlayerImpl* webmediaplayer_; - scoped_refptr<VideoRendererImpl> video_renderer_; + scoped_refptr<WebVideoRenderer> video_renderer_; Lock lock_; int outstanding_repaints_; @@ -161,8 +166,12 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer, // audio renderer is a fake audio device that plays silence. Provider of the // |factory| can override the default filters by adding extra filters to // |factory| before calling this method. + // + // |video_renderer_factory| is used to construct a factory that should create + // a subclass of WebVideoRenderer. Is deleted by WebMediaPlayerImpl. WebMediaPlayerImpl(WebKit::WebMediaPlayerClient* client, - media::FilterFactoryCollection* factory); + media::FilterFactoryCollection* factory, + WebVideoRendererFactoryFactory* video_renderer_factory); virtual ~WebMediaPlayerImpl(); virtual void load(const WebKit::WebURL& url); @@ -295,6 +304,29 @@ class WebMediaPlayerImpl : public WebKit::WebMediaPlayer, DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl); }; +// TODO(scherkus): WebMediaPlayerImpl creates and injects its Proxy into a +// video renderer factory, so we need to (unfortunately) have a factory of a +// factory so we can receive the proxy pointer without violating the +// separation of renderer code from webkit glue code. This is part of a +// longer-term plan to rethink our FilterFactory strategy (refer to +// http://crbug.com/28207). +// +// Either that or we rethink this Proxy business as a short-term solution. +class WebVideoRendererFactoryFactory { + public: + WebVideoRendererFactoryFactory() {} + virtual ~WebVideoRendererFactoryFactory() {} + + // Creates a FilterFactory which should be capable of creating a + // WebVideoRenderer subclass. + virtual media::FilterFactory* CreateFactory( + WebMediaPlayerImpl::Proxy* proxy) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(WebVideoRendererFactoryFactory); +}; + + } // namespace webkit_glue #endif // WEBKIT_GLUE_WEBMEDIAPLAYER_IMPL_H_ diff --git a/webkit/tools/test_shell/test_webview_delegate.cc b/webkit/tools/test_shell/test_webview_delegate.cc index 4c5db40..1cff673 100644 --- a/webkit/tools/test_shell/test_webview_delegate.cc +++ b/webkit/tools/test_shell/test_webview_delegate.cc @@ -44,6 +44,7 @@ #include "webkit/glue/media/buffered_data_source.h" #include "webkit/glue/media/media_resource_loader_bridge_factory.h" #include "webkit/glue/media/simple_data_source.h" +#include "webkit/glue/media/video_renderer_impl.h" #include "webkit/glue/webdropdata.h" #include "webkit/glue/webplugin_impl.h" #include "webkit/glue/webpreferences.h" @@ -667,7 +668,8 @@ WebMediaPlayer* TestWebViewDelegate::createMediaPlayer( bridge_factory); factory->AddFactory(buffered_data_source_factory); factory->AddFactory(simple_data_source_factory); - return new webkit_glue::WebMediaPlayerImpl(client, factory); + return new webkit_glue::WebMediaPlayerImpl( + client, factory, new webkit_glue::VideoRendererImpl::FactoryFactory()); } bool TestWebViewDelegate::allowPlugins(WebFrame* frame, diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index 4c1f9a1..fce94944 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -240,6 +240,7 @@ 'glue/media/simple_data_source.h', 'glue/media/video_renderer_impl.cc', 'glue/media/video_renderer_impl.h', + 'glue/media/web_video_renderer.h', 'glue/plugins/coregraphics_private_symbols_mac.h', 'glue/plugins/nphostapi.h', 'glue/plugins/fake_plugin_window_tracker_mac.h', |