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