Home | History | Annotate | Download | only in media
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 // Implementation notes: This needs to work on a variety of hardware
      6 // configurations where the speed of the CPU and GPU greatly affect overall
      7 // performance. Spanning several threads, the process of capturing has been
      8 // split up into four conceptual stages:
      9 //
     10 //   1. Reserve Buffer: Before a frame can be captured, a slot in the consumer's
     11 //      shared-memory IPC buffer is reserved. There are only a few of these;
     12 //      when they run out, it indicates that the downstream consumer -- likely a
     13 //      video encoder -- is the performance bottleneck, and that the rate of
     14 //      frame capture should be throttled back.
     15 //
     16 //   2. Capture: A bitmap is snapshotted/copied from the RenderView's backing
     17 //      store. This is initiated on the UI BrowserThread, and often occurs
     18 //      asynchronously. Where supported, the GPU scales and color converts
     19 //      frames to our desired size, and the readback happens directly into the
     20 //      shared-memory buffer. But this is not always possible, particularly when
     21 //      accelerated compositing is disabled.
     22 //
     23 //   3. Render (if needed): If the web contents cannot be captured directly into
     24 //      our target size and color format, scaling and colorspace conversion must
     25 //      be done on the CPU. A dedicated thread is used for this operation, to
     26 //      avoid blocking the UI thread. The Render stage always reads from a
     27 //      bitmap returned by Capture, and writes into the reserved slot in the
     28 //      shared-memory buffer.
     29 //
     30 //   4. Deliver: The rendered video frame is returned to the consumer (which
     31 //      implements the VideoCaptureDevice::EventHandler interface). Because
     32 //      all paths have written the frame into the IPC buffer, this step should
     33 //      never need to do an additional copy of the pixel data.
     34 //
     35 // In the best-performing case, the Render step is bypassed: Capture produces
     36 // ready-to-Deliver frames. But when accelerated readback is not possible, the
     37 // system is designed so that Capture and Render may run concurrently. A timing
     38 // diagram helps illustrate this point (@30 FPS):
     39 //
     40 //    Time: 0ms                 33ms                 66ms                 99ms
     41 // thread1: |-Capture-f1------v |-Capture-f2------v  |-Capture-f3----v    |-Capt
     42 // thread2:                   |-Render-f1-----v   |-Render-f2-----v  |-Render-f3
     43 //
     44 // In the above example, both capturing and rendering *each* take almost the
     45 // full 33 ms available between frames, yet we see that the required throughput
     46 // is obtained.
     47 //
     48 // Turning on verbose logging will cause the effective frame rate to be logged
     49 // at 5-second intervals.
     50 
     51 #include "content/browser/renderer_host/media/web_contents_video_capture_device.h"
     52 
     53 #include <algorithm>
     54 #include <list>
     55 #include <string>
     56 
     57 #include "base/basictypes.h"
     58 #include "base/bind.h"
     59 #include "base/bind_helpers.h"
     60 #include "base/callback_forward.h"
     61 #include "base/debug/trace_event.h"
     62 #include "base/logging.h"
     63 #include "base/memory/scoped_ptr.h"
     64 #include "base/memory/weak_ptr.h"
     65 #include "base/message_loop/message_loop_proxy.h"
     66 #include "base/metrics/histogram.h"
     67 #include "base/sequenced_task_runner.h"
     68 #include "base/strings/stringprintf.h"
     69 #include "base/synchronization/lock.h"
     70 #include "base/threading/thread.h"
     71 #include "base/threading/thread_checker.h"
     72 #include "base/time/time.h"
     73 #include "content/browser/renderer_host/media/video_capture_oracle.h"
     74 #include "content/browser/renderer_host/media/web_contents_capture_util.h"
     75 #include "content/browser/renderer_host/render_widget_host_impl.h"
     76 #include "content/browser/web_contents/web_contents_impl.h"
     77 #include "content/port/browser/render_widget_host_view_frame_subscriber.h"
     78 #include "content/port/browser/render_widget_host_view_port.h"
     79 #include "content/public/browser/browser_thread.h"
     80 #include "content/public/browser/notification_source.h"
     81 #include "content/public/browser/notification_types.h"
     82 #include "content/public/browser/render_process_host.h"
     83 #include "content/public/browser/render_view_host.h"
     84 #include "content/public/browser/render_widget_host_view.h"
     85 #include "content/public/browser/web_contents.h"
     86 #include "content/public/browser/web_contents_observer.h"
     87 #include "media/base/bind_to_loop.h"
     88 #include "media/base/video_frame.h"
     89 #include "media/base/video_util.h"
     90 #include "media/base/yuv_convert.h"
     91 #include "media/video/capture/video_capture_types.h"
     92 #include "skia/ext/image_operations.h"
     93 #include "third_party/skia/include/core/SkBitmap.h"
     94 #include "third_party/skia/include/core/SkColor.h"
     95 #include "ui/gfx/rect.h"
     96 #include "ui/gfx/skia_util.h"
     97 
     98 namespace content {
     99 
    100 namespace {
    101 
    102 const int kMinFrameWidth = 2;
    103 const int kMinFrameHeight = 2;
    104 const int kMaxFramesInFlight = 2;
    105 const int kMaxSnapshotsInFlight = 1;
    106 
    107 // TODO(nick): Remove this once frame subscription is supported on Aura and
    108 // Linux.
    109 #if (defined(OS_WIN) || defined(OS_MACOSX)) || defined(USE_AURA)
    110 const bool kAcceleratedSubscriberIsSupported = true;
    111 #else
    112 const bool kAcceleratedSubscriberIsSupported = false;
    113 #endif
    114 
    115 // Returns the nearest even integer closer to zero.
    116 template<typename IntType>
    117 IntType MakeEven(IntType x) {
    118   return x & static_cast<IntType>(-2);
    119 }
    120 
    121 // Compute a letterbox region, aligned to even coordinates.
    122 gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size,
    123                                      const gfx::Size& content_size) {
    124 
    125   gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size),
    126                                                    content_size);
    127 
    128   result.set_x(MakeEven(result.x()));
    129   result.set_y(MakeEven(result.y()));
    130   result.set_width(std::max(kMinFrameWidth, MakeEven(result.width())));
    131   result.set_height(std::max(kMinFrameHeight, MakeEven(result.height())));
    132 
    133   return result;
    134 }
    135 
    136 // Thread-safe, refcounted proxy to the VideoCaptureOracle.  This proxy wraps
    137 // the VideoCaptureOracle, which decides which frames to capture, and a
    138 // VideoCaptureDevice::EventHandler, which allocates and receives the captured
    139 // frames, in a lock to synchronize state between the two.
    140 class ThreadSafeCaptureOracle
    141     : public base::RefCountedThreadSafe<ThreadSafeCaptureOracle> {
    142  public:
    143   ThreadSafeCaptureOracle(media::VideoCaptureDevice::EventHandler* consumer,
    144                           scoped_ptr<VideoCaptureOracle> oracle);
    145 
    146   bool ObserveEventAndDecideCapture(
    147       VideoCaptureOracle::Event event,
    148       base::Time event_time,
    149       scoped_refptr<media::VideoFrame>* storage,
    150       RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback);
    151 
    152   base::TimeDelta capture_period() const {
    153     return oracle_->capture_period();
    154   }
    155 
    156   // Allow new captures to start occurring.
    157   void Start();
    158 
    159   // Stop new captures from happening (but doesn't forget the consumer).
    160   void Stop();
    161 
    162   // Signal an error to the consumer.
    163   void ReportError();
    164 
    165   // Permanently stop capturing. Immediately cease all activity on the
    166   // VCD::EventHandler.
    167   void InvalidateConsumer();
    168 
    169  private:
    170   friend class base::RefCountedThreadSafe<ThreadSafeCaptureOracle>;
    171   virtual ~ThreadSafeCaptureOracle() {}
    172 
    173   // Callback invoked on completion of all captures.
    174   void DidCaptureFrame(const scoped_refptr<media::VideoFrame>& frame,
    175                        int frame_number,
    176                        base::Time timestamp,
    177                        bool success);
    178 
    179   // Protects everything below it.
    180   base::Lock lock_;
    181 
    182   // Recipient of our capture activity. Becomes null after it is invalidated.
    183   media::VideoCaptureDevice::EventHandler* consumer_;
    184 
    185   // Makes the decision to capture a frame.
    186   const scoped_ptr<VideoCaptureOracle> oracle_;
    187 
    188   // Whether capturing is currently allowed. Can toggle back and forth.
    189   bool is_started_;
    190 };
    191 
    192 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible
    193 // with RenderWidgetHostViewFrameSubscriber. We create one per event type.
    194 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
    195  public:
    196   FrameSubscriber(VideoCaptureOracle::Event event_type,
    197                   const scoped_refptr<ThreadSafeCaptureOracle>& oracle)
    198       : event_type_(event_type),
    199         oracle_proxy_(oracle) {}
    200 
    201   virtual bool ShouldCaptureFrame(
    202       base::Time present_time,
    203       scoped_refptr<media::VideoFrame>* storage,
    204       RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback*
    205           deliver_frame_cb) OVERRIDE;
    206 
    207  private:
    208   const VideoCaptureOracle::Event event_type_;
    209   scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
    210 };
    211 
    212 // ContentCaptureSubscription is the relationship between a RenderWidgetHost
    213 // whose content is updating, a subscriber that is deciding which of these
    214 // updates to capture (and where to deliver them to), and a callback that
    215 // knows how to do the capture and prepare the result for delivery.
    216 //
    217 // In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in
    218 // the RenderWidgetHostView, to process updates that occur via accelerated
    219 // compositing, (b) installing itself as an observer of updates to the
    220 // RenderWidgetHost's backing store, to hook updates that occur via software
    221 // rendering, and (c) running a timer to possibly initiate non-event-driven
    222 // captures that the subscriber might request.
    223 //
    224 // All of this happens on the UI thread, although the
    225 // RenderWidgetHostViewFrameSubscriber we install may be dispatching updates
    226 // autonomously on some other thread.
    227 class ContentCaptureSubscription : public content::NotificationObserver {
    228  public:
    229   typedef base::Callback<void(
    230       const base::Time&,
    231       const scoped_refptr<media::VideoFrame>&,
    232       const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&)>
    233           CaptureCallback;
    234 
    235   // Create a subscription. Whenever a manual capture is required, the
    236   // subscription will invoke |capture_callback| on the UI thread to do the
    237   // work.
    238   ContentCaptureSubscription(
    239       const RenderWidgetHost& source,
    240       const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
    241       const CaptureCallback& capture_callback);
    242   virtual ~ContentCaptureSubscription();
    243 
    244   // content::NotificationObserver implementation.
    245   virtual void Observe(int type,
    246                        const content::NotificationSource& source,
    247                        const content::NotificationDetails& details) OVERRIDE;
    248 
    249  private:
    250   void OnTimer();
    251 
    252   const int render_process_id_;
    253   const int render_view_id_;
    254 
    255   FrameSubscriber paint_subscriber_;
    256   FrameSubscriber timer_subscriber_;
    257   content::NotificationRegistrar registrar_;
    258   CaptureCallback capture_callback_;
    259   base::Timer timer_;
    260 
    261   DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription);
    262 };
    263 
    264 // Render the SkBitmap |input| into the given VideoFrame buffer |output|, then
    265 // invoke |done_cb| to indicate success or failure. |input| is expected to be
    266 // ARGB. |output| must be YV12 or I420. Colorspace conversion is always done.
    267 // Scaling and letterboxing will be done as needed.
    268 //
    269 // This software implementation should be used only when GPU acceleration of
    270 // these activities is not possible. This operation may be expensive (tens to
    271 // hundreds of milliseconds), so the caller should ensure that it runs on a
    272 // thread where such a pause would cause UI jank.
    273 void RenderVideoFrame(const SkBitmap& input,
    274                       const scoped_refptr<media::VideoFrame>& output,
    275                       const base::Callback<void(bool)>& done_cb);
    276 
    277 // Keeps track of the RenderView to be sourced, and executes copying of the
    278 // backing store on the UI BrowserThread.
    279 //
    280 // TODO(nick): It would be nice to merge this with WebContentsTracker, but its
    281 // implementation is currently asynchronous -- in our case, the "rvh changed"
    282 // notification would get posted back to the UI thread and processed later, and
    283 // this seems disadvantageous.
    284 class CaptureMachine : public WebContentsObserver,
    285                        public base::SupportsWeakPtr<CaptureMachine> {
    286  public:
    287   virtual ~CaptureMachine();
    288 
    289   // Creates a CaptureMachine. Must be run on the UI BrowserThread. Returns
    290   // NULL if the indicated render view cannot be found.
    291   static scoped_ptr<CaptureMachine> Create(
    292       int render_process_id,
    293       int render_view_id,
    294       const scoped_refptr<base::SequencedTaskRunner>& render_task_runner,
    295       const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy);
    296 
    297   // Starts a copy from the backing store or the composited surface. Must be run
    298   // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation
    299   // completes. The copy will occur to |target|.
    300   //
    301   // This may be used as a ContentCaptureSubscription::CaptureCallback.
    302   void Capture(
    303       const base::Time& start_time,
    304       const scoped_refptr<media::VideoFrame>& target,
    305       const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
    306           deliver_frame_cb);
    307 
    308   // content::WebContentsObserver implementation.
    309   virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE {
    310     fullscreen_widget_id_ = routing_id;
    311     RenewFrameSubscription();
    312   }
    313 
    314   virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE {
    315     DCHECK_EQ(fullscreen_widget_id_, routing_id);
    316     fullscreen_widget_id_ = MSG_ROUTING_NONE;
    317     RenewFrameSubscription();
    318   }
    319 
    320   virtual void RenderViewReady() OVERRIDE {
    321     RenewFrameSubscription();
    322   }
    323 
    324   virtual void AboutToNavigateRenderView(RenderViewHost* rvh) OVERRIDE {
    325     RenewFrameSubscription();
    326   }
    327 
    328   virtual void DidNavigateMainFrame(
    329       const LoadCommittedDetails& details,
    330       const FrameNavigateParams& params) OVERRIDE {
    331     RenewFrameSubscription();
    332   }
    333 
    334   virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
    335 
    336  private:
    337   CaptureMachine(
    338      const scoped_refptr<base::SequencedTaskRunner>& render_task_runner,
    339      const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy);
    340 
    341   // Starts observing the web contents, returning false if lookup fails.
    342   bool StartObservingWebContents(int initial_render_process_id,
    343                                  int initial_render_view_id);
    344 
    345   // Helper function to determine the view that we are currently tracking.
    346   RenderWidgetHost* GetTarget();
    347 
    348   // Response callback for RenderWidgetHost::CopyFromBackingStore().
    349   void DidCopyFromBackingStore(
    350       const base::Time& start_time,
    351       const scoped_refptr<media::VideoFrame>& target,
    352       const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
    353           deliver_frame_cb,
    354       bool success,
    355       const SkBitmap& bitmap);
    356 
    357   // Response callback for RWHVP::CopyFromCompositingSurfaceToVideoFrame().
    358   void DidCopyFromCompositingSurfaceToVideoFrame(
    359       const base::Time& start_time,
    360       const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
    361           deliver_frame_cb,
    362       bool success);
    363 
    364   // Remove the old subscription, and start a new one. This should be called
    365   // after any change to the WebContents that affects the RenderWidgetHost or
    366   // attached views.
    367   void RenewFrameSubscription();
    368 
    369   // The task runner of the thread on which SkBitmap->VideoFrame conversion will
    370   // occur. Only used when this activity cannot be done on the GPU.
    371   const scoped_refptr<base::SequencedTaskRunner> render_task_runner_;
    372 
    373   // Makes all the decisions about which frames to copy, and how.
    374   const scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
    375 
    376   // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE
    377   // otherwise.
    378   int fullscreen_widget_id_;
    379 
    380   // Last known RenderView size.
    381   gfx::Size last_view_size_;
    382 
    383   // Responsible for forwarding events from the active RenderWidgetHost to the
    384   // oracle, and initiating captures accordingly.
    385   scoped_ptr<ContentCaptureSubscription> subscription_;
    386 
    387   DISALLOW_COPY_AND_ASSIGN(CaptureMachine);
    388 };
    389 
    390 // Responsible for logging the effective frame rate.
    391 // TODO(nick): Make this compatible with the push model and hook it back up.
    392 class VideoFrameDeliveryLog {
    393  public:
    394   VideoFrameDeliveryLog();
    395 
    396   // Treat |frame_number| as having been delivered, and update the
    397   // frame rate statistics accordingly.
    398   void ChronicleFrameDelivery(int frame_number);
    399 
    400  private:
    401   // The following keep track of and log the effective frame rate whenever
    402   // verbose logging is turned on.
    403   base::Time last_frame_rate_log_time_;
    404   int count_frames_rendered_;
    405   int last_frame_number_;
    406 
    407   DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog);
    408 };
    409 
    410 ThreadSafeCaptureOracle::ThreadSafeCaptureOracle(
    411     media::VideoCaptureDevice::EventHandler* consumer,
    412     scoped_ptr<VideoCaptureOracle> oracle)
    413     : consumer_(consumer),
    414       oracle_(oracle.Pass()),
    415       is_started_(false) {
    416 }
    417 
    418 bool ThreadSafeCaptureOracle::ObserveEventAndDecideCapture(
    419     VideoCaptureOracle::Event event,
    420     base::Time event_time,
    421     scoped_refptr<media::VideoFrame>* storage,
    422     RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* callback) {
    423   base::AutoLock guard(lock_);
    424 
    425   if (!consumer_ || !is_started_)
    426     return false;  // Capture is stopped.
    427 
    428   scoped_refptr<media::VideoFrame> output_buffer =
    429       consumer_->ReserveOutputBuffer();
    430   const bool should_capture =
    431       oracle_->ObserveEventAndDecideCapture(event, event_time);
    432   const bool content_is_dirty =
    433       (event == VideoCaptureOracle::kCompositorUpdate ||
    434        event == VideoCaptureOracle::kSoftwarePaint);
    435   const char* event_name =
    436       (event == VideoCaptureOracle::kTimerPoll ? "poll" :
    437        (event == VideoCaptureOracle::kCompositorUpdate ? "gpu" :
    438        "paint"));
    439 
    440   // Consider the various reasons not to initiate a capture.
    441   if (should_capture && !output_buffer.get()) {
    442     TRACE_EVENT_INSTANT1("mirroring",
    443                          "EncodeLimited",
    444                          TRACE_EVENT_SCOPE_THREAD,
    445                          "trigger",
    446                          event_name);
    447     return false;
    448   } else if (!should_capture && output_buffer.get()) {
    449     if (content_is_dirty) {
    450       // This is a normal and acceptable way to drop a frame. We've hit our
    451       // capture rate limit: for example, the content is animating at 60fps but
    452       // we're capturing at 30fps.
    453       TRACE_EVENT_INSTANT1("mirroring", "FpsRateLimited",
    454                            TRACE_EVENT_SCOPE_THREAD,
    455                            "trigger", event_name);
    456     }
    457     return false;
    458   } else if (!should_capture && !output_buffer.get()) {
    459     // We decided not to capture, but we wouldn't have been able to if we wanted
    460     // to because no output buffer was available.
    461     TRACE_EVENT_INSTANT1("mirroring", "NearlyEncodeLimited",
    462                          TRACE_EVENT_SCOPE_THREAD,
    463                          "trigger", event_name);
    464     return false;
    465   }
    466   int frame_number = oracle_->RecordCapture();
    467   TRACE_EVENT_ASYNC_BEGIN2("mirroring", "Capture", output_buffer.get(),
    468                            "frame_number", frame_number,
    469                            "trigger", event_name);
    470   *storage = output_buffer;
    471   *callback = base::Bind(&ThreadSafeCaptureOracle::DidCaptureFrame,
    472                          this, output_buffer, frame_number);
    473   return true;
    474 }
    475 
    476 void ThreadSafeCaptureOracle::Start() {
    477   base::AutoLock guard(lock_);
    478   is_started_ = true;
    479 }
    480 
    481 void ThreadSafeCaptureOracle::Stop() {
    482   base::AutoLock guard(lock_);
    483   is_started_ = false;
    484 }
    485 
    486 void ThreadSafeCaptureOracle::ReportError() {
    487   base::AutoLock guard(lock_);
    488   if (consumer_)
    489     consumer_->OnError();
    490 }
    491 
    492 void ThreadSafeCaptureOracle::InvalidateConsumer() {
    493   base::AutoLock guard(lock_);
    494 
    495   TRACE_EVENT_INSTANT0("mirroring", "InvalidateConsumer",
    496                        TRACE_EVENT_SCOPE_THREAD);
    497 
    498   is_started_ = false;
    499   consumer_ = NULL;
    500 }
    501 
    502 void ThreadSafeCaptureOracle::DidCaptureFrame(
    503     const scoped_refptr<media::VideoFrame>& frame,
    504     int frame_number,
    505     base::Time timestamp,
    506     bool success) {
    507   base::AutoLock guard(lock_);
    508 
    509   TRACE_EVENT_ASYNC_END2("mirroring", "Capture", frame.get(),
    510                          "success", success,
    511                          "timestamp", timestamp.ToInternalValue());
    512 
    513   if (!consumer_ || !is_started_)
    514     return;  // Capture is stopped.
    515 
    516   if (success)
    517     if (oracle_->CompleteCapture(frame_number, timestamp))
    518       consumer_->OnIncomingCapturedVideoFrame(frame, timestamp);
    519 }
    520 
    521 bool FrameSubscriber::ShouldCaptureFrame(
    522     base::Time present_time,
    523     scoped_refptr<media::VideoFrame>* storage,
    524     DeliverFrameCallback* deliver_frame_cb) {
    525   TRACE_EVENT1("mirroring", "FrameSubscriber::ShouldCaptureFrame",
    526                "instance", this);
    527 
    528   return oracle_proxy_->ObserveEventAndDecideCapture(event_type_, present_time,
    529                                                      storage, deliver_frame_cb);
    530 }
    531 
    532 ContentCaptureSubscription::ContentCaptureSubscription(
    533     const RenderWidgetHost& source,
    534     const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
    535     const CaptureCallback& capture_callback)
    536     : render_process_id_(source.GetProcess()->GetID()),
    537       render_view_id_(source.GetRoutingID()),
    538       paint_subscriber_(VideoCaptureOracle::kSoftwarePaint, oracle_proxy),
    539       timer_subscriber_(VideoCaptureOracle::kTimerPoll, oracle_proxy),
    540       capture_callback_(capture_callback),
    541       timer_(true, true) {
    542   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    543 
    544   RenderWidgetHostViewPort* view =
    545       RenderWidgetHostViewPort::FromRWHV(source.GetView());
    546 
    547   // Subscribe to accelerated presents. These will be serviced directly by the
    548   // oracle.
    549   if (view && kAcceleratedSubscriberIsSupported) {
    550     scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
    551         new FrameSubscriber(VideoCaptureOracle::kCompositorUpdate,
    552             oracle_proxy));
    553     view->BeginFrameSubscription(subscriber.Pass());
    554   }
    555 
    556   // Subscribe to software paint events. This instance will service these by
    557   // reflecting them back to the CaptureMachine via |capture_callback|.
    558   registrar_.Add(
    559       this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE,
    560       Source<RenderWidgetHost>(&source));
    561 
    562   // Subscribe to timer events. This instance will service these as well.
    563   timer_.Start(FROM_HERE, oracle_proxy->capture_period(),
    564                base::Bind(&ContentCaptureSubscription::OnTimer,
    565                           base::Unretained(this)));
    566 }
    567 
    568 ContentCaptureSubscription::~ContentCaptureSubscription() {
    569   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    570   if (kAcceleratedSubscriberIsSupported) {
    571     RenderViewHost* source = RenderViewHost::FromID(render_process_id_,
    572                                                     render_view_id_);
    573     if (source) {
    574       RenderWidgetHostViewPort* view =
    575           RenderWidgetHostViewPort::FromRWHV(source->GetView());
    576       if (view)
    577         view->EndFrameSubscription();
    578     }
    579   }
    580 }
    581 
    582 void ContentCaptureSubscription::Observe(
    583     int type,
    584     const content::NotificationSource& source,
    585     const content::NotificationDetails& details) {
    586   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    587   DCHECK_EQ(NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, type);
    588 
    589   RenderWidgetHostImpl* rwh =
    590       RenderWidgetHostImpl::From(Source<RenderWidgetHost>(source).ptr());
    591 
    592   // This message occurs on window resizes and visibility changes even when
    593   // accelerated compositing is active, so we need to filter out these cases.
    594   if (!rwh || !rwh->GetView() || (rwh->is_accelerated_compositing_active() &&
    595                                   rwh->GetView()->IsSurfaceAvailableForCopy()))
    596     return;
    597 
    598   TRACE_EVENT1("mirroring", "ContentCaptureSubscription::Observe",
    599                "instance", this);
    600 
    601   base::Closure copy_done_callback;
    602   scoped_refptr<media::VideoFrame> frame;
    603   RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb;
    604   const base::Time start_time = base::Time::Now();
    605   if (paint_subscriber_.ShouldCaptureFrame(start_time,
    606                                            &frame,
    607                                            &deliver_frame_cb)) {
    608     // This message happens just before paint. If we post a task to do the copy,
    609     // it should run soon after the paint.
    610     BrowserThread::PostTask(
    611         BrowserThread::UI, FROM_HERE,
    612         base::Bind(capture_callback_, start_time, frame, deliver_frame_cb));
    613   }
    614 }
    615 
    616 void ContentCaptureSubscription::OnTimer() {
    617   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    618   TRACE_EVENT0("mirroring", "ContentCaptureSubscription::OnTimer");
    619 
    620   scoped_refptr<media::VideoFrame> frame;
    621   RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb;
    622 
    623   const base::Time start_time = base::Time::Now();
    624   if (timer_subscriber_.ShouldCaptureFrame(start_time,
    625                                            &frame,
    626                                            &deliver_frame_cb)) {
    627     capture_callback_.Run(start_time, frame, deliver_frame_cb);
    628   }
    629 }
    630 
    631 void RenderVideoFrame(const SkBitmap& input,
    632                       const scoped_refptr<media::VideoFrame>& output,
    633                       const base::Callback<void(bool)>& done_cb) {
    634   base::ScopedClosureRunner failure_handler(base::Bind(done_cb, false));
    635 
    636   SkAutoLockPixels locker(input);
    637 
    638   // Sanity-check the captured bitmap.
    639   if (input.empty() ||
    640       !input.readyToDraw() ||
    641       input.config() != SkBitmap::kARGB_8888_Config ||
    642       input.width() < 2 || input.height() < 2) {
    643     DVLOG(1) << "input unacceptable (size="
    644              << input.getSize()
    645              << ", ready=" << input.readyToDraw()
    646              << ", config=" << input.config() << ')';
    647     return;
    648   }
    649 
    650   // Sanity-check the output buffer.
    651   if (output->format() != media::VideoFrame::I420) {
    652     NOTREACHED();
    653     return;
    654   }
    655 
    656   // Calculate the width and height of the content region in the |output|, based
    657   // on the aspect ratio of |input|.
    658   gfx::Rect region_in_frame = ComputeYV12LetterboxRegion(
    659       output->coded_size(), gfx::Size(input.width(), input.height()));
    660 
    661   // Scale the bitmap to the required size, if necessary.
    662   SkBitmap scaled_bitmap;
    663   if (input.width() != region_in_frame.width() ||
    664       input.height() != region_in_frame.height()) {
    665 
    666     skia::ImageOperations::ResizeMethod method;
    667     if (input.width() < region_in_frame.width() ||
    668         input.height() < region_in_frame.height()) {
    669       // Avoid box filtering when magnifying, because it's actually
    670       // nearest-neighbor.
    671       method = skia::ImageOperations::RESIZE_HAMMING1;
    672     } else {
    673       method = skia::ImageOperations::RESIZE_BOX;
    674     }
    675 
    676     TRACE_EVENT_ASYNC_STEP0("mirroring", "Capture", output.get(), "Scale");
    677     scaled_bitmap = skia::ImageOperations::Resize(input, method,
    678                                                   region_in_frame.width(),
    679                                                   region_in_frame.height());
    680   } else {
    681     scaled_bitmap = input;
    682   }
    683 
    684   TRACE_EVENT_ASYNC_STEP0("mirroring", "Capture", output.get(), "YUV");
    685   {
    686     SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
    687 
    688     media::CopyRGBToVideoFrame(
    689         reinterpret_cast<uint8*>(scaled_bitmap.getPixels()),
    690         scaled_bitmap.rowBytes(),
    691         region_in_frame,
    692         output.get());
    693   }
    694 
    695   // The result is now ready.
    696   failure_handler.Release();
    697   done_cb.Run(true);
    698 }
    699 
    700 VideoFrameDeliveryLog::VideoFrameDeliveryLog()
    701     : last_frame_rate_log_time_(),
    702       count_frames_rendered_(0),
    703       last_frame_number_(0) {
    704 }
    705 
    706 void VideoFrameDeliveryLog::ChronicleFrameDelivery(int frame_number) {
    707   // Log frame rate, if verbose logging is turned on.
    708   static const base::TimeDelta kFrameRateLogInterval =
    709       base::TimeDelta::FromSeconds(10);
    710   const base::Time now = base::Time::Now();
    711   if (last_frame_rate_log_time_.is_null()) {
    712     last_frame_rate_log_time_ = now;
    713     count_frames_rendered_ = 0;
    714     last_frame_number_ = frame_number;
    715   } else {
    716     ++count_frames_rendered_;
    717     const base::TimeDelta elapsed = now - last_frame_rate_log_time_;
    718     if (elapsed >= kFrameRateLogInterval) {
    719       const double measured_fps =
    720           count_frames_rendered_ / elapsed.InSecondsF();
    721       const int frames_elapsed = frame_number - last_frame_number_;
    722       const int count_frames_dropped = frames_elapsed - count_frames_rendered_;
    723       DCHECK_LE(0, count_frames_dropped);
    724       UMA_HISTOGRAM_PERCENTAGE(
    725           "TabCapture.FrameDropPercentage",
    726           (count_frames_dropped * 100 + frames_elapsed / 2) / frames_elapsed);
    727       UMA_HISTOGRAM_COUNTS(
    728           "TabCapture.FrameRate",
    729           static_cast<int>(measured_fps));
    730       VLOG(1) << "Current measured frame rate for "
    731               << "WebContentsVideoCaptureDevice is " << measured_fps << " FPS.";
    732       last_frame_rate_log_time_ = now;
    733       count_frames_rendered_ = 0;
    734       last_frame_number_ = frame_number;
    735     }
    736   }
    737 }
    738 
    739 // static
    740 scoped_ptr<CaptureMachine> CaptureMachine::Create(
    741     int render_process_id,
    742     int render_view_id,
    743     const scoped_refptr<base::SequencedTaskRunner>& render_task_runner,
    744     const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) {
    745   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    746   DCHECK(render_task_runner.get());
    747   DCHECK(oracle_proxy.get());
    748   scoped_ptr<CaptureMachine> machine(
    749       new CaptureMachine(render_task_runner, oracle_proxy));
    750 
    751   if (!machine->StartObservingWebContents(render_process_id, render_view_id))
    752     machine.reset();
    753 
    754   return machine.Pass();
    755 }
    756 
    757 CaptureMachine::CaptureMachine(
    758     const scoped_refptr<base::SequencedTaskRunner>& render_task_runner,
    759     const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy)
    760     : render_task_runner_(render_task_runner),
    761       oracle_proxy_(oracle_proxy),
    762       fullscreen_widget_id_(MSG_ROUTING_NONE) {}
    763 
    764 CaptureMachine::~CaptureMachine() {
    765   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
    766          !BrowserThread::IsMessageLoopValid(BrowserThread::UI));
    767 
    768   // Stop observing the web contents.
    769   subscription_.reset();
    770   if (web_contents()) {
    771     web_contents()->DecrementCapturerCount();
    772     Observe(NULL);
    773   }
    774 }
    775 
    776 void CaptureMachine::Capture(
    777     const base::Time& start_time,
    778     const scoped_refptr<media::VideoFrame>& target,
    779     const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
    780         deliver_frame_cb) {
    781   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    782 
    783   RenderWidgetHost* rwh = GetTarget();
    784   RenderWidgetHostViewPort* view =
    785       rwh ? RenderWidgetHostViewPort::FromRWHV(rwh->GetView()) : NULL;
    786   if (!view || !rwh) {
    787     deliver_frame_cb.Run(base::Time(), false);
    788     return;
    789   }
    790 
    791   gfx::Size video_size = target->coded_size();
    792   gfx::Size view_size = view->GetViewBounds().size();
    793   gfx::Size fitted_size;
    794   if (!view_size.IsEmpty()) {
    795     fitted_size = ComputeYV12LetterboxRegion(video_size, view_size).size();
    796   }
    797   if (view_size != last_view_size_) {
    798     last_view_size_ = view_size;
    799 
    800     // Measure the number of kilopixels.
    801     UMA_HISTOGRAM_COUNTS_10000(
    802         "TabCapture.ViewChangeKiloPixels",
    803         view_size.width() * view_size.height() / 1024);
    804   }
    805 
    806   if (!view->IsSurfaceAvailableForCopy()) {
    807     // Fallback to the more expensive renderer-side copy if the surface and
    808     // backing store are not accessible.
    809     rwh->GetSnapshotFromRenderer(
    810         gfx::Rect(),
    811         base::Bind(&CaptureMachine::DidCopyFromBackingStore, this->AsWeakPtr(),
    812                    start_time, target, deliver_frame_cb));
    813   } else if (view->CanCopyToVideoFrame()) {
    814     view->CopyFromCompositingSurfaceToVideoFrame(
    815         gfx::Rect(view_size),
    816         target,
    817         base::Bind(&CaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame,
    818                    this->AsWeakPtr(), start_time, deliver_frame_cb));
    819   } else {
    820     rwh->CopyFromBackingStore(
    821         gfx::Rect(),
    822         fitted_size,  // Size here is a request not always honored.
    823         base::Bind(&CaptureMachine::DidCopyFromBackingStore, this->AsWeakPtr(),
    824                    start_time, target, deliver_frame_cb));
    825   }
    826 }
    827 
    828 bool CaptureMachine::StartObservingWebContents(int initial_render_process_id,
    829                                                int initial_render_view_id) {
    830   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    831 
    832   // Look-up the RenderViewHost and, from that, the WebContents that wraps it.
    833   // If successful, begin observing the WebContents instance.
    834   //
    835   // Why this can be unsuccessful: The request for mirroring originates in a
    836   // render process, and this request is based on the current RenderView
    837   // associated with a tab.  However, by the time we get up-and-running here,
    838   // there have been multiple back-and-forth IPCs between processes, as well as
    839   // a bit of indirection across threads.  It's easily possible that, in the
    840   // meantime, the original RenderView may have gone away.
    841   RenderViewHost* const rvh =
    842       RenderViewHost::FromID(initial_render_process_id,
    843                              initial_render_view_id);
    844   DVLOG_IF(1, !rvh) << "RenderViewHost::FromID("
    845                     << initial_render_process_id << ", "
    846                     << initial_render_view_id << ") returned NULL.";
    847   Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL);
    848 
    849   WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents());
    850   if (contents) {
    851     contents->IncrementCapturerCount();
    852     fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID();
    853     RenewFrameSubscription();
    854     return true;
    855   }
    856 
    857   DVLOG(1) << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL.";
    858   return false;
    859 }
    860 
    861 void CaptureMachine::WebContentsDestroyed(WebContents* web_contents) {
    862   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    863 
    864   subscription_.reset();
    865   web_contents->DecrementCapturerCount();
    866   oracle_proxy_->ReportError();
    867 }
    868 
    869 RenderWidgetHost* CaptureMachine::GetTarget() {
    870   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    871   if (!web_contents())
    872     return NULL;
    873 
    874   RenderWidgetHost* rwh = NULL;
    875   if (fullscreen_widget_id_ != MSG_ROUTING_NONE) {
    876     RenderProcessHost* process = web_contents()->GetRenderProcessHost();
    877     if (process)
    878       rwh = RenderWidgetHost::FromID(process->GetID(), fullscreen_widget_id_);
    879   } else {
    880     rwh = web_contents()->GetRenderViewHost();
    881   }
    882 
    883   return rwh;
    884 }
    885 
    886 void CaptureMachine::DidCopyFromBackingStore(
    887     const base::Time& start_time,
    888     const scoped_refptr<media::VideoFrame>& target,
    889     const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
    890         deliver_frame_cb,
    891     bool success,
    892     const SkBitmap& bitmap) {
    893   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    894 
    895   base::Time now = base::Time::Now();
    896   if (success) {
    897     UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
    898     TRACE_EVENT_ASYNC_STEP0("mirroring", "Capture", target.get(), "Render");
    899     render_task_runner_->PostTask(FROM_HERE, base::Bind(
    900         &RenderVideoFrame, bitmap, target,
    901         base::Bind(deliver_frame_cb, start_time)));
    902   } else {
    903     // Capture can fail due to transient issues, so just skip this frame.
    904     DVLOG(1) << "CopyFromBackingStore failed; skipping frame.";
    905     deliver_frame_cb.Run(start_time, false);
    906   }
    907 }
    908 
    909 void CaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
    910     const base::Time& start_time,
    911     const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
    912         deliver_frame_cb,
    913     bool success) {
    914   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    915   base::Time now = base::Time::Now();
    916 
    917   if (success) {
    918     UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time);
    919   } else {
    920     // Capture can fail due to transient issues, so just skip this frame.
    921     DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame.";
    922   }
    923   deliver_frame_cb.Run(start_time, success);
    924 }
    925 
    926 void CaptureMachine::RenewFrameSubscription() {
    927   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    928 
    929   // Always destroy the old subscription before creating a new one.
    930   subscription_.reset();
    931 
    932   RenderWidgetHost* rwh = GetTarget();
    933   if (!rwh || !rwh->GetView())
    934     return;
    935 
    936   subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_,
    937       base::Bind(&CaptureMachine::Capture, this->AsWeakPtr())));
    938 }
    939 
    940 void DeleteCaptureMachineOnUIThread(
    941     scoped_ptr<CaptureMachine> capture_machine) {
    942   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    943   capture_machine.reset();
    944 }
    945 
    946 }  // namespace
    947 
    948 // The "meat" of the video capture implementation, which is a ref-counted class.
    949 // Separating this from the "shell class" WebContentsVideoCaptureDevice allows
    950 // safe destruction without needing to block any threads (e.g., the IO
    951 // BrowserThread).
    952 //
    953 // WebContentsVideoCaptureDevice::Impl manages a simple state machine and the
    954 // pipeline (see notes at top of this file).  It times the start of successive
    955 // captures and facilitates the processing of each through the stages of the
    956 // pipeline.
    957 class WebContentsVideoCaptureDevice::Impl : public base::SupportsWeakPtr<Impl> {
    958  public:
    959 
    960   Impl(int render_process_id, int render_view_id);
    961   virtual ~Impl();
    962 
    963   // Asynchronous requests to change WebContentsVideoCaptureDevice::Impl state.
    964   void Allocate(int width,
    965                 int height,
    966                 int frame_rate,
    967                 media::VideoCaptureDevice::EventHandler* consumer);
    968   void Start();
    969   void Stop();
    970   void DeAllocate();
    971 
    972  private:
    973 
    974   // Flag indicating current state.
    975   enum State {
    976     kIdle,
    977     kAllocated,
    978     kCapturing,
    979     kError
    980   };
    981 
    982   void TransitionStateTo(State next_state);
    983 
    984   // Stops capturing and notifies consumer_ of an error state.
    985   void Error();
    986 
    987   // Called in response to CaptureMachine::Create that runs on the UI thread.
    988   // It will assign the capture machine to the Impl class if it still exists
    989   // otherwise it will post a task to delete CaptureMachine on the UI thread.
    990   static void AssignCaptureMachine(
    991       base::WeakPtr<WebContentsVideoCaptureDevice::Impl> impl,
    992       scoped_ptr<CaptureMachine> capture_machine);
    993 
    994   // Tracks that all activity occurs on the media stream manager's thread.
    995   base::ThreadChecker thread_checker_;
    996 
    997   // These values identify the starting view that will be captured. After
    998   // capture starts, the target view IDs will change as navigation occurs, and
    999   // so these values are not relevant after the initial bootstrapping.
   1000   const int initial_render_process_id_;
   1001   const int initial_render_view_id_;
   1002 
   1003   // Our event handler, which gobbles the frames we capture.
   1004   VideoCaptureDevice::EventHandler* consumer_;
   1005 
   1006   // Current lifecycle state.
   1007   State state_;
   1008 
   1009   // A dedicated worker thread for doing image operations. Started/joined here,
   1010   // but used by the CaptureMachine.
   1011   base::Thread render_thread_;
   1012 
   1013   // Tracks the CaptureMachine that's doing work on our behalf on the UI thread.
   1014   // This value should never be dereferenced by this class, other than to
   1015   // create and destroy it on the UI thread.
   1016   scoped_ptr<CaptureMachine> capture_machine_;
   1017 
   1018   // Our thread-safe capture oracle which serves as the gateway to the video
   1019   // capture pipeline. Besides the WCVCD itself, it is the only component of the
   1020   // system with direct access to |consumer_|.
   1021   scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
   1022 
   1023   DISALLOW_COPY_AND_ASSIGN(Impl);
   1024 };
   1025 
   1026 WebContentsVideoCaptureDevice::Impl::Impl(int render_process_id,
   1027                                           int render_view_id)
   1028     : initial_render_process_id_(render_process_id),
   1029       initial_render_view_id_(render_view_id),
   1030       consumer_(NULL),
   1031       state_(kIdle),
   1032       render_thread_("WebContentsVideo_RenderThread") {
   1033 }
   1034 
   1035 void WebContentsVideoCaptureDevice::Impl::Allocate(
   1036     int width,
   1037     int height,
   1038     int frame_rate,
   1039     VideoCaptureDevice::EventHandler* consumer) {
   1040   DCHECK(thread_checker_.CalledOnValidThread());
   1041 
   1042   if (state_ != kIdle) {
   1043     DVLOG(1) << "Allocate() invoked when not in state Idle.";
   1044     return;
   1045   }
   1046 
   1047   if (frame_rate <= 0) {
   1048     DVLOG(1) << "invalid frame_rate: " << frame_rate;
   1049     consumer->OnError();
   1050     return;
   1051   }
   1052 
   1053   if (!render_thread_.Start()) {
   1054     DVLOG(1) << "Failed to spawn render thread.";
   1055     consumer->OnError();
   1056     return;
   1057   }
   1058 
   1059   // Frame dimensions must each be a positive, even integer, since the consumer
   1060   // wants (or will convert to) YUV420.
   1061   width = MakeEven(width);
   1062   height = MakeEven(height);
   1063   if (width < kMinFrameWidth || height < kMinFrameHeight) {
   1064     DVLOG(1) << "invalid width (" << width << ") and/or height ("
   1065              << height << ")";
   1066     consumer->OnError();
   1067     return;
   1068   }
   1069 
   1070   // Initialize capture settings which will be consistent for the
   1071   // duration of the capture.
   1072   media::VideoCaptureCapability settings;
   1073 
   1074   settings.width = width;
   1075   settings.height = height;
   1076   settings.frame_rate = frame_rate;
   1077   // Note: the value of |settings.color| doesn't matter if we use only the
   1078   // VideoFrame based methods on |consumer|.
   1079   settings.color = media::VideoCaptureCapability::kI420;
   1080   settings.expected_capture_delay = 0;
   1081   settings.interlaced = false;
   1082 
   1083   base::TimeDelta capture_period = base::TimeDelta::FromMicroseconds(
   1084       1000000.0 / settings.frame_rate + 0.5);
   1085 
   1086   consumer_ = consumer;
   1087   consumer_->OnFrameInfo(settings);
   1088   scoped_ptr<VideoCaptureOracle> oracle(
   1089       new VideoCaptureOracle(capture_period,
   1090                              kAcceleratedSubscriberIsSupported));
   1091   oracle_proxy_ = new ThreadSafeCaptureOracle(
   1092       consumer_,
   1093       oracle.Pass());
   1094 
   1095   // Allocates the CaptureMachine. The CaptureMachine will be tracking render
   1096   // view swapping over its lifetime, and we don't want to lose our reference to
   1097   // the current render view by starting over with the stale
   1098   // |initial_render_view_id_|.
   1099   DCHECK(!capture_machine_.get());
   1100   BrowserThread::PostTaskAndReplyWithResult(
   1101       BrowserThread::UI, FROM_HERE,
   1102       base::Bind(&CaptureMachine::Create,
   1103                  initial_render_process_id_,
   1104                  initial_render_view_id_,
   1105                  render_thread_.message_loop_proxy(), oracle_proxy_),
   1106       base::Bind(&Impl::AssignCaptureMachine, AsWeakPtr()));
   1107 
   1108   TransitionStateTo(kAllocated);
   1109 }
   1110 
   1111 void WebContentsVideoCaptureDevice::Impl::Start() {
   1112   DCHECK(thread_checker_.CalledOnValidThread());
   1113 
   1114   if (state_ != kAllocated) {
   1115     return;
   1116   }
   1117 
   1118   TransitionStateTo(kCapturing);
   1119 
   1120   oracle_proxy_->Start();
   1121 }
   1122 
   1123 // static
   1124 void WebContentsVideoCaptureDevice::Impl::AssignCaptureMachine(
   1125     base::WeakPtr<WebContentsVideoCaptureDevice::Impl> impl,
   1126     scoped_ptr<CaptureMachine> capture_machine) {
   1127   DCHECK(!impl.get() || impl->thread_checker_.CalledOnValidThread());
   1128 
   1129   if (!impl.get()) {
   1130     // If WCVD::Impl was destroyed before we got back on it's thread and
   1131     // capture_machine is not NULL, then we need to return to the UI thread to
   1132     // safely cleanup the CaptureMachine.
   1133     if (capture_machine) {
   1134       BrowserThread::PostTask(
   1135           BrowserThread::UI, FROM_HERE, base::Bind(
   1136               &DeleteCaptureMachineOnUIThread, base::Passed(&capture_machine)));
   1137       return;
   1138     }
   1139   } else if (!capture_machine) {
   1140     impl->Error();
   1141   } else {
   1142     impl->capture_machine_ = capture_machine.Pass();
   1143   }
   1144 }
   1145 
   1146 void WebContentsVideoCaptureDevice::Impl::Stop() {
   1147   DCHECK(thread_checker_.CalledOnValidThread());
   1148 
   1149   if (state_ != kCapturing) {
   1150     return;
   1151   }
   1152   oracle_proxy_->Stop();
   1153 
   1154   TransitionStateTo(kAllocated);
   1155 }
   1156 
   1157 void WebContentsVideoCaptureDevice::Impl::DeAllocate() {
   1158   DCHECK(thread_checker_.CalledOnValidThread());
   1159   if (state_ == kCapturing) {
   1160     Stop();
   1161   }
   1162   if (state_ == kAllocated) {
   1163     // |consumer_| is about to be deleted, so we mustn't use it anymore.
   1164     oracle_proxy_->InvalidateConsumer();
   1165     consumer_ = NULL;
   1166     oracle_proxy_ = NULL;
   1167     render_thread_.Stop();
   1168 
   1169     TransitionStateTo(kIdle);
   1170   }
   1171 }
   1172 
   1173 WebContentsVideoCaptureDevice::Impl::~Impl() {
   1174   // There is still a capture pipeline running that is checking in with the
   1175   // oracle, and processing captures that are already started in flight. That
   1176   // pipeline must be shut down asynchronously, on the UI thread.
   1177   if (capture_machine_) {
   1178     // The task that is posted to the UI thread might not run if we are shutting
   1179     // down, so we transfer ownership of CaptureMachine to the closure so that
   1180     // it is still cleaned up when the closure is deleted.
   1181     BrowserThread::PostTask(
   1182         BrowserThread::UI, FROM_HERE, base::Bind(
   1183             &DeleteCaptureMachineOnUIThread, base::Passed(&capture_machine_)));
   1184   }
   1185 
   1186   DCHECK(!capture_machine_) << "Cleanup on UI thread did not happen.";
   1187   DCHECK(!consumer_) << "Device not DeAllocated -- possible data race.";
   1188   DVLOG(1) << "WebContentsVideoCaptureDevice::Impl@" << this << " destroying.";
   1189 }
   1190 
   1191 void WebContentsVideoCaptureDevice::Impl::TransitionStateTo(State next_state) {
   1192   DCHECK(thread_checker_.CalledOnValidThread());
   1193 
   1194 #ifndef NDEBUG
   1195   static const char* kStateNames[] = {
   1196     "Idle", "Allocated", "Capturing", "Error"
   1197   };
   1198   DVLOG(1) << "State change: " << kStateNames[state_]
   1199            << " --> " << kStateNames[next_state];
   1200 #endif
   1201 
   1202   state_ = next_state;
   1203 }
   1204 
   1205 void WebContentsVideoCaptureDevice::Impl::Error() {
   1206   DCHECK(thread_checker_.CalledOnValidThread());
   1207 
   1208   if (state_ == kIdle)
   1209     return;
   1210 
   1211   if (consumer_)
   1212     consumer_->OnError();
   1213 
   1214   DeAllocate();
   1215   TransitionStateTo(kError);
   1216 }
   1217 
   1218 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
   1219     const media::VideoCaptureDevice::Name& name,
   1220     int render_process_id,
   1221     int render_view_id)
   1222     : device_name_(name),
   1223       impl_(new WebContentsVideoCaptureDevice::Impl(render_process_id,
   1224                                                     render_view_id)) {}
   1225 
   1226 WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() {
   1227   DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying.";
   1228 }
   1229 
   1230 // static
   1231 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create(
   1232     const std::string& device_id) {
   1233   // Parse device_id into render_process_id and render_view_id.
   1234   int render_process_id = -1;
   1235   int render_view_id = -1;
   1236   if (!WebContentsCaptureUtil::ExtractTabCaptureTarget(device_id,
   1237                                                        &render_process_id,
   1238                                                        &render_view_id))
   1239     return NULL;
   1240 
   1241   std::string device_name;
   1242   base::SStringPrintf(&device_name,
   1243                       "WebContents[%.*s]",
   1244                       static_cast<int>(device_id.size()), device_id.data());
   1245   return new WebContentsVideoCaptureDevice(
   1246       media::VideoCaptureDevice::Name(device_name, device_id),
   1247       render_process_id, render_view_id);
   1248 }
   1249 
   1250 void WebContentsVideoCaptureDevice::Allocate(
   1251     const media::VideoCaptureCapability& capture_format,
   1252     VideoCaptureDevice::EventHandler* observer) {
   1253   DVLOG(1) << "Allocating " << capture_format.width << "x"
   1254            << capture_format.height;
   1255   impl_->Allocate(capture_format.width,
   1256                   capture_format.height,
   1257                   capture_format.frame_rate,
   1258                   observer);
   1259 }
   1260 
   1261 void WebContentsVideoCaptureDevice::Start() {
   1262   impl_->Start();
   1263 }
   1264 
   1265 void WebContentsVideoCaptureDevice::Stop() {
   1266   impl_->Stop();
   1267 }
   1268 
   1269 void WebContentsVideoCaptureDevice::DeAllocate() {
   1270   impl_->DeAllocate();
   1271 }
   1272 
   1273 const media::VideoCaptureDevice::Name&
   1274 WebContentsVideoCaptureDevice::device_name() {
   1275   return device_name_;
   1276 }
   1277 
   1278 }  // namespace content
   1279