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

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

Powered by Google App Engine
This is Rietveld 408576698