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

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: Added unit tests Created 5 years, 1 month 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>
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 #endif
93
87 namespace content { 94 namespace content {
88 95
89 namespace { 96 namespace {
90 97
91 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread, 98 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread,
92 const base::Closure& callback) { 99 const base::Closure& callback) {
93 render_thread.reset(); 100 render_thread.reset();
94 101
95 // After thread join call the callback on UI thread. 102 // After thread join call the callback on UI thread.
96 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); 103 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
(...skipping 15 matching lines...) Expand all
112 119
113 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog); 120 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog);
114 }; 121 };
115 122
116 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible 123 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible
117 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. 124 // with RenderWidgetHostViewFrameSubscriber. We create one per event type.
118 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { 125 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
119 public: 126 public:
120 FrameSubscriber(media::VideoCaptureOracle::Event event_type, 127 FrameSubscriber(media::VideoCaptureOracle::Event event_type,
121 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle, 128 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle,
122 VideoFrameDeliveryLog* delivery_log) 129 VideoFrameDeliveryLog* delivery_log,
130 base::WeakPtr<content::CursorRenderer> cursor_renderer)
123 : event_type_(event_type), 131 : event_type_(event_type),
124 oracle_proxy_(oracle), 132 oracle_proxy_(oracle),
125 delivery_log_(delivery_log) {} 133 delivery_log_(delivery_log),
134 cursor_renderer_(cursor_renderer),
135 weak_ptr_factory_(this) {}
126 136
127 bool ShouldCaptureFrame( 137 bool ShouldCaptureFrame(
128 const gfx::Rect& damage_rect, 138 const gfx::Rect& damage_rect,
129 base::TimeTicks present_time, 139 base::TimeTicks present_time,
130 scoped_refptr<media::VideoFrame>* storage, 140 scoped_refptr<media::VideoFrame>* storage,
131 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* 141 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback*
132 deliver_frame_cb) override; 142 deliver_frame_cb) override;
133 143
144 static void DidCaptureFrame(
145 base::WeakPtr<FrameSubscriber> frame_subscriber_,
146 const media::ThreadSafeCaptureOracle::CaptureFrameCallback&
147 capture_frame_cb,
148 const scoped_refptr<media::VideoFrame>& frame,
149 base::TimeTicks timestamp,
150 const gfx::Rect& region_in_frame,
151 bool success);
152
134 private: 153 private:
135 const media::VideoCaptureOracle::Event event_type_; 154 const media::VideoCaptureOracle::Event event_type_;
136 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; 155 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_;
137 VideoFrameDeliveryLog* const delivery_log_; 156 VideoFrameDeliveryLog* const delivery_log_;
157 // We need a weak pointer since FrameSubscriber is owned externally and
158 // may outlive the cursor renderer.
159 base::WeakPtr<CursorRenderer> cursor_renderer_;
160 base::WeakPtrFactory<FrameSubscriber> weak_ptr_factory_;
138 }; 161 };
139 162
140 // ContentCaptureSubscription is the relationship between a RenderWidgetHost 163 // ContentCaptureSubscription is the relationship between a RenderWidgetHost
141 // whose content is updating, a subscriber that is deciding which of these 164 // 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 165 // 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. 166 // knows how to do the capture and prepare the result for delivery.
144 // 167 //
145 // In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in 168 // In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in
146 // the RenderWidgetHostView, to process compositor updates, and (b) running a 169 // the RenderWidgetHostView, to process compositor updates, and (b) running a
147 // timer to possibly initiate forced, non-event-driven captures needed by 170 // timer to possibly initiate forced, non-event-driven captures needed by
(...skipping 22 matching lines...) Expand all
170 private: 193 private:
171 void OnTimer(); 194 void OnTimer();
172 195
173 // Maintain a weak reference to the RenderWidgetHost (via its routing ID), 196 // Maintain a weak reference to the RenderWidgetHost (via its routing ID),
174 // since the instance could be destroyed externally during the lifetime of 197 // since the instance could be destroyed externally during the lifetime of
175 // |this|. 198 // |this|.
176 const int render_process_id_; 199 const int render_process_id_;
177 const int render_widget_id_; 200 const int render_widget_id_;
178 201
179 VideoFrameDeliveryLog delivery_log_; 202 VideoFrameDeliveryLog delivery_log_;
180 FrameSubscriber timer_subscriber_; 203 scoped_ptr<FrameSubscriber> timer_subscriber_;
181 CaptureCallback capture_callback_; 204 CaptureCallback capture_callback_;
182 base::Timer timer_; 205 base::Timer timer_;
183 206
207 // Responsible for tracking the cursor state and input events to make
208 // decisions and then render the mouse cursor on the video frame after
209 // capture is completed.
210 scoped_ptr<content::CursorRenderer> cursor_renderer_;
211
184 DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription); 212 DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription);
185 }; 213 };
186 214
187 // Render the SkBitmap |input| into the given VideoFrame buffer |output|, then 215 // 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 216 // 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. 217 // ARGB. |output| must be YV12 or I420. Colorspace conversion is always done.
190 // Scaling and letterboxing will be done as needed. 218 // Scaling and letterboxing will be done as needed.
191 // 219 //
192 // This software implementation should be used only when GPU acceleration of 220 // This software implementation should be used only when GPU acceleration of
193 // these activities is not possible. This operation may be expensive (tens to 221 // 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 222 // hundreds of milliseconds), so the caller should ensure that it runs on a
195 // thread where such a pause would cause UI jank. 223 // thread where such a pause would cause UI jank.
196 void RenderVideoFrame(const SkBitmap& input, 224 void RenderVideoFrame(
197 const scoped_refptr<media::VideoFrame>& output, 225 const SkBitmap& input,
198 const base::Callback<void(bool)>& done_cb); 226 const scoped_refptr<media::VideoFrame>& output,
227 const base::Callback<void(const gfx::Rect&, bool)>& done_cb);
199 228
200 // Renews capture subscriptions based on feedback from WebContentsTracker, and 229 // Renews capture subscriptions based on feedback from WebContentsTracker, and
201 // also executes copying of the backing store on the UI BrowserThread. 230 // also executes copying of the backing store on the UI BrowserThread.
202 class WebContentsCaptureMachine : public media::VideoCaptureMachine { 231 class WebContentsCaptureMachine : public media::VideoCaptureMachine {
203 public: 232 public:
204 WebContentsCaptureMachine(int render_process_id, 233 WebContentsCaptureMachine(int render_process_id,
205 int main_render_frame_id, 234 int main_render_frame_id,
206 bool enable_auto_throttling); 235 bool enable_auto_throttling);
207 ~WebContentsCaptureMachine() override; 236 ~WebContentsCaptureMachine() override;
208 237
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
242 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 271 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
243 deliver_frame_cb, 272 deliver_frame_cb,
244 const SkBitmap& bitmap, 273 const SkBitmap& bitmap,
245 ReadbackResponse response); 274 ReadbackResponse response);
246 275
247 // Response callback for RWHVP::CopyFromCompositingSurfaceToVideoFrame(). 276 // Response callback for RWHVP::CopyFromCompositingSurfaceToVideoFrame().
248 void DidCopyFromCompositingSurfaceToVideoFrame( 277 void DidCopyFromCompositingSurfaceToVideoFrame(
249 const base::TimeTicks& start_time, 278 const base::TimeTicks& start_time,
250 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 279 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
251 deliver_frame_cb, 280 deliver_frame_cb,
281 const gfx::Rect& region_in_frame,
252 bool success); 282 bool success);
253 283
254 // Remove the old subscription, and attempt to start a new one if |had_target| 284 // Remove the old subscription, and attempt to start a new one if |had_target|
255 // is true. 285 // is true.
256 void RenewFrameSubscription(bool had_target); 286 void RenewFrameSubscription(bool had_target);
257 287
258 // Called whenever the render widget is resized. 288 // Called whenever the render widget is resized.
259 void UpdateCaptureSize(); 289 void UpdateCaptureSize();
260 290
261 // Parameters saved in constructor. 291 // Parameters saved in constructor.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 327
298 bool FrameSubscriber::ShouldCaptureFrame( 328 bool FrameSubscriber::ShouldCaptureFrame(
299 const gfx::Rect& damage_rect, 329 const gfx::Rect& damage_rect,
300 base::TimeTicks present_time, 330 base::TimeTicks present_time,
301 scoped_refptr<media::VideoFrame>* storage, 331 scoped_refptr<media::VideoFrame>* storage,
302 DeliverFrameCallback* deliver_frame_cb) { 332 DeliverFrameCallback* deliver_frame_cb) {
303 TRACE_EVENT1("gpu.capture", "FrameSubscriber::ShouldCaptureFrame", 333 TRACE_EVENT1("gpu.capture", "FrameSubscriber::ShouldCaptureFrame",
304 "instance", this); 334 "instance", this);
305 335
306 media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; 336 media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb;
337
307 bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture( 338 bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture(
308 event_type_, damage_rect, present_time, storage, &capture_frame_cb); 339 event_type_, damage_rect, present_time, storage, &capture_frame_cb);
309 340
310 if (!capture_frame_cb.is_null()) 341 if (!capture_frame_cb.is_null())
311 *deliver_frame_cb = base::Bind(capture_frame_cb, *storage); 342 *deliver_frame_cb =
343 base::Bind(&FrameSubscriber::DidCaptureFrame,
344 weak_ptr_factory_.GetWeakPtr(), capture_frame_cb, *storage);
312 if (oracle_decision) 345 if (oracle_decision)
313 delivery_log_->ChronicleFrameDelivery(present_time); 346 delivery_log_->ChronicleFrameDelivery(present_time);
314 return oracle_decision; 347 return oracle_decision;
315 } 348 }
316 349
350 void FrameSubscriber::DidCaptureFrame(
351 base::WeakPtr<FrameSubscriber> frame_subscriber_,
352 const media::ThreadSafeCaptureOracle::CaptureFrameCallback&
353 capture_frame_cb,
354 const scoped_refptr<media::VideoFrame>& frame,
355 base::TimeTicks timestamp,
356 const gfx::Rect& region_in_frame,
357 bool success) {
358 DCHECK_CURRENTLY_ON(BrowserThread::UI);
359 // TODO(isheriff): Unclear if taking a snapshot of cursor here affects user
360 // experience in any particular scenarios. Doing it prior to capture may
361 // require evaluating region_in_frame in this file.
362 if (frame_subscriber_ && frame_subscriber_->cursor_renderer_ && success) {
363 if (frame_subscriber_->cursor_renderer_->SnapshotCursorState(
364 region_in_frame))
365 frame_subscriber_->cursor_renderer_->RenderOnVideoFrame(frame);
366 }
367 capture_frame_cb.Run(frame, timestamp, success);
368 }
369
317 ContentCaptureSubscription::ContentCaptureSubscription( 370 ContentCaptureSubscription::ContentCaptureSubscription(
318 const RenderWidgetHost& source, 371 const RenderWidgetHost& source,
319 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, 372 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy,
320 const CaptureCallback& capture_callback) 373 const CaptureCallback& capture_callback)
321 : render_process_id_(source.GetProcess()->GetID()), 374 : render_process_id_(source.GetProcess()->GetID()),
322 render_widget_id_(source.GetRoutingID()), 375 render_widget_id_(source.GetRoutingID()),
323 delivery_log_(), 376 delivery_log_(),
324 timer_subscriber_(media::VideoCaptureOracle::kTimerPoll, oracle_proxy,
325 &delivery_log_),
326 capture_callback_(capture_callback), 377 capture_callback_(capture_callback),
327 timer_(true, true) { 378 timer_(true, true) {
328 DCHECK_CURRENTLY_ON(BrowserThread::UI); 379 DCHECK_CURRENTLY_ON(BrowserThread::UI);
329 380
330 RenderWidgetHostView* const view = source.GetView(); 381 RenderWidgetHostView* const view = source.GetView();
382 #if defined(USE_AURA)
383 if (view)
384 cursor_renderer_.reset(
385 new content::CursorRendererAura(view->GetNativeView()));
386 #endif
387 timer_subscriber_.reset(new FrameSubscriber(
388 media::VideoCaptureOracle::kTimerPoll, oracle_proxy, &delivery_log_,
389 cursor_renderer_ ? cursor_renderer_->GetWeakPtr()
390 : base::WeakPtr<CursorRenderer>()));
331 391
332 // Subscribe to compositor updates. These will be serviced directly by the 392 // Subscribe to compositor updates. These will be serviced directly by the
333 // oracle. 393 // oracle.
334 if (view) { 394 if (view) {
335 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( 395 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
336 new FrameSubscriber(media::VideoCaptureOracle::kCompositorUpdate, 396 new FrameSubscriber(media::VideoCaptureOracle::kCompositorUpdate,
337 oracle_proxy, &delivery_log_)); 397 oracle_proxy, &delivery_log_,
398 cursor_renderer_
399 ? cursor_renderer_->GetWeakPtr()
400 : base::WeakPtr<CursorRenderer>()));
338 view->BeginFrameSubscription(subscriber.Pass()); 401 view->BeginFrameSubscription(subscriber.Pass());
339 } 402 }
340 403
341 // Subscribe to timer events. This instance will service these as well. 404 // Subscribe to timer events. This instance will service these as well.
342 timer_.Start(FROM_HERE, 405 timer_.Start(FROM_HERE,
343 std::max(oracle_proxy->min_capture_period(), 406 std::max(oracle_proxy->min_capture_period(),
344 base::TimeDelta::FromMilliseconds(media 407 base::TimeDelta::FromMilliseconds(media
345 ::VideoCaptureOracle::kMinTimerPollPeriodMillis)), 408 ::VideoCaptureOracle::kMinTimerPollPeriodMillis)),
346 base::Bind(&ContentCaptureSubscription::OnTimer, 409 base::Bind(&ContentCaptureSubscription::OnTimer,
347 base::Unretained(this))); 410 base::Unretained(this)));
(...skipping 15 matching lines...) Expand all
363 } 426 }
364 427
365 void ContentCaptureSubscription::OnTimer() { 428 void ContentCaptureSubscription::OnTimer() {
366 DCHECK_CURRENTLY_ON(BrowserThread::UI); 429 DCHECK_CURRENTLY_ON(BrowserThread::UI);
367 TRACE_EVENT0("gpu.capture", "ContentCaptureSubscription::OnTimer"); 430 TRACE_EVENT0("gpu.capture", "ContentCaptureSubscription::OnTimer");
368 431
369 scoped_refptr<media::VideoFrame> frame; 432 scoped_refptr<media::VideoFrame> frame;
370 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb; 433 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb;
371 434
372 const base::TimeTicks start_time = base::TimeTicks::Now(); 435 const base::TimeTicks start_time = base::TimeTicks::Now();
373 if (timer_subscriber_.ShouldCaptureFrame(gfx::Rect(), 436 if (timer_subscriber_->ShouldCaptureFrame(gfx::Rect(), start_time, &frame,
374 start_time, 437 &deliver_frame_cb)) {
375 &frame,
376 &deliver_frame_cb)) {
377 capture_callback_.Run(start_time, frame, deliver_frame_cb); 438 capture_callback_.Run(start_time, frame, deliver_frame_cb);
378 } 439 }
379 } 440 }
380 441
381 void RenderVideoFrame(const SkBitmap& input, 442 void RenderVideoFrame(
382 const scoped_refptr<media::VideoFrame>& output, 443 const SkBitmap& input,
383 const base::Callback<void(bool)>& done_cb) { 444 const scoped_refptr<media::VideoFrame>& output,
384 base::ScopedClosureRunner failure_handler(base::Bind(done_cb, false)); 445 const base::Callback<void(const gfx::Rect&, bool)>& done_cb) {
446 base::ScopedClosureRunner failure_handler(
447 base::Bind(done_cb, gfx::Rect(), false));
385 448
386 SkAutoLockPixels locker(input); 449 SkAutoLockPixels locker(input);
387 450
388 // Sanity-check the captured bitmap. 451 // Sanity-check the captured bitmap.
389 if (input.empty() || 452 if (input.empty() ||
390 !input.readyToDraw() || 453 !input.readyToDraw() ||
391 input.colorType() != kN32_SkColorType || 454 input.colorType() != kN32_SkColorType ||
392 input.width() < 2 || input.height() < 2) { 455 input.width() < 2 || input.height() < 2) {
393 DVLOG(1) << "input unacceptable (size=" 456 DVLOG(1) << "input unacceptable (size="
394 << input.getSize() 457 << input.getSize()
(...skipping 10 matching lines...) Expand all
405 468
406 // Calculate the width and height of the content region in the |output|, based 469 // Calculate the width and height of the content region in the |output|, based
407 // on the aspect ratio of |input|. 470 // on the aspect ratio of |input|.
408 const gfx::Rect region_in_frame = media::ComputeLetterboxRegion( 471 const gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
409 output->visible_rect(), gfx::Size(input.width(), input.height())); 472 output->visible_rect(), gfx::Size(input.width(), input.height()));
410 473
411 // Scale the bitmap to the required size, if necessary. 474 // Scale the bitmap to the required size, if necessary.
412 SkBitmap scaled_bitmap; 475 SkBitmap scaled_bitmap;
413 if (input.width() != region_in_frame.width() || 476 if (input.width() != region_in_frame.width() ||
414 input.height() != region_in_frame.height()) { 477 input.height() != region_in_frame.height()) {
415
416 skia::ImageOperations::ResizeMethod method; 478 skia::ImageOperations::ResizeMethod method;
417 if (input.width() < region_in_frame.width() || 479 if (input.width() < region_in_frame.width() ||
418 input.height() < region_in_frame.height()) { 480 input.height() < region_in_frame.height()) {
419 // Avoid box filtering when magnifying, because it's actually 481 // Avoid box filtering when magnifying, because it's actually
420 // nearest-neighbor. 482 // nearest-neighbor.
421 method = skia::ImageOperations::RESIZE_HAMMING1; 483 method = skia::ImageOperations::RESIZE_HAMMING1;
422 } else { 484 } else {
423 method = skia::ImageOperations::RESIZE_BOX; 485 method = skia::ImageOperations::RESIZE_BOX;
424 } 486 }
425 487
(...skipping 20 matching lines...) Expand all
446 SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap); 508 SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
447 media::CopyRGBToVideoFrame( 509 media::CopyRGBToVideoFrame(
448 reinterpret_cast<uint8*>(scaled_bitmap.getPixels()), 510 reinterpret_cast<uint8*>(scaled_bitmap.getPixels()),
449 scaled_bitmap.rowBytes(), 511 scaled_bitmap.rowBytes(),
450 region_in_yv12_frame, 512 region_in_yv12_frame,
451 output.get()); 513 output.get());
452 } 514 }
453 515
454 // The result is now ready. 516 // The result is now ready.
455 ignore_result(failure_handler.Release()); 517 ignore_result(failure_handler.Release());
456 done_cb.Run(true); 518 done_cb.Run(region_in_frame, true);
457 } 519 }
458 520
459 VideoFrameDeliveryLog::VideoFrameDeliveryLog() 521 VideoFrameDeliveryLog::VideoFrameDeliveryLog()
460 : last_frame_rate_log_time_(), 522 : last_frame_rate_log_time_(),
461 count_frames_rendered_(0) { 523 count_frames_rendered_(0) {
462 } 524 }
463 525
464 void VideoFrameDeliveryLog::ChronicleFrameDelivery(base::TimeTicks frame_time) { 526 void VideoFrameDeliveryLog::ChronicleFrameDelivery(base::TimeTicks frame_time) {
465 // Log frame rate, if verbose logging is turned on. 527 // Log frame rate, if verbose logging is turned on.
466 static const base::TimeDelta kFrameRateLogInterval = 528 static const base::TimeDelta kFrameRateLogInterval =
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 const base::TimeTicks& start_time, 652 const base::TimeTicks& start_time,
591 const scoped_refptr<media::VideoFrame>& target, 653 const scoped_refptr<media::VideoFrame>& target,
592 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 654 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
593 deliver_frame_cb) { 655 deliver_frame_cb) {
594 DCHECK_CURRENTLY_ON(BrowserThread::UI); 656 DCHECK_CURRENTLY_ON(BrowserThread::UI);
595 657
596 RenderWidgetHost* rwh = tracker_->GetTargetRenderWidgetHost(); 658 RenderWidgetHost* rwh = tracker_->GetTargetRenderWidgetHost();
597 RenderWidgetHostViewBase* view = 659 RenderWidgetHostViewBase* view =
598 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL; 660 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL;
599 if (!view) { 661 if (!view) {
600 deliver_frame_cb.Run(base::TimeTicks(), false); 662 deliver_frame_cb.Run(base::TimeTicks(), gfx::Rect(), false);
601 return; 663 return;
602 } 664 }
603 665
604 gfx::Size view_size = view->GetViewBounds().size(); 666 gfx::Size view_size = view->GetViewBounds().size();
605 if (view_size != last_view_size_) { 667 if (view_size != last_view_size_) {
606 last_view_size_ = view_size; 668 last_view_size_ = view_size;
607 669
608 // Measure the number of kilopixels. 670 // Measure the number of kilopixels.
609 UMA_HISTOGRAM_COUNTS_10000( 671 UMA_HISTOGRAM_COUNTS_10000(
610 "TabCapture.ViewChangeKiloPixels", 672 "TabCapture.ViewChangeKiloPixels",
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 if (response == READBACK_SUCCESS) { 777 if (response == READBACK_SUCCESS) {
716 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); 778 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
717 TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", target.get(), 779 TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", target.get(),
718 "Render"); 780 "Render");
719 render_thread_->task_runner()->PostTask( 781 render_thread_->task_runner()->PostTask(
720 FROM_HERE, base::Bind(&RenderVideoFrame, bitmap, target, 782 FROM_HERE, base::Bind(&RenderVideoFrame, bitmap, target,
721 base::Bind(deliver_frame_cb, start_time))); 783 base::Bind(deliver_frame_cb, start_time)));
722 } else { 784 } else {
723 // Capture can fail due to transient issues, so just skip this frame. 785 // Capture can fail due to transient issues, so just skip this frame.
724 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; 786 DVLOG(1) << "CopyFromBackingStore failed; skipping frame.";
725 deliver_frame_cb.Run(start_time, false); 787 deliver_frame_cb.Run(start_time, gfx::Rect(), false);
726 } 788 }
727 } 789 }
728 790
729 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( 791 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
730 const base::TimeTicks& start_time, 792 const base::TimeTicks& start_time,
731 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 793 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
732 deliver_frame_cb, 794 deliver_frame_cb,
795 const gfx::Rect& region_in_frame,
733 bool success) { 796 bool success) {
734 DCHECK_CURRENTLY_ON(BrowserThread::UI); 797 DCHECK_CURRENTLY_ON(BrowserThread::UI);
735 base::TimeTicks now = base::TimeTicks::Now(); 798 base::TimeTicks now = base::TimeTicks::Now();
736 799
737 if (success) { 800 if (success) {
738 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time); 801 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time);
739 } else { 802 } else {
740 // Capture can fail due to transient issues, so just skip this frame. 803 // Capture can fail due to transient issues, so just skip this frame.
741 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; 804 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame.";
742 } 805 }
743 deliver_frame_cb.Run(start_time, success); 806 deliver_frame_cb.Run(start_time, region_in_frame, success);
744 } 807 }
745 808
746 void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) { 809 void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) {
747 DCHECK_CURRENTLY_ON(BrowserThread::UI); 810 DCHECK_CURRENTLY_ON(BrowserThread::UI);
748 811
749 RenderWidgetHost* const rwh = 812 RenderWidgetHost* const rwh =
750 had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr; 813 had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr;
751 814
752 // Always destroy the old subscription before creating a new one. 815 // Always destroy the old subscription before creating a new one.
753 const bool had_subscription = !!subscription_; 816 const bool had_subscription = !!subscription_;
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
836 scoped_ptr<Client> client) { 899 scoped_ptr<Client> client) {
837 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); 900 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString();
838 core_->AllocateAndStart(params, client.Pass()); 901 core_->AllocateAndStart(params, client.Pass());
839 } 902 }
840 903
841 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { 904 void WebContentsVideoCaptureDevice::StopAndDeAllocate() {
842 core_->StopAndDeAllocate(); 905 core_->StopAndDeAllocate();
843 } 906 }
844 907
845 } // namespace content 908 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698