Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: content/browser/media/capture/web_contents_video_capture_device.cc

Issue 1412173003: cast: support cursor rendering for tab capture (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add missing cursor renderer files in repo Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // Implementation notes: This needs to work on a variety of hardware 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 6 // configurations where the speed of the CPU and GPU greatly affect overall
7 // performance. Spanning several threads, the process of capturing has been 7 // performance. Spanning several threads, the process of capturing has been
8 // split up into four conceptual stages: 8 // split up into four conceptual stages:
9 // 9 //
10 // 1. Reserve Buffer: Before a frame can be captured, a slot in the client's 10 // 1. Reserve Buffer: Before a frame can be captured, a slot in the client's
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 // 43 //
44 // In the above example, both capturing and rendering *each* take almost the 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 45 // full 33 ms available between frames, yet we see that the required throughput
46 // is obtained. 46 // is obtained.
47 // 47 //
48 // Turning on verbose logging will cause the effective frame rate to be logged 48 // Turning on verbose logging will cause the effective frame rate to be logged
49 // at 5-second intervals. 49 // at 5-second intervals.
50 50
51 #include "content/browser/media/capture/web_contents_video_capture_device.h" 51 #include "content/browser/media/capture/web_contents_video_capture_device.h"
52 52
53 #include <algorithm>
xjz 2015/10/22 17:08:42 Still think no need to include this.
Irfan 2015/10/26 23:10:32 This was a lint error unrelated to my code change
54
53 #include "base/basictypes.h" 55 #include "base/basictypes.h"
54 #include "base/bind.h" 56 #include "base/bind.h"
55 #include "base/callback_helpers.h" 57 #include "base/callback_helpers.h"
56 #include "base/location.h" 58 #include "base/location.h"
57 #include "base/logging.h" 59 #include "base/logging.h"
58 #include "base/memory/scoped_ptr.h" 60 #include "base/memory/scoped_ptr.h"
59 #include "base/memory/weak_ptr.h" 61 #include "base/memory/weak_ptr.h"
60 #include "base/metrics/histogram.h" 62 #include "base/metrics/histogram.h"
61 #include "base/sequenced_task_runner.h" 63 #include "base/sequenced_task_runner.h"
62 #include "base/single_thread_task_runner.h" 64 #include "base/single_thread_task_runner.h"
63 #include "base/threading/thread.h" 65 #include "base/threading/thread.h"
64 #include "base/threading/thread_checker.h" 66 #include "base/threading/thread_checker.h"
65 #include "base/time/time.h" 67 #include "base/time/time.h"
68 #include "content/browser/media/capture/cursor_renderer.h"
66 #include "content/browser/media/capture/web_contents_capture_util.h" 69 #include "content/browser/media/capture/web_contents_capture_util.h"
67 #include "content/browser/media/capture/web_contents_tracker.h" 70 #include "content/browser/media/capture/web_contents_tracker.h"
68 #include "content/browser/renderer_host/render_widget_host_impl.h" 71 #include "content/browser/renderer_host/render_widget_host_impl.h"
69 #include "content/browser/renderer_host/render_widget_host_view_base.h" 72 #include "content/browser/renderer_host/render_widget_host_view_base.h"
70 #include "content/public/browser/browser_thread.h" 73 #include "content/public/browser/browser_thread.h"
71 #include "content/public/browser/render_process_host.h" 74 #include "content/public/browser/render_process_host.h"
72 #include "content/public/browser/render_widget_host_view.h" 75 #include "content/public/browser/render_widget_host_view.h"
73 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" 76 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
74 #include "content/public/browser/web_contents.h" 77 #include "content/public/browser/web_contents.h"
75 #include "media/base/video_capture_types.h" 78 #include "media/base/video_capture_types.h"
76 #include "media/base/video_util.h" 79 #include "media/base/video_util.h"
77 #include "media/capture/content/screen_capture_device_core.h" 80 #include "media/capture/content/screen_capture_device_core.h"
78 #include "media/capture/content/thread_safe_capture_oracle.h" 81 #include "media/capture/content/thread_safe_capture_oracle.h"
79 #include "media/capture/content/video_capture_oracle.h" 82 #include "media/capture/content/video_capture_oracle.h"
80 #include "skia/ext/image_operations.h" 83 #include "skia/ext/image_operations.h"
81 #include "third_party/skia/include/core/SkBitmap.h" 84 #include "third_party/skia/include/core/SkBitmap.h"
82 #include "third_party/skia/include/core/SkColor.h" 85 #include "third_party/skia/include/core/SkColor.h"
83 #include "ui/base/layout.h" 86 #include "ui/base/layout.h"
84 #include "ui/gfx/geometry/dip_util.h" 87 #include "ui/gfx/geometry/dip_util.h"
85 #include "ui/gfx/geometry/size_conversions.h" 88 #include "ui/gfx/geometry/size_conversions.h"
86 89
90 #if defined(USE_AURA)
91 #include "content/browser/media/capture/cursor_renderer_aura.h"
92 #else
93 #include "content/browser/media/capture/cursor_renderer_dummy.h"
miu 2015/10/23 01:55:13 Suggest you don't provide the #else clause. See c
Irfan 2015/10/26 23:10:31 Done.
94 #endif
95
87 namespace content { 96 namespace content {
88 97
89 namespace { 98 namespace {
90 99
91 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread, 100 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread,
92 const base::Closure& callback) { 101 const base::Closure& callback) {
93 render_thread.reset(); 102 render_thread.reset();
94 103
95 // After thread join call the callback on UI thread. 104 // After thread join call the callback on UI thread.
96 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); 105 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
(...skipping 15 matching lines...) Expand all
112 121
113 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog); 122 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog);
114 }; 123 };
115 124
116 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible 125 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible
117 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. 126 // with RenderWidgetHostViewFrameSubscriber. We create one per event type.
118 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { 127 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
119 public: 128 public:
120 FrameSubscriber(media::VideoCaptureOracle::Event event_type, 129 FrameSubscriber(media::VideoCaptureOracle::Event event_type,
121 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle, 130 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle,
122 VideoFrameDeliveryLog* delivery_log) 131 VideoFrameDeliveryLog* delivery_log,
132 base::WeakPtr<content::CursorRenderer> cursor_renderer)
123 : event_type_(event_type), 133 : event_type_(event_type),
124 oracle_proxy_(oracle), 134 oracle_proxy_(oracle),
125 delivery_log_(delivery_log) {} 135 delivery_log_(delivery_log),
136 cursor_renderer_(cursor_renderer),
137 weak_ptr_factory_(this) {}
126 138
127 bool ShouldCaptureFrame( 139 bool ShouldCaptureFrame(
128 const gfx::Rect& damage_rect, 140 const gfx::Rect& damage_rect,
129 base::TimeTicks present_time, 141 base::TimeTicks present_time,
130 scoped_refptr<media::VideoFrame>* storage, 142 scoped_refptr<media::VideoFrame>* storage,
131 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* 143 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback*
132 deliver_frame_cb) override; 144 deliver_frame_cb) override;
133 145
146 static void DidCaptureFrame(
147 base::WeakPtr<FrameSubscriber> frame_subscriber_,
148 media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb,
miu 2015/10/23 01:55:13 Please pass the callback by const reference. The
Irfan 2015/10/26 23:10:32 Done.
149 const scoped_refptr<media::VideoFrame>& frame,
150 base::TimeTicks timestamp,
151 gfx::Rect region_in_frame,
miu 2015/10/23 01:55:13 The gfx::Rect should be passed by const reference
Irfan 2015/10/26 23:10:32 Done.
152 bool success);
153
134 private: 154 private:
135 const media::VideoCaptureOracle::Event event_type_; 155 const media::VideoCaptureOracle::Event event_type_;
136 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; 156 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_;
137 VideoFrameDeliveryLog* const delivery_log_; 157 VideoFrameDeliveryLog* const delivery_log_;
158 base::WeakPtr<content::CursorRenderer> cursor_renderer_;
miu 2015/10/23 01:55:13 Please document why we need a weak pointer to the
miu 2015/10/23 01:55:13 No need for content:: qualifier.
Irfan 2015/10/26 23:10:31 Done.
Irfan 2015/10/26 23:10:32 Done.
159 base::WeakPtrFactory<FrameSubscriber> weak_ptr_factory_;
138 }; 160 };
139 161
140 // ContentCaptureSubscription is the relationship between a RenderWidgetHost 162 // ContentCaptureSubscription is the relationship between a RenderWidgetHost
141 // whose content is updating, a subscriber that is deciding which of these 163 // whose content is updating, a subscriber that is deciding which of these
142 // updates to capture (and where to deliver them to), and a callback that 164 // updates to capture (and where to deliver them to), and a callback that
143 // knows how to do the capture and prepare the result for delivery. 165 // knows how to do the capture and prepare the result for delivery.
144 // 166 //
145 // In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in 167 // In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in
146 // the RenderWidgetHostView, to process compositor updates, and (b) running a 168 // the RenderWidgetHostView, to process compositor updates, and (b) running a
147 // timer to possibly initiate forced, non-event-driven captures needed by 169 // timer to possibly initiate forced, non-event-driven captures needed by
(...skipping 22 matching lines...) Expand all
170 private: 192 private:
171 void OnTimer(); 193 void OnTimer();
172 194
173 // Maintain a weak reference to the RenderWidgetHost (via its routing ID), 195 // Maintain a weak reference to the RenderWidgetHost (via its routing ID),
174 // since the instance could be destroyed externally during the lifetime of 196 // since the instance could be destroyed externally during the lifetime of
175 // |this|. 197 // |this|.
176 const int render_process_id_; 198 const int render_process_id_;
177 const int render_widget_id_; 199 const int render_widget_id_;
178 200
179 VideoFrameDeliveryLog delivery_log_; 201 VideoFrameDeliveryLog delivery_log_;
180 FrameSubscriber timer_subscriber_; 202 scoped_ptr<FrameSubscriber> timer_subscriber_;
181 CaptureCallback capture_callback_; 203 CaptureCallback capture_callback_;
182 base::Timer timer_; 204 base::Timer timer_;
183 205
206 // Responsible for tracking the cursor state and input events to make
207 // decisions and then render the mouse cursor on the video frame after
208 // capture is completed.
209 scoped_ptr<content::CursorRenderer> cursor_renderer_;
210
184 DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription); 211 DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription);
185 }; 212 };
186 213
187 // Render the SkBitmap |input| into the given VideoFrame buffer |output|, then 214 // Render the SkBitmap |input| into the given VideoFrame buffer |output|, then
188 // invoke |done_cb| to indicate success or failure. |input| is expected to be 215 // invoke |done_cb| to indicate success or failure. |input| is expected to be
189 // ARGB. |output| must be YV12 or I420. Colorspace conversion is always done. 216 // ARGB. |output| must be YV12 or I420. Colorspace conversion is always done.
190 // Scaling and letterboxing will be done as needed. 217 // Scaling and letterboxing will be done as needed.
191 // 218 //
192 // This software implementation should be used only when GPU acceleration of 219 // This software implementation should be used only when GPU acceleration of
193 // these activities is not possible. This operation may be expensive (tens to 220 // these activities is not possible. This operation may be expensive (tens to
194 // hundreds of milliseconds), so the caller should ensure that it runs on a 221 // hundreds of milliseconds), so the caller should ensure that it runs on a
195 // thread where such a pause would cause UI jank. 222 // thread where such a pause would cause UI jank.
196 void RenderVideoFrame(const SkBitmap& input, 223 void RenderVideoFrame(const SkBitmap& input,
197 const scoped_refptr<media::VideoFrame>& output, 224 const scoped_refptr<media::VideoFrame>& output,
198 const base::Callback<void(bool)>& done_cb); 225 const base::Callback<void(gfx::Rect, bool)>& done_cb);
199 226
200 // Renews capture subscriptions based on feedback from WebContentsTracker, and 227 // Renews capture subscriptions based on feedback from WebContentsTracker, and
201 // also executes copying of the backing store on the UI BrowserThread. 228 // also executes copying of the backing store on the UI BrowserThread.
202 class WebContentsCaptureMachine : public media::VideoCaptureMachine { 229 class WebContentsCaptureMachine : public media::VideoCaptureMachine {
203 public: 230 public:
204 WebContentsCaptureMachine(int render_process_id, 231 WebContentsCaptureMachine(int render_process_id,
205 int main_render_frame_id, 232 int main_render_frame_id,
206 bool enable_auto_throttling); 233 bool enable_auto_throttling);
207 ~WebContentsCaptureMachine() override; 234 ~WebContentsCaptureMachine() override;
208 235
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 269 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
243 deliver_frame_cb, 270 deliver_frame_cb,
244 const SkBitmap& bitmap, 271 const SkBitmap& bitmap,
245 ReadbackResponse response); 272 ReadbackResponse response);
246 273
247 // Response callback for RWHVP::CopyFromCompositingSurfaceToVideoFrame(). 274 // Response callback for RWHVP::CopyFromCompositingSurfaceToVideoFrame().
248 void DidCopyFromCompositingSurfaceToVideoFrame( 275 void DidCopyFromCompositingSurfaceToVideoFrame(
249 const base::TimeTicks& start_time, 276 const base::TimeTicks& start_time,
250 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 277 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
251 deliver_frame_cb, 278 deliver_frame_cb,
279 gfx::Rect region_in_frame,
252 bool success); 280 bool success);
253 281
254 // Remove the old subscription, and attempt to start a new one if |had_target| 282 // Remove the old subscription, and attempt to start a new one if |had_target|
255 // is true. 283 // is true.
256 void RenewFrameSubscription(bool had_target); 284 void RenewFrameSubscription(bool had_target);
257 285
258 // Called whenever the render widget is resized. 286 // Called whenever the render widget is resized.
259 void UpdateCaptureSize(); 287 void UpdateCaptureSize();
260 288
261 // Parameters saved in constructor. 289 // Parameters saved in constructor.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 325
298 bool FrameSubscriber::ShouldCaptureFrame( 326 bool FrameSubscriber::ShouldCaptureFrame(
299 const gfx::Rect& damage_rect, 327 const gfx::Rect& damage_rect,
300 base::TimeTicks present_time, 328 base::TimeTicks present_time,
301 scoped_refptr<media::VideoFrame>* storage, 329 scoped_refptr<media::VideoFrame>* storage,
302 DeliverFrameCallback* deliver_frame_cb) { 330 DeliverFrameCallback* deliver_frame_cb) {
303 TRACE_EVENT1("gpu.capture", "FrameSubscriber::ShouldCaptureFrame", 331 TRACE_EVENT1("gpu.capture", "FrameSubscriber::ShouldCaptureFrame",
304 "instance", this); 332 "instance", this);
305 333
306 media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; 334 media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
335
307 bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture( 336 bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture(
308 event_type_, damage_rect, present_time, storage, &capture_frame_cb); 337 event_type_, damage_rect, present_time, storage, &capture_frame_cb);
309 338
310 if (!capture_frame_cb.is_null()) 339 if (!capture_frame_cb.is_null())
311 *deliver_frame_cb = base::Bind(capture_frame_cb, *storage); 340 *deliver_frame_cb =
341 base::Bind(&FrameSubscriber::DidCaptureFrame,
342 weak_ptr_factory_.GetWeakPtr(), capture_frame_cb, *storage);
312 if (oracle_decision) 343 if (oracle_decision)
313 delivery_log_->ChronicleFrameDelivery(present_time); 344 delivery_log_->ChronicleFrameDelivery(present_time);
314 return oracle_decision; 345 return oracle_decision;
315 } 346 }
316 347
348 void FrameSubscriber::DidCaptureFrame(
349 base::WeakPtr<FrameSubscriber> frame_subscriber_,
350 media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb,
351 const scoped_refptr<media::VideoFrame>& frame,
352 base::TimeTicks timestamp,
353 gfx::Rect region_in_frame,
354 bool success) {
355 DCHECK_CURRENTLY_ON(BrowserThread::UI);
356 if (frame_subscriber_ && frame_subscriber_->cursor_renderer_ && success) {
357 if (frame_subscriber_->cursor_renderer_->Update(region_in_frame))
miu 2015/10/23 01:55:13 Some considerations on the timing of the call to U
Irfan 2015/10/26 23:10:32 I went with a comment to see if it affects any sce
358 frame_subscriber_->cursor_renderer_->RenderOnVideoFrame(frame);
359 }
360 capture_frame_cb.Run(frame, timestamp, success);
361 }
362
317 ContentCaptureSubscription::ContentCaptureSubscription( 363 ContentCaptureSubscription::ContentCaptureSubscription(
318 const RenderWidgetHost& source, 364 const RenderWidgetHost& source,
319 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, 365 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy,
320 const CaptureCallback& capture_callback) 366 const CaptureCallback& capture_callback)
321 : render_process_id_(source.GetProcess()->GetID()), 367 : render_process_id_(source.GetProcess()->GetID()),
322 render_widget_id_(source.GetRoutingID()), 368 render_widget_id_(source.GetRoutingID()),
323 delivery_log_(), 369 delivery_log_(),
324 timer_subscriber_(media::VideoCaptureOracle::kTimerPoll, oracle_proxy,
325 &delivery_log_),
326 capture_callback_(capture_callback), 370 capture_callback_(capture_callback),
327 timer_(true, true) { 371 timer_(true, true) {
328 DCHECK_CURRENTLY_ON(BrowserThread::UI); 372 DCHECK_CURRENTLY_ON(BrowserThread::UI);
329 373
330 RenderWidgetHostView* const view = source.GetView(); 374 RenderWidgetHostView* const view = source.GetView();
375 if (view)
376 #if defined(USE_AURA)
377 cursor_renderer_.reset(
378 new content::CursorRendererAura(view->GetNativeView()));
379 #else
380 cursor_renderer_.reset(
miu 2015/10/23 01:55:13 Please remove the #else clause here. In Chromium
Irfan 2015/10/26 23:10:32 Done.
381 new content::CursorRendererDummy(view->GetNativeView()));
382 #endif
383 timer_subscriber_.reset(
384 new FrameSubscriber(media::VideoCaptureOracle::kTimerPoll, oracle_proxy,
385 &delivery_log_, cursor_renderer_->GetWeakPtr()));
331 386
332 // Subscribe to compositor updates. These will be serviced directly by the 387 // Subscribe to compositor updates. These will be serviced directly by the
333 // oracle. 388 // oracle.
334 if (view) { 389 if (view) {
335 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( 390 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
336 new FrameSubscriber(media::VideoCaptureOracle::kCompositorUpdate, 391 new FrameSubscriber(media::VideoCaptureOracle::kCompositorUpdate,
337 oracle_proxy, &delivery_log_)); 392 oracle_proxy, &delivery_log_,
393 cursor_renderer_->GetWeakPtr()));
338 view->BeginFrameSubscription(subscriber.Pass()); 394 view->BeginFrameSubscription(subscriber.Pass());
339 } 395 }
340 396
341 // Subscribe to timer events. This instance will service these as well. 397 // Subscribe to timer events. This instance will service these as well.
342 timer_.Start(FROM_HERE, 398 timer_.Start(FROM_HERE,
343 std::max(oracle_proxy->min_capture_period(), 399 std::max(oracle_proxy->min_capture_period(),
344 base::TimeDelta::FromMilliseconds(media 400 base::TimeDelta::FromMilliseconds(media
345 ::VideoCaptureOracle::kMinTimerPollPeriodMillis)), 401 ::VideoCaptureOracle::kMinTimerPollPeriodMillis)),
346 base::Bind(&ContentCaptureSubscription::OnTimer, 402 base::Bind(&ContentCaptureSubscription::OnTimer,
347 base::Unretained(this))); 403 base::Unretained(this)));
(...skipping 15 matching lines...) Expand all
363 } 419 }
364 420
365 void ContentCaptureSubscription::OnTimer() { 421 void ContentCaptureSubscription::OnTimer() {
366 DCHECK_CURRENTLY_ON(BrowserThread::UI); 422 DCHECK_CURRENTLY_ON(BrowserThread::UI);
367 TRACE_EVENT0("gpu.capture", "ContentCaptureSubscription::OnTimer"); 423 TRACE_EVENT0("gpu.capture", "ContentCaptureSubscription::OnTimer");
368 424
369 scoped_refptr<media::VideoFrame> frame; 425 scoped_refptr<media::VideoFrame> frame;
370 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb; 426 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb;
371 427
372 const base::TimeTicks start_time = base::TimeTicks::Now(); 428 const base::TimeTicks start_time = base::TimeTicks::Now();
373 if (timer_subscriber_.ShouldCaptureFrame(gfx::Rect(), 429 if (timer_subscriber_->ShouldCaptureFrame(gfx::Rect(), start_time, &frame,
374 start_time, 430 &deliver_frame_cb)) {
375 &frame,
376 &deliver_frame_cb)) {
377 capture_callback_.Run(start_time, frame, deliver_frame_cb); 431 capture_callback_.Run(start_time, frame, deliver_frame_cb);
378 } 432 }
379 } 433 }
380 434
381 void RenderVideoFrame(const SkBitmap& input, 435 void RenderVideoFrame(const SkBitmap& input,
382 const scoped_refptr<media::VideoFrame>& output, 436 const scoped_refptr<media::VideoFrame>& output,
383 const base::Callback<void(bool)>& done_cb) { 437 const base::Callback<void(gfx::Rect, bool)>& done_cb) {
384 base::ScopedClosureRunner failure_handler(base::Bind(done_cb, false)); 438 base::ScopedClosureRunner failure_handler(
439 base::Bind(done_cb, gfx::Rect(), false));
385 440
386 SkAutoLockPixels locker(input); 441 SkAutoLockPixels locker(input);
387 442
388 // Sanity-check the captured bitmap. 443 // Sanity-check the captured bitmap.
389 if (input.empty() || 444 if (input.empty() ||
390 !input.readyToDraw() || 445 !input.readyToDraw() ||
391 input.colorType() != kN32_SkColorType || 446 input.colorType() != kN32_SkColorType ||
392 input.width() < 2 || input.height() < 2) { 447 input.width() < 2 || input.height() < 2) {
393 DVLOG(1) << "input unacceptable (size=" 448 DVLOG(1) << "input unacceptable (size="
394 << input.getSize() 449 << input.getSize()
(...skipping 10 matching lines...) Expand all
405 460
406 // Calculate the width and height of the content region in the |output|, based 461 // Calculate the width and height of the content region in the |output|, based
407 // on the aspect ratio of |input|. 462 // on the aspect ratio of |input|.
408 const gfx::Rect region_in_frame = media::ComputeLetterboxRegion( 463 const gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
409 output->visible_rect(), gfx::Size(input.width(), input.height())); 464 output->visible_rect(), gfx::Size(input.width(), input.height()));
410 465
411 // Scale the bitmap to the required size, if necessary. 466 // Scale the bitmap to the required size, if necessary.
412 SkBitmap scaled_bitmap; 467 SkBitmap scaled_bitmap;
413 if (input.width() != region_in_frame.width() || 468 if (input.width() != region_in_frame.width() ||
414 input.height() != region_in_frame.height()) { 469 input.height() != region_in_frame.height()) {
415
416 skia::ImageOperations::ResizeMethod method; 470 skia::ImageOperations::ResizeMethod method;
417 if (input.width() < region_in_frame.width() || 471 if (input.width() < region_in_frame.width() ||
418 input.height() < region_in_frame.height()) { 472 input.height() < region_in_frame.height()) {
419 // Avoid box filtering when magnifying, because it's actually 473 // Avoid box filtering when magnifying, because it's actually
420 // nearest-neighbor. 474 // nearest-neighbor.
421 method = skia::ImageOperations::RESIZE_HAMMING1; 475 method = skia::ImageOperations::RESIZE_HAMMING1;
422 } else { 476 } else {
423 method = skia::ImageOperations::RESIZE_BOX; 477 method = skia::ImageOperations::RESIZE_BOX;
424 } 478 }
425 479
(...skipping 20 matching lines...) Expand all
446 SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap); 500 SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
447 media::CopyRGBToVideoFrame( 501 media::CopyRGBToVideoFrame(
448 reinterpret_cast<uint8*>(scaled_bitmap.getPixels()), 502 reinterpret_cast<uint8*>(scaled_bitmap.getPixels()),
449 scaled_bitmap.rowBytes(), 503 scaled_bitmap.rowBytes(),
450 region_in_yv12_frame, 504 region_in_yv12_frame,
451 output.get()); 505 output.get());
452 } 506 }
453 507
454 // The result is now ready. 508 // The result is now ready.
455 ignore_result(failure_handler.Release()); 509 ignore_result(failure_handler.Release());
456 done_cb.Run(true); 510 done_cb.Run(region_in_frame, true);
457 } 511 }
458 512
459 VideoFrameDeliveryLog::VideoFrameDeliveryLog() 513 VideoFrameDeliveryLog::VideoFrameDeliveryLog()
460 : last_frame_rate_log_time_(), 514 : last_frame_rate_log_time_(),
461 count_frames_rendered_(0) { 515 count_frames_rendered_(0) {
462 } 516 }
463 517
464 void VideoFrameDeliveryLog::ChronicleFrameDelivery(base::TimeTicks frame_time) { 518 void VideoFrameDeliveryLog::ChronicleFrameDelivery(base::TimeTicks frame_time) {
465 // Log frame rate, if verbose logging is turned on. 519 // Log frame rate, if verbose logging is turned on.
466 static const base::TimeDelta kFrameRateLogInterval = 520 static const base::TimeDelta kFrameRateLogInterval =
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
570 // The following cancels any outstanding callbacks and causes IsStarted() to 624 // The following cancels any outstanding callbacks and causes IsStarted() to
571 // return false from here onward. 625 // return false from here onward.
572 weak_ptr_factory_.InvalidateWeakPtrs(); 626 weak_ptr_factory_.InvalidateWeakPtrs();
573 627
574 // Note: RenewFrameSubscription() must be called before stopping |tracker_| so 628 // Note: RenewFrameSubscription() must be called before stopping |tracker_| so
575 // the web_contents() can be notified that the capturing is ending. 629 // the web_contents() can be notified that the capturing is ending.
576 RenewFrameSubscription(false); 630 RenewFrameSubscription(false);
577 tracker_->Stop(); 631 tracker_->Stop();
578 632
579 // The render thread cannot be stopped on the UI thread, so post a message 633 // The render thread cannot be stopped on the UI thread, so post a message
580 // to the thread pool used for blocking operations. 634 // to the thread pool used; for blocking operations.
xjz 2015/10/22 17:08:42 nit: remove ';'.
581 if (render_thread_.get()) { 635 if (render_thread_.get()) {
582 BrowserThread::PostBlockingPoolTask( 636 BrowserThread::PostBlockingPoolTask(
583 FROM_HERE, 637 FROM_HERE,
584 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), 638 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_),
585 callback)); 639 callback));
586 } 640 }
587 } 641 }
588 642
589 void WebContentsCaptureMachine::Capture( 643 void WebContentsCaptureMachine::Capture(
590 const base::TimeTicks& start_time, 644 const base::TimeTicks& start_time,
591 const scoped_refptr<media::VideoFrame>& target, 645 const scoped_refptr<media::VideoFrame>& target,
592 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 646 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
593 deliver_frame_cb) { 647 deliver_frame_cb) {
594 DCHECK_CURRENTLY_ON(BrowserThread::UI); 648 DCHECK_CURRENTLY_ON(BrowserThread::UI);
595 649
596 RenderWidgetHost* rwh = tracker_->GetTargetRenderWidgetHost(); 650 RenderWidgetHost* rwh = tracker_->GetTargetRenderWidgetHost();
597 RenderWidgetHostViewBase* view = 651 RenderWidgetHostViewBase* view =
598 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL; 652 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL;
599 if (!view) { 653 if (!view) {
600 deliver_frame_cb.Run(base::TimeTicks(), false); 654 deliver_frame_cb.Run(base::TimeTicks(), gfx::Rect(), false);
601 return; 655 return;
602 } 656 }
603 657
604 gfx::Size view_size = view->GetViewBounds().size(); 658 gfx::Size view_size = view->GetViewBounds().size();
605 if (view_size != last_view_size_) { 659 if (view_size != last_view_size_) {
606 last_view_size_ = view_size; 660 last_view_size_ = view_size;
607 661
608 // Measure the number of kilopixels. 662 // Measure the number of kilopixels.
609 UMA_HISTOGRAM_COUNTS_10000( 663 UMA_HISTOGRAM_COUNTS_10000(
610 "TabCapture.ViewChangeKiloPixels", 664 "TabCapture.ViewChangeKiloPixels",
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 if (response == READBACK_SUCCESS) { 769 if (response == READBACK_SUCCESS) {
716 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); 770 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
717 TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", target.get(), 771 TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", target.get(),
718 "Render"); 772 "Render");
719 render_thread_->task_runner()->PostTask( 773 render_thread_->task_runner()->PostTask(
720 FROM_HERE, base::Bind(&RenderVideoFrame, bitmap, target, 774 FROM_HERE, base::Bind(&RenderVideoFrame, bitmap, target,
721 base::Bind(deliver_frame_cb, start_time))); 775 base::Bind(deliver_frame_cb, start_time)));
722 } else { 776 } else {
723 // Capture can fail due to transient issues, so just skip this frame. 777 // Capture can fail due to transient issues, so just skip this frame.
724 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; 778 DVLOG(1) << "CopyFromBackingStore failed; skipping frame.";
725 deliver_frame_cb.Run(start_time, false); 779 deliver_frame_cb.Run(start_time, gfx::Rect(), false);
726 } 780 }
727 } 781 }
728 782
729 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( 783 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
730 const base::TimeTicks& start_time, 784 const base::TimeTicks& start_time,
731 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 785 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
732 deliver_frame_cb, 786 deliver_frame_cb,
787 gfx::Rect region_in_frame,
733 bool success) { 788 bool success) {
734 DCHECK_CURRENTLY_ON(BrowserThread::UI); 789 DCHECK_CURRENTLY_ON(BrowserThread::UI);
735 base::TimeTicks now = base::TimeTicks::Now(); 790 base::TimeTicks now = base::TimeTicks::Now();
736 791
737 if (success) { 792 if (success) {
738 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time); 793 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time);
739 } else { 794 } else {
740 // Capture can fail due to transient issues, so just skip this frame. 795 // Capture can fail due to transient issues, so just skip this frame.
741 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; 796 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame.";
742 } 797 }
743 deliver_frame_cb.Run(start_time, success); 798 deliver_frame_cb.Run(start_time, region_in_frame, success);
744 } 799 }
745 800
746 void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) { 801 void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) {
747 DCHECK_CURRENTLY_ON(BrowserThread::UI); 802 DCHECK_CURRENTLY_ON(BrowserThread::UI);
748 803
749 RenderWidgetHost* const rwh = 804 RenderWidgetHost* const rwh =
750 had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr; 805 had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr;
751 806
752 // Always destroy the old subscription before creating a new one. 807 // Always destroy the old subscription before creating a new one.
753 const bool had_subscription = !!subscription_; 808 const bool had_subscription = !!subscription_;
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
836 scoped_ptr<Client> client) { 891 scoped_ptr<Client> client) {
837 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); 892 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString();
838 core_->AllocateAndStart(params, client.Pass()); 893 core_->AllocateAndStart(params, client.Pass());
839 } 894 }
840 895
841 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { 896 void WebContentsVideoCaptureDevice::StopAndDeAllocate() {
842 core_->StopAndDeAllocate(); 897 core_->StopAndDeAllocate();
843 } 898 }
844 899
845 } // namespace content 900 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698