Chromium Code Reviews| Index: content/browser/media/capture/web_contents_video_capture_device.cc |
| diff --git a/content/browser/media/capture/web_contents_video_capture_device.cc b/content/browser/media/capture/web_contents_video_capture_device.cc |
| index 64312d9a7c92fd296700e79464d0ecb1d8d004f6..265080ba181d383c910357418d9b0e2ba220ff8a 100644 |
| --- a/content/browser/media/capture/web_contents_video_capture_device.cc |
| +++ b/content/browser/media/capture/web_contents_video_capture_device.cc |
| @@ -50,6 +50,8 @@ |
| #include "content/browser/media/capture/web_contents_video_capture_device.h" |
| +#include <algorithm> |
| + |
| #include "base/basictypes.h" |
| #include "base/bind.h" |
| #include "base/callback_helpers.h" |
| @@ -63,6 +65,7 @@ |
| #include "base/threading/thread.h" |
| #include "base/threading/thread_checker.h" |
| #include "base/time/time.h" |
| +#include "content/browser/media/capture/cursor_renderer.h" |
| #include "content/browser/media/capture/web_contents_capture_util.h" |
| #include "content/browser/media/capture/web_contents_tracker.h" |
| #include "content/browser/renderer_host/render_widget_host_impl.h" |
| @@ -119,10 +122,12 @@ class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { |
| public: |
| FrameSubscriber(media::VideoCaptureOracle::Event event_type, |
| const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle, |
| - VideoFrameDeliveryLog* delivery_log) |
| + VideoFrameDeliveryLog* delivery_log, |
| + content::CursorRenderer* cursor_renderer) |
| : event_type_(event_type), |
| oracle_proxy_(oracle), |
| - delivery_log_(delivery_log) {} |
| + delivery_log_(delivery_log), |
| + cursor_renderer_(cursor_renderer) {} |
| bool ShouldCaptureFrame( |
| const gfx::Rect& damage_rect, |
| @@ -131,10 +136,18 @@ class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { |
| RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* |
| deliver_frame_cb) override; |
| + void DidCaptureFrame(const scoped_refptr<media::VideoFrame>& frame, |
| + base::TimeTicks timestamp, |
| + gfx::Rect region_in_frame, |
| + bool success); |
| + |
| private: |
| const media::VideoCaptureOracle::Event event_type_; |
| scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; |
| VideoFrameDeliveryLog* const delivery_log_; |
| + content::CursorRenderer* const cursor_renderer_; |
| + |
| + media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb_; |
| }; |
| // ContentCaptureSubscription is the relationship between a RenderWidgetHost |
| @@ -177,10 +190,15 @@ class ContentCaptureSubscription { |
| const int render_widget_id_; |
| VideoFrameDeliveryLog delivery_log_; |
| - FrameSubscriber timer_subscriber_; |
| + scoped_ptr<FrameSubscriber> timer_subscriber_; |
| CaptureCallback capture_callback_; |
| base::Timer timer_; |
| + // Responsible for tracking the cursor state and input events to make |
| + // decisions and then render the mouse cursor on the video frame after |
| + // capture is completed. |
| + scoped_ptr<content::CursorRenderer> cursor_renderer_; |
| + |
| DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription); |
| }; |
| @@ -195,7 +213,7 @@ class ContentCaptureSubscription { |
| // thread where such a pause would cause UI jank. |
| void RenderVideoFrame(const SkBitmap& input, |
| const scoped_refptr<media::VideoFrame>& output, |
| - const base::Callback<void(bool)>& done_cb); |
| + const base::Callback<void(gfx::Rect, bool)>& done_cb); |
| // Renews capture subscriptions based on feedback from WebContentsTracker, and |
| // also executes copying of the backing store on the UI BrowserThread. |
| @@ -249,6 +267,7 @@ class WebContentsCaptureMachine : public media::VideoCaptureMachine { |
| const base::TimeTicks& start_time, |
| const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
| deliver_frame_cb, |
| + gfx::Rect region_in_frame, |
| bool success); |
| // Remove the old subscription, and attempt to start a new one if |had_target| |
| @@ -303,17 +322,29 @@ bool FrameSubscriber::ShouldCaptureFrame( |
| TRACE_EVENT1("gpu.capture", "FrameSubscriber::ShouldCaptureFrame", |
| "instance", this); |
| - media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; |
| bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture( |
| - event_type_, damage_rect, present_time, storage, &capture_frame_cb); |
| + event_type_, damage_rect, present_time, storage, &capture_frame_cb_); |
|
miu
2015/10/20 02:12:44
Unfortunately, you can't store this in a single |c
Irfan
2015/10/21 23:01:08
Done.
|
| - if (!capture_frame_cb.is_null()) |
| - *deliver_frame_cb = base::Bind(capture_frame_cb, *storage); |
| + if (!capture_frame_cb_.is_null()) |
| + *deliver_frame_cb = base::Bind(&FrameSubscriber::DidCaptureFrame, |
| + base::Unretained(this), *storage); |
| if (oracle_decision) |
| delivery_log_->ChronicleFrameDelivery(present_time); |
| return oracle_decision; |
| } |
| +void FrameSubscriber::DidCaptureFrame( |
| + const scoped_refptr<media::VideoFrame>& frame, |
| + base::TimeTicks timestamp, |
| + gfx::Rect region_in_frame, |
| + bool success) { |
| + if (cursor_renderer_ && success) { |
| + if (cursor_renderer_->Update(region_in_frame)) |
| + cursor_renderer_->RenderOnVideoFrame(frame); |
| + } |
| + capture_frame_cb_.Run(frame, timestamp, success); |
| +} |
| + |
| ContentCaptureSubscription::ContentCaptureSubscription( |
| const RenderWidgetHost& source, |
| const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, |
| @@ -321,20 +352,24 @@ ContentCaptureSubscription::ContentCaptureSubscription( |
| : render_process_id_(source.GetProcess()->GetID()), |
| render_widget_id_(source.GetRoutingID()), |
| delivery_log_(), |
| - timer_subscriber_(media::VideoCaptureOracle::kTimerPoll, oracle_proxy, |
| - &delivery_log_), |
| capture_callback_(capture_callback), |
| timer_(true, true) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| RenderWidgetHostView* const view = source.GetView(); |
| + cursor_renderer_.reset(new content::CursorRenderer( |
|
miu
2015/10/20 02:12:44
nit: These can go back into the initializer list a
Irfan
2015/10/21 23:01:08
I retained this mainly because it depends on fetch
|
| + view->GetNativeView(), content::ENABLE_MOUSE_EVENTS)); |
| + timer_subscriber_.reset( |
| + new FrameSubscriber(media::VideoCaptureOracle::kTimerPoll, oracle_proxy, |
| + &delivery_log_, cursor_renderer_.get())); |
| // Subscribe to compositor updates. These will be serviced directly by the |
| // oracle. |
| if (view) { |
| scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( |
| new FrameSubscriber(media::VideoCaptureOracle::kCompositorUpdate, |
| - oracle_proxy, &delivery_log_)); |
| + oracle_proxy, &delivery_log_, |
| + cursor_renderer_.get())); |
| view->BeginFrameSubscription(subscriber.Pass()); |
| } |
| @@ -370,18 +405,17 @@ void ContentCaptureSubscription::OnTimer() { |
| RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb; |
| const base::TimeTicks start_time = base::TimeTicks::Now(); |
| - if (timer_subscriber_.ShouldCaptureFrame(gfx::Rect(), |
| - start_time, |
| - &frame, |
| - &deliver_frame_cb)) { |
| + if (timer_subscriber_->ShouldCaptureFrame(gfx::Rect(), start_time, &frame, |
| + &deliver_frame_cb)) { |
| capture_callback_.Run(start_time, frame, deliver_frame_cb); |
| } |
| } |
| void RenderVideoFrame(const SkBitmap& input, |
| const scoped_refptr<media::VideoFrame>& output, |
| - const base::Callback<void(bool)>& done_cb) { |
| - base::ScopedClosureRunner failure_handler(base::Bind(done_cb, false)); |
| + const base::Callback<void(gfx::Rect, bool)>& done_cb) { |
| + base::ScopedClosureRunner failure_handler( |
| + base::Bind(done_cb, gfx::Rect(), false)); |
| SkAutoLockPixels locker(input); |
| @@ -412,7 +446,6 @@ void RenderVideoFrame(const SkBitmap& input, |
| SkBitmap scaled_bitmap; |
| if (input.width() != region_in_frame.width() || |
| input.height() != region_in_frame.height()) { |
| - |
| skia::ImageOperations::ResizeMethod method; |
| if (input.width() < region_in_frame.width() || |
| input.height() < region_in_frame.height()) { |
| @@ -453,7 +486,7 @@ void RenderVideoFrame(const SkBitmap& input, |
| // The result is now ready. |
| ignore_result(failure_handler.Release()); |
| - done_cb.Run(true); |
| + done_cb.Run(region_in_frame, true); |
| } |
| VideoFrameDeliveryLog::VideoFrameDeliveryLog() |
| @@ -597,7 +630,7 @@ void WebContentsCaptureMachine::Capture( |
| RenderWidgetHostViewBase* view = |
| rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL; |
| if (!view) { |
| - deliver_frame_cb.Run(base::TimeTicks(), false); |
| + deliver_frame_cb.Run(base::TimeTicks(), gfx::Rect(), false); |
| return; |
| } |
| @@ -722,7 +755,7 @@ void WebContentsCaptureMachine::DidCopyFromBackingStore( |
| } else { |
| // Capture can fail due to transient issues, so just skip this frame. |
| DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; |
| - deliver_frame_cb.Run(start_time, false); |
| + deliver_frame_cb.Run(start_time, gfx::Rect(), false); |
| } |
| } |
| @@ -730,6 +763,7 @@ void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( |
| const base::TimeTicks& start_time, |
| const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
| deliver_frame_cb, |
| + gfx::Rect region_in_frame, |
| bool success) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| base::TimeTicks now = base::TimeTicks::Now(); |
| @@ -740,7 +774,7 @@ void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( |
| // Capture can fail due to transient issues, so just skip this frame. |
| DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; |
| } |
| - deliver_frame_cb.Run(start_time, success); |
| + deliver_frame_cb.Run(start_time, region_in_frame, success); |
| } |
| void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) { |