15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implementation notes: This needs to work on a variety of hardware 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// configurations where the speed of the CPU and GPU greatly affect overall 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// performance. Spanning several threads, the process of capturing has been 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// split up into four conceptual stages: 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 1068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// 1. Reserve Buffer: Before a frame can be captured, a slot in the client's 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// shared-memory IPC buffer is reserved. There are only a few of these; 1268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// when they run out, it indicates that the downstream client -- likely a 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// video encoder -- is the performance bottleneck, and that the rate of 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// frame capture should be throttled back. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// 2. Capture: A bitmap is snapshotted/copied from the RenderWidget's backing 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// store. This is initiated on the UI BrowserThread, and often occurs 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// asynchronously. Where supported, the GPU scales and color converts 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// frames to our desired size, and the readback happens directly into the 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// shared-memory buffer. But this is not always possible, particularly when 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// accelerated compositing is disabled. 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3. Render (if needed): If the web contents cannot be captured directly into 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// our target size and color format, scaling and colorspace conversion must 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// be done on the CPU. A dedicated thread is used for this operation, to 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// avoid blocking the UI thread. The Render stage always reads from a 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// bitmap returned by Capture, and writes into the reserved slot in the 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// shared-memory buffer. 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 3068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// 4. Deliver: The rendered video frame is returned to the client (which 3168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// implements the VideoCaptureDevice::Client interface). Because all 3268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)// paths have written the frame into the IPC buffer, this step should 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// never need to do an additional copy of the pixel data. 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// In the best-performing case, the Render step is bypassed: Capture produces 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ready-to-Deliver frames. But when accelerated readback is not possible, the 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// system is designed so that Capture and Render may run concurrently. A timing 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// diagram helps illustrate this point (@30 FPS): 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Time: 0ms 33ms 66ms 99ms 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread1: |-Capture-f1------v |-Capture-f2------v |-Capture-f3----v |-Capt 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread2: |-Render-f1-----v |-Render-f2-----v |-Render-f3 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In the above example, both capturing and rendering *each* take almost the 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// full 33 ms available between frames, yet we see that the required throughput 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// is obtained. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Turning on verbose logging will cause the effective frame rate to be logged 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// at 5-second intervals. 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/media/capture/web_contents_video_capture_device.h" 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h" 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 55424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "base/callback_helpers.h" 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/weak_ptr.h" 59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/metrics/histogram.h" 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/sequenced_task_runner.h" 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h" 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/thread_checker.h" 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/media/capture/content_video_capture_device_core.h" 66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/media/capture/video_capture_oracle.h" 67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "content/browser/media/capture/web_contents_capture_util.h" 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/browser/media/capture/web_contents_tracker.h" 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/browser/renderer_host/render_widget_host_impl.h" 70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "content/browser/renderer_host/render_widget_host_view_base.h" 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/notification_observer.h" 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/notification_registrar.h" 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_source.h" 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/notification_types.h" 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/render_process_host.h" 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_widget_host_view.h" 78010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "content/public/browser/render_widget_host_view_frame_subscriber.h" 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/web_contents.h" 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/video_util.h" 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/video/capture/video_capture_types.h" 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "skia/ext/image_operations.h" 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h" 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkColor.h" 856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/gfx/display.h" 866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/gfx/geometry/size.h" 876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/gfx/geometry/size_conversions.h" 886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/gfx/screen.h" 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Compute a letterbox region, aligned to even coordinates. 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size, 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Size& content_size) { 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size), 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content_size); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result.set_x(MakeEven(result.x())); 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result.set_y(MakeEven(result.y())); 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result.set_width(std::max(kMinFrameWidth, MakeEven(result.width()))); 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) result.set_height(std::max(kMinFrameHeight, MakeEven(result.height()))); 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return result; 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread, 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::Closure& callback) { 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) render_thread.reset(); 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // After thread join call the callback on UI thread. 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 117c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch// Responsible for logging the effective frame rate. 118c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochclass VideoFrameDeliveryLog { 119c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch public: 120c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch VideoFrameDeliveryLog(); 121c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 122c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // Report that the frame posted with |frame_time| has been delivered. 123c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch void ChronicleFrameDelivery(base::TimeTicks frame_time); 124c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 125c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch private: 126c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // The following keep track of and log the effective frame rate whenever 127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch // verbose logging is turned on. 128c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch base::TimeTicks last_frame_rate_log_time_; 129c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch int count_frames_rendered_; 130c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog); 132c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}; 133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch 134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible 135a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// with RenderWidgetHostViewFrameSubscriber. We create one per event type. 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) FrameSubscriber(VideoCaptureOracle::Event event_type, 139c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const scoped_refptr<ThreadSafeCaptureOracle>& oracle, 140c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch VideoFrameDeliveryLog* delivery_log) 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : event_type_(event_type), 142c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch oracle_proxy_(oracle), 143c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch delivery_log_(delivery_log) {} 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual bool ShouldCaptureFrame( 1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const gfx::Rect& damage_rect, 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::TimeTicks present_time, 1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<media::VideoFrame>* storage, 1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* 1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) deliver_frame_cb) OVERRIDE; 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 153a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const VideoCaptureOracle::Event event_type_; 154a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; 155c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch VideoFrameDeliveryLog* const delivery_log_; 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}; 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// ContentCaptureSubscription is the relationship between a RenderWidgetHost 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// whose content is updating, a subscriber that is deciding which of these 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// updates to capture (and where to deliver them to), and a callback that 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// knows how to do the capture and prepare the result for delivery. 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in 1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the RenderWidgetHostView, to process updates that occur via accelerated 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// compositing, (b) installing itself as an observer of updates to the 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// RenderWidgetHost's backing store, to hook updates that occur via software 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// rendering, and (c) running a timer to possibly initiate non-event-driven 1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// captures that the subscriber might request. 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// All of this happens on the UI thread, although the 1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// RenderWidgetHostViewFrameSubscriber we install may be dispatching updates 1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// autonomously on some other thread. 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ContentCaptureSubscription : public content::NotificationObserver { 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public: 1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) typedef base::Callback< 1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void(const base::TimeTicks&, 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const scoped_refptr<media::VideoFrame>&, 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&)> 1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CaptureCallback; 1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Create a subscription. Whenever a manual capture is required, the 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // subscription will invoke |capture_callback| on the UI thread to do the 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // work. 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ContentCaptureSubscription( 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const RenderWidgetHost& source, 186a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, 1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const CaptureCallback& capture_callback); 1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual ~ContentCaptureSubscription(); 1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // content::NotificationObserver implementation. 1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void Observe(int type, 1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const content::NotificationSource& source, 1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const content::NotificationDetails& details) OVERRIDE; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private: 1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void OnTimer(); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Maintain a weak reference to the RenderWidgetHost (via its routing ID), 1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // since the instance could be destroyed externally during the lifetime of 2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // |this|. 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int render_process_id_; 2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const int render_widget_id_; 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 204c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch VideoFrameDeliveryLog delivery_log_; 2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FrameSubscriber paint_subscriber_; 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FrameSubscriber timer_subscriber_; 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content::NotificationRegistrar registrar_; 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CaptureCallback capture_callback_; 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Timer timer_; 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription); 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Render the SkBitmap |input| into the given VideoFrame buffer |output|, then 215c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// invoke |done_cb| to indicate success or failure. |input| is expected to be 216c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// ARGB. |output| must be YV12 or I420. Colorspace conversion is always done. 217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Scaling and letterboxing will be done as needed. 218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// 219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// This software implementation should be used only when GPU acceleration of 220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// these activities is not possible. This operation may be expensive (tens to 221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// hundreds of milliseconds), so the caller should ensure that it runs on a 222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// thread where such a pause would cause UI jank. 223c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void RenderVideoFrame(const SkBitmap& input, 224c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const scoped_refptr<media::VideoFrame>& output, 225c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::Callback<void(bool)>& done_cb); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Renews capture subscriptions based on feedback from WebContentsTracker, and 2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// also executes copying of the backing store on the UI BrowserThread. 2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass WebContentsCaptureMachine : public VideoCaptureMachine { 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch WebContentsCaptureMachine(int render_process_id, int main_render_frame_id); 232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) virtual ~WebContentsCaptureMachine(); 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // VideoCaptureMachine overrides. 235010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) virtual bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, 236010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const media::VideoCaptureParams& params) OVERRIDE; 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual void Stop(const base::Closure& callback) OVERRIDE; 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Starts a copy from the backing store or the composited surface. Must be run 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation 2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // completes. The copy will occur to |target|. 2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // 2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This may be used as a ContentCaptureSubscription::CaptureCallback. 2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void Capture(const base::TimeTicks& start_time, 2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const scoped_refptr<media::VideoFrame>& target, 2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) deliver_frame_cb); 2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool IsStarted() const; 2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 2526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Computes the preferred size of the target RenderWidget for optimal capture. 2536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) gfx::Size ComputeOptimalTargetSize() const; 2546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Response callback for RenderWidgetHost::CopyFromBackingStore(). 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void DidCopyFromBackingStore( 2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::TimeTicks& start_time, 2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const scoped_refptr<media::VideoFrame>& target, 259a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 260a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) deliver_frame_cb, 2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool success, 2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SkBitmap& bitmap); 2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Response callback for RWHVP::CopyFromCompositingSurfaceToVideoFrame(). 2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) void DidCopyFromCompositingSurfaceToVideoFrame( 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::TimeTicks& start_time, 267a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 268a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) deliver_frame_cb, 2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool success); 2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Remove the old subscription, and start a new one if |rwh| is not NULL. 2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci void RenewFrameSubscription(RenderWidgetHost* rwh); 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 274f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Parameters saved in constructor. 275f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const int initial_render_process_id_; 276116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const int initial_main_render_frame_id_; 277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Tracks events and calls back to RenewFrameSubscription() to maintain 2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // capture on the correct RenderWidgetHost. 2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const scoped_refptr<WebContentsTracker> tracker_; 2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // A dedicated worker thread on which SkBitmap->VideoFrame conversion will 283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // occur. Only used when this activity cannot be done on the GPU. 2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<base::Thread> render_thread_; 285c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 286c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Makes all the decisions about which frames to copy, and how. 287f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 289010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) // Video capture parameters that this machine is started with. 290010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) media::VideoCaptureParams capture_params_; 291010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) 2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Last known RenderView size. 2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size last_view_size_; 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Responsible for forwarding events from the active RenderWidgetHost to the 296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // oracle, and initiating captures accordingly. 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<ContentCaptureSubscription> subscription_; 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Weak pointer factory used to invalidate callbacks. 30023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) // NOTE: Weak pointers must be invalidated before all other member variables. 3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::WeakPtrFactory<WebContentsCaptureMachine> weak_ptr_factory_; 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 303f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(WebContentsCaptureMachine); 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FrameSubscriber::ShouldCaptureFrame( 3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const gfx::Rect& damage_rect, 3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::TimeTicks present_time, 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<media::VideoFrame>* storage, 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DeliverFrameCallback* deliver_frame_cb) { 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TRACE_EVENT1("mirroring", "FrameSubscriber::ShouldCaptureFrame", 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "instance", this); 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 314f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; 315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture( 3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) event_type_, damage_rect, present_time, storage, &capture_frame_cb); 317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 318010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (!capture_frame_cb.is_null()) 319010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) *deliver_frame_cb = base::Bind(capture_frame_cb, *storage); 320c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch if (oracle_decision) 321c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch delivery_log_->ChronicleFrameDelivery(present_time); 322f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return oracle_decision; 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ContentCaptureSubscription::ContentCaptureSubscription( 3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const RenderWidgetHost& source, 327a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, 3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const CaptureCallback& capture_callback) 3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : render_process_id_(source.GetProcess()->GetID()), 3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci render_widget_id_(source.GetRoutingID()), 331c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch delivery_log_(), 332c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch paint_subscriber_(VideoCaptureOracle::kSoftwarePaint, oracle_proxy, 333c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch &delivery_log_), 334c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch timer_subscriber_(VideoCaptureOracle::kTimerPoll, oracle_proxy, 335c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch &delivery_log_), 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) capture_callback_(capture_callback), 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) timer_(true, true) { 3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci RenderWidgetHostView* const view = source.GetView(); 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Subscribe to accelerated presents. These will be serviced directly by the 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // oracle. 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (view && kAcceleratedSubscriberIsSupported) { 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( 346a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) new FrameSubscriber(VideoCaptureOracle::kCompositorUpdate, 347c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch oracle_proxy, &delivery_log_)); 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) view->BeginFrameSubscription(subscriber.Pass()); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Subscribe to software paint events. This instance will service these by 352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // reflecting them back to the WebContentsCaptureMachine via 353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // |capture_callback|. 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) registrar_.Add( 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Source<RenderWidgetHost>(&source)); 3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Subscribe to timer events. This instance will service these as well. 3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) timer_.Start(FROM_HERE, oracle_proxy->min_capture_period(), 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Bind(&ContentCaptureSubscription::OnTimer, 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Unretained(this))); 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ContentCaptureSubscription::~ContentCaptureSubscription() { 3651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // If the BrowserThreads have been torn down, then the browser is in the final 3661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // stages of exiting and it is dangerous to take any further action. We must 3671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // return early. http://crbug.com/396413 3681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!BrowserThread::IsMessageLoopValid(BrowserThread::UI)) 3691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 3701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 3711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (kAcceleratedSubscriberIsSupported) { 3731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci RenderWidgetHost* const source = 3741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci RenderWidgetHost::FromID(render_process_id_, render_widget_id_); 3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci RenderWidgetHostView* const view = source ? source->GetView() : NULL; 3761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (view) 3771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci view->EndFrameSubscription(); 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ContentCaptureSubscription::Observe( 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int type, 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const content::NotificationSource& source, 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const content::NotificationDetails& details) { 3851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK_EQ(NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, type); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RenderWidgetHostImpl* rwh = 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RenderWidgetHostImpl::From(Source<RenderWidgetHost>(source).ptr()); 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This message occurs on window resizes and visibility changes even when 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // accelerated compositing is active, so we need to filter out these cases. 393effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch if (!rwh || !rwh->GetView()) 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 395effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // Mac sends DID_UPDATE_BACKING_STORE messages to inform the capture system 396effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // of new software compositor frames, so always treat these messages as 397effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // signals of a new frame on Mac. 398effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch // http://crbug.com/333986 399effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#if !defined(OS_MACOSX) 400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (rwh->GetView()->IsSurfaceAvailableForCopy()) 401effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return; 402effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#endif 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TRACE_EVENT1("mirroring", "ContentCaptureSubscription::Observe", 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "instance", this); 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::Closure copy_done_callback; 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<media::VideoFrame> frame; 4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb; 4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::TimeTicks start_time = base::TimeTicks::Now(); 4115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (paint_subscriber_.ShouldCaptureFrame(gfx::Rect(), 4125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) start_time, 413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &frame, 414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &deliver_frame_cb)) { 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This message happens just before paint. If we post a task to do the copy, 4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // it should run soon after the paint. 4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::PostTask( 4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) BrowserThread::UI, FROM_HERE, 419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::Bind(capture_callback_, start_time, frame, deliver_frame_cb)); 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ContentCaptureSubscription::OnTimer() { 4241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) TRACE_EVENT0("mirroring", "ContentCaptureSubscription::OnTimer"); 4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scoped_refptr<media::VideoFrame> frame; 4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb; 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::TimeTicks start_time = base::TimeTicks::Now(); 4315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if (timer_subscriber_.ShouldCaptureFrame(gfx::Rect(), 4325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) start_time, 433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &frame, 434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &deliver_frame_cb)) { 435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) capture_callback_.Run(start_time, frame, deliver_frame_cb); 436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void RenderVideoFrame(const SkBitmap& input, 440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const scoped_refptr<media::VideoFrame>& output, 441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const base::Callback<void(bool)>& done_cb) { 4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::ScopedClosureRunner failure_handler(base::Bind(done_cb, false)); 4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkAutoLockPixels locker(input); 4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Sanity-check the captured bitmap. 4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (input.empty() || 4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) !input.readyToDraw() || 449116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch input.colorType() != kN32_SkColorType || 4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) input.width() < 2 || input.height() < 2) { 4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << "input unacceptable (size=" 4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << input.getSize() 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << ", ready=" << input.readyToDraw() 454116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch << ", colorType=" << input.colorType() << ')'; 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Sanity-check the output buffer. 459ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (output->format() != media::VideoFrame::I420) { 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) NOTREACHED(); 4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Calculate the width and height of the content region in the |output|, based 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // on the aspect ratio of |input|. 4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect region_in_frame = ComputeYV12LetterboxRegion( 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) output->coded_size(), gfx::Size(input.width(), input.height())); 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Scale the bitmap to the required size, if necessary. 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkBitmap scaled_bitmap; 4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (input.width() != region_in_frame.width() || 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) input.height() != region_in_frame.height()) { 473b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 474b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) skia::ImageOperations::ResizeMethod method; 475b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) if (input.width() < region_in_frame.width() || 476b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) input.height() < region_in_frame.height()) { 477b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // Avoid box filtering when magnifying, because it's actually 478b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) // nearest-neighbor. 479b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) method = skia::ImageOperations::RESIZE_HAMMING1; 480b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } else { 481b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) method = skia::ImageOperations::RESIZE_BOX; 482b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) } 483b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 4841e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", output.get(), "Scale"); 485b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) scaled_bitmap = skia::ImageOperations::Resize(input, method, 486b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) region_in_frame.width(), 487b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) region_in_frame.height()); 4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scaled_bitmap = input; 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", output.get(), "YUV"); 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap); 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) media::CopyRGBToVideoFrame( 4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) reinterpret_cast<uint8*>(scaled_bitmap.getPixels()), 4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) scaled_bitmap.rowBytes(), 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) region_in_frame, 500868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) output.get()); 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The result is now ready. 504424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) ignore_result(failure_handler.Release()); 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) done_cb.Run(true); 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)VideoFrameDeliveryLog::VideoFrameDeliveryLog() 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : last_frame_rate_log_time_(), 510c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch count_frames_rendered_(0) { 5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 513c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochvoid VideoFrameDeliveryLog::ChronicleFrameDelivery(base::TimeTicks frame_time) { 5142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Log frame rate, if verbose logging is turned on. 5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static const base::TimeDelta kFrameRateLogInterval = 5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::TimeDelta::FromSeconds(10); 5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (last_frame_rate_log_time_.is_null()) { 518c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch last_frame_rate_log_time_ = frame_time; 5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) count_frames_rendered_ = 0; 5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ++count_frames_rendered_; 522c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch const base::TimeDelta elapsed = frame_time - last_frame_rate_log_time_; 5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (elapsed >= kFrameRateLogInterval) { 5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const double measured_fps = 5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) count_frames_rendered_ / elapsed.InSecondsF(); 5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UMA_HISTOGRAM_COUNTS( 5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "TabCapture.FrameRate", 5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) static_cast<int>(measured_fps)); 5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) VLOG(1) << "Current measured frame rate for " 5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) << "WebContentsVideoCaptureDevice is " << measured_fps << " FPS."; 531c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch last_frame_rate_log_time_ = frame_time; 5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) count_frames_rendered_ = 0; 5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 537f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id, 538116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int main_render_frame_id) 539f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : initial_render_process_id_(render_process_id), 540116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch initial_main_render_frame_id_(main_render_frame_id), 5411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tracker_(new WebContentsTracker(true)), 5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_(this) {} 5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciWebContentsCaptureMachine::~WebContentsCaptureMachine() {} 5451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool WebContentsCaptureMachine::IsStarted() const { 5471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 5481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return weak_ptr_factory_.HasWeakPtrs(); 5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 550f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 551f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool WebContentsCaptureMachine::Start( 552010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, 553010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) const media::VideoCaptureParams& params) { 5541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 5551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(!IsStarted()); 5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 557f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(oracle_proxy.get()); 558f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) oracle_proxy_ = oracle_proxy; 559010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) capture_params_ = params; 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) render_thread_.reset(new base::Thread("WebContentsVideo_RenderThread")); 5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!render_thread_->Start()) { 563f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DVLOG(1) << "Failed to spawn render thread."; 5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) render_thread_.reset(); 565f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return false; 566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) } 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Note: Creation of the first WeakPtr in the following statement will cause 5691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // IsStarted() to return true from now on. 5701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tracker_->Start(initial_render_process_id_, initial_main_render_frame_id_, 5711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::Bind(&WebContentsCaptureMachine::RenewFrameSubscription, 5721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci weak_ptr_factory_.GetWeakPtr())); 5732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 574f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return true; 575f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void WebContentsCaptureMachine::Stop(const base::Closure& callback) { 5781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 5791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!IsStarted()) { 5811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci callback.Run(); 5821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // The following cancels any outstanding callbacks and causes IsStarted() to 5861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // return false from here onward. 5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_.InvalidateWeakPtrs(); 5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Note: RenewFrameSubscription() must be called before stopping |tracker_| so 5901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // the web_contents() can be notified that the capturing is ending. 5911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci RenewFrameSubscription(NULL); 5921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tracker_->Stop(); 5931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The render thread cannot be stopped on the UI thread, so post a message 5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // to the thread pool used for blocking operations. 5961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (render_thread_.get()) { 5971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci BrowserThread::PostBlockingPoolTask( 5981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci FROM_HERE, 5991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), 6001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci callback)); 6011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 604f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void WebContentsCaptureMachine::Capture( 6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::TimeTicks& start_time, 6062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const scoped_refptr<media::VideoFrame>& target, 607a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 608a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) deliver_frame_cb) { 6091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 6102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci RenderWidgetHost* rwh = tracker_->GetTargetRenderWidgetHost(); 612010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) RenderWidgetHostViewBase* view = 613010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL; 6141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!view) { 6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) deliver_frame_cb.Run(base::TimeTicks(), false); 6162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size video_size = target->coded_size(); 6202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size view_size = view->GetViewBounds().size(); 6212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size fitted_size; 6222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!view_size.IsEmpty()) { 6232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fitted_size = ComputeYV12LetterboxRegion(video_size, view_size).size(); 6242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (view_size != last_view_size_) { 6262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) last_view_size_ = view_size; 6272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Measure the number of kilopixels. 6292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UMA_HISTOGRAM_COUNTS_10000( 6302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) "TabCapture.ViewChangeKiloPixels", 6312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) view_size.width() * view_size.height() / 1024); 6322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 6345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (view->CanCopyToVideoFrame()) { 6352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) view->CopyFromCompositingSurfaceToVideoFrame( 6362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect(view_size), 6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) target, 638f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Bind(&WebContentsCaptureMachine:: 639f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DidCopyFromCompositingSurfaceToVideoFrame, 6405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 6415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) start_time, deliver_frame_cb)); 6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) rwh->CopyFromBackingStore( 6442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Rect(), 6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) fitted_size, // Size here is a request not always honored. 646f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore, 6475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr(), 648a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) start_time, 649a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) target, 650a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) deliver_frame_cb), 651116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch kN32_SkColorType); 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)gfx::Size WebContentsCaptureMachine::ComputeOptimalTargetSize() const { 6561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 6576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 6586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) gfx::Size optimal_size = oracle_proxy_->GetCaptureSize(); 6596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 6606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If the ratio between physical and logical pixels is greater than 1:1, 6616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // shrink |optimal_size| by that amount. Then, when external code resizes the 6626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // render widget to the "preferred size," the widget will be physically 6636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // rendered at the exact capture size, thereby eliminating unnecessary scaling 6646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // operations in the graphics pipeline. 6651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci RenderWidgetHost* const rwh = tracker_->GetTargetRenderWidgetHost(); 6666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) RenderWidgetHostView* const rwhv = rwh ? rwh->GetView() : NULL; 6676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (rwhv) { 6686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const gfx::NativeView view = rwhv->GetNativeView(); 6696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) gfx::Screen* const screen = gfx::Screen::GetScreenFor(view); 6706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (screen->IsDIPEnabled()) { 6716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const gfx::Display display = screen->GetDisplayNearestWindow(view); 6726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const float scale = display.device_scale_factor(); 6736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (scale > 1.0f) { 6746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) const gfx::Size shrunk_size( 6756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) gfx::ToFlooredSize(gfx::ScaleSize(optimal_size, 1.0f / scale))); 6766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (shrunk_size.width() > 0 && shrunk_size.height() > 0) 6776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) optimal_size = shrunk_size; 6786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 6796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 6806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 6816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 6826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) VLOG(1) << "Computed optimal target size: " << optimal_size.ToString(); 6836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return optimal_size; 6846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 6856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 686f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void WebContentsCaptureMachine::DidCopyFromBackingStore( 6875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::TimeTicks& start_time, 6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const scoped_refptr<media::VideoFrame>& target, 689a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 690a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) deliver_frame_cb, 6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool success, 6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const SkBitmap& bitmap) { 6931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::TimeTicks now = base::TimeTicks::Now(); 6965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(render_thread_.get()); 6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (success) { 6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); 6991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(), 7001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) "Render"); 7015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) render_thread_->message_loop_proxy()->PostTask(FROM_HERE, base::Bind( 702c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) &RenderVideoFrame, bitmap, target, 703c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::Bind(deliver_frame_cb, start_time))); 7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 7052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Capture can fail due to transient issues, so just skip this frame. 7062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; 707c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) deliver_frame_cb.Run(start_time, false); 7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 711f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( 7125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const base::TimeTicks& start_time, 713a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 714a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) deliver_frame_cb, 7152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool success) { 7161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::TimeTicks now = base::TimeTicks::Now(); 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (success) { 7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time); 7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 7222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Capture can fail due to transient issues, so just skip this frame. 7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 725c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) deliver_frame_cb.Run(start_time, success); 7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid WebContentsCaptureMachine::RenewFrameSubscription(RenderWidgetHost* rwh) { 7291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK_CURRENTLY_ON(BrowserThread::UI); 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Always destroy the old subscription before creating a new one. 7321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const bool had_subscription = !!subscription_; 7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) subscription_.reset(); 7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 7351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DVLOG(1) << "Renewing frame subscription to RWH@" << rwh 7361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci << ", had_subscription=" << had_subscription; 7371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 7381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!rwh) { 7391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (had_subscription && tracker_->web_contents()) 7401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tracker_->web_contents()->DecrementCapturerCount(); 7411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (IsStarted()) { 7421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Tracking of WebContents and/or its main frame has failed before Stop() 7431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // was called, so report this as an error: 7441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci oracle_proxy_->ReportError("WebContents and/or main frame are gone."); 7451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 7471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 7481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 7491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!had_subscription && tracker_->web_contents()) { 7501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci tracker_->web_contents()->IncrementCapturerCount( 7511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ComputeOptimalTargetSize()); 7521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 754a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_, 7555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&WebContentsCaptureMachine::Capture, 7565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) weak_ptr_factory_.GetWeakPtr()))); 757c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 758c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( 762116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int render_process_id, int main_render_frame_id) 7635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>( 764116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch new WebContentsCaptureMachine( 765116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch render_process_id, main_render_frame_id)))) {} 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() { 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying."; 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 7724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create( 773c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& device_id) { 7741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Parse device_id into render_process_id and main_render_frame_id. 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int render_process_id = -1; 776116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch int main_render_frame_id = -1; 7774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!WebContentsCaptureUtil::ExtractTabCaptureTarget( 778116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch device_id, &render_process_id, &main_render_frame_id)) { 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 7804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 782116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return new WebContentsVideoCaptureDevice( 783116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch render_process_id, main_render_frame_id); 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void WebContentsVideoCaptureDevice::AllocateAndStart( 787f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const media::VideoCaptureParams& params, 7884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) scoped_ptr<Client> client) { 789f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); 7905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) core_->AllocateAndStart(params, client.Pass()); 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void WebContentsVideoCaptureDevice::StopAndDeAllocate() { 7945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) core_->StopAndDeAllocate(); 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace content 798