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

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: Fix build and tests after rebase 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 // We can get a callback in the shutdown sequence for the browser main loop
359 // and this can result in a DCHECK failure. Avoid this by doing DCHECK only
360 // on success.
361 if (success) {
362 DCHECK_CURRENTLY_ON(BrowserThread::UI);
363 // TODO(isheriff): Unclear if taking a snapshot of cursor here affects user
364 // experience in any particular scenarios. Doing it prior to capture may
365 // require evaluating region_in_frame in this file.
366 if (frame_subscriber_ && frame_subscriber_->cursor_renderer_ && success) {
miu 2015/11/06 00:22:54 Don't need the "&& success" at the end anymore.
Irfan 2015/11/06 17:49:26 Done.
367 if (frame_subscriber_->cursor_renderer_->SnapshotCursorState(
368 region_in_frame))
369 frame_subscriber_->cursor_renderer_->RenderOnVideoFrame(frame);
370 }
371 }
372 capture_frame_cb.Run(frame, timestamp, success);
373 }
374
317 ContentCaptureSubscription::ContentCaptureSubscription( 375 ContentCaptureSubscription::ContentCaptureSubscription(
318 const RenderWidgetHost& source, 376 const RenderWidgetHost& source,
319 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, 377 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy,
320 const CaptureCallback& capture_callback) 378 const CaptureCallback& capture_callback)
321 : render_process_id_(source.GetProcess()->GetID()), 379 : render_process_id_(source.GetProcess()->GetID()),
322 render_widget_id_(source.GetRoutingID()), 380 render_widget_id_(source.GetRoutingID()),
323 delivery_log_(), 381 delivery_log_(),
324 timer_subscriber_(media::VideoCaptureOracle::kTimerPoll, oracle_proxy,
325 &delivery_log_),
326 capture_callback_(capture_callback), 382 capture_callback_(capture_callback),
327 timer_(true, true) { 383 timer_(true, true) {
328 DCHECK_CURRENTLY_ON(BrowserThread::UI); 384 DCHECK_CURRENTLY_ON(BrowserThread::UI);
329 385
330 RenderWidgetHostView* const view = source.GetView(); 386 RenderWidgetHostView* const view = source.GetView();
387 #if defined(USE_AURA)
388 if (view)
389 cursor_renderer_.reset(
390 new content::CursorRendererAura(view->GetNativeView()));
391 #endif
392 timer_subscriber_.reset(new FrameSubscriber(
393 media::VideoCaptureOracle::kTimerPoll, oracle_proxy, &delivery_log_,
394 cursor_renderer_ ? cursor_renderer_->GetWeakPtr()
395 : base::WeakPtr<CursorRenderer>()));
331 396
332 // Subscribe to compositor updates. These will be serviced directly by the 397 // Subscribe to compositor updates. These will be serviced directly by the
333 // oracle. 398 // oracle.
334 if (view) { 399 if (view) {
335 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( 400 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
336 new FrameSubscriber(media::VideoCaptureOracle::kCompositorUpdate, 401 new FrameSubscriber(media::VideoCaptureOracle::kCompositorUpdate,
337 oracle_proxy, &delivery_log_)); 402 oracle_proxy, &delivery_log_,
403 cursor_renderer_
404 ? cursor_renderer_->GetWeakPtr()
405 : base::WeakPtr<CursorRenderer>()));
338 view->BeginFrameSubscription(subscriber.Pass()); 406 view->BeginFrameSubscription(subscriber.Pass());
339 } 407 }
340 408
341 // Subscribe to timer events. This instance will service these as well. 409 // Subscribe to timer events. This instance will service these as well.
342 timer_.Start(FROM_HERE, 410 timer_.Start(FROM_HERE,
343 std::max(oracle_proxy->min_capture_period(), 411 std::max(oracle_proxy->min_capture_period(),
344 base::TimeDelta::FromMilliseconds(media 412 base::TimeDelta::FromMilliseconds(media
345 ::VideoCaptureOracle::kMinTimerPollPeriodMillis)), 413 ::VideoCaptureOracle::kMinTimerPollPeriodMillis)),
346 base::Bind(&ContentCaptureSubscription::OnTimer, 414 base::Bind(&ContentCaptureSubscription::OnTimer,
347 base::Unretained(this))); 415 base::Unretained(this)));
(...skipping 15 matching lines...) Expand all
363 } 431 }
364 432
365 void ContentCaptureSubscription::OnTimer() { 433 void ContentCaptureSubscription::OnTimer() {
366 DCHECK_CURRENTLY_ON(BrowserThread::UI); 434 DCHECK_CURRENTLY_ON(BrowserThread::UI);
367 TRACE_EVENT0("gpu.capture", "ContentCaptureSubscription::OnTimer"); 435 TRACE_EVENT0("gpu.capture", "ContentCaptureSubscription::OnTimer");
368 436
369 scoped_refptr<media::VideoFrame> frame; 437 scoped_refptr<media::VideoFrame> frame;
370 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb; 438 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb;
371 439
372 const base::TimeTicks start_time = base::TimeTicks::Now(); 440 const base::TimeTicks start_time = base::TimeTicks::Now();
373 if (timer_subscriber_.ShouldCaptureFrame(gfx::Rect(), 441 if (timer_subscriber_->ShouldCaptureFrame(gfx::Rect(), start_time, &frame,
374 start_time, 442 &deliver_frame_cb)) {
375 &frame,
376 &deliver_frame_cb)) {
377 capture_callback_.Run(start_time, frame, deliver_frame_cb); 443 capture_callback_.Run(start_time, frame, deliver_frame_cb);
378 } 444 }
379 } 445 }
380 446
381 void RenderVideoFrame(const SkBitmap& input, 447 // ScopedClosureRunOnBrowserThread ensures that the closure always executes
382 const scoped_refptr<media::VideoFrame>& output, 448 // (on the browser thread) no matter how the current scope exits.
383 const base::Callback<void(bool)>& done_cb) { 449 class ScopedClosureRunOnBrowserThread {
miu 2015/11/06 00:22:54 There's a common solution to this problem: media::
Irfan 2015/11/06 17:49:26 Aha, excellent
384 base::ScopedClosureRunner failure_handler(base::Bind(done_cb, false)); 450 public:
451 ScopedClosureRunOnBrowserThread(const base::Closure& closure);
452 ~ScopedClosureRunOnBrowserThread();
453 void Release();
454
455 private:
456 base::Closure closure_;
457
458 DISALLOW_COPY_AND_ASSIGN(ScopedClosureRunOnBrowserThread);
459 };
460
461 ScopedClosureRunOnBrowserThread::ScopedClosureRunOnBrowserThread(
462 const base::Closure& closure)
463 : closure_(closure) {}
464
465 ScopedClosureRunOnBrowserThread::~ScopedClosureRunOnBrowserThread() {
466 if (!closure_.is_null())
467 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, closure_);
468 }
469
470 void ScopedClosureRunOnBrowserThread::Release() {
471 closure_.Reset();
472 }
473
474 void RenderVideoFrame(
475 const SkBitmap& input,
476 const scoped_refptr<media::VideoFrame>& output,
477 const base::Callback<void(const gfx::Rect&, bool)>& done_cb) {
478 ScopedClosureRunOnBrowserThread failure_handler(
479 base::Bind(done_cb, gfx::Rect(), false));
385 480
386 SkAutoLockPixels locker(input); 481 SkAutoLockPixels locker(input);
387 482
388 // Sanity-check the captured bitmap. 483 // Sanity-check the captured bitmap.
389 if (input.empty() || 484 if (input.empty() ||
390 !input.readyToDraw() || 485 !input.readyToDraw() ||
391 input.colorType() != kN32_SkColorType || 486 input.colorType() != kN32_SkColorType ||
392 input.width() < 2 || input.height() < 2) { 487 input.width() < 2 || input.height() < 2) {
393 DVLOG(1) << "input unacceptable (size=" 488 DVLOG(1) << "input unacceptable (size="
394 << input.getSize() 489 << input.getSize()
(...skipping 10 matching lines...) Expand all
405 500
406 // Calculate the width and height of the content region in the |output|, based 501 // Calculate the width and height of the content region in the |output|, based
407 // on the aspect ratio of |input|. 502 // on the aspect ratio of |input|.
408 const gfx::Rect region_in_frame = media::ComputeLetterboxRegion( 503 const gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
409 output->visible_rect(), gfx::Size(input.width(), input.height())); 504 output->visible_rect(), gfx::Size(input.width(), input.height()));
410 505
411 // Scale the bitmap to the required size, if necessary. 506 // Scale the bitmap to the required size, if necessary.
412 SkBitmap scaled_bitmap; 507 SkBitmap scaled_bitmap;
413 if (input.width() != region_in_frame.width() || 508 if (input.width() != region_in_frame.width() ||
414 input.height() != region_in_frame.height()) { 509 input.height() != region_in_frame.height()) {
415
416 skia::ImageOperations::ResizeMethod method; 510 skia::ImageOperations::ResizeMethod method;
417 if (input.width() < region_in_frame.width() || 511 if (input.width() < region_in_frame.width() ||
418 input.height() < region_in_frame.height()) { 512 input.height() < region_in_frame.height()) {
419 // Avoid box filtering when magnifying, because it's actually 513 // Avoid box filtering when magnifying, because it's actually
420 // nearest-neighbor. 514 // nearest-neighbor.
421 method = skia::ImageOperations::RESIZE_HAMMING1; 515 method = skia::ImageOperations::RESIZE_HAMMING1;
422 } else { 516 } else {
423 method = skia::ImageOperations::RESIZE_BOX; 517 method = skia::ImageOperations::RESIZE_BOX;
424 } 518 }
425 519
(...skipping 19 matching lines...) Expand all
445 539
446 SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap); 540 SkAutoLockPixels scaled_bitmap_locker(scaled_bitmap);
447 media::CopyRGBToVideoFrame( 541 media::CopyRGBToVideoFrame(
448 reinterpret_cast<uint8*>(scaled_bitmap.getPixels()), 542 reinterpret_cast<uint8*>(scaled_bitmap.getPixels()),
449 scaled_bitmap.rowBytes(), 543 scaled_bitmap.rowBytes(),
450 region_in_yv12_frame, 544 region_in_yv12_frame,
451 output.get()); 545 output.get());
452 } 546 }
453 547
454 // The result is now ready. 548 // The result is now ready.
455 ignore_result(failure_handler.Release()); 549 failure_handler.Release();
456 done_cb.Run(true); 550 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
551 base::Bind(done_cb, region_in_frame, true));
457 } 552 }
458 553
459 VideoFrameDeliveryLog::VideoFrameDeliveryLog() 554 VideoFrameDeliveryLog::VideoFrameDeliveryLog()
460 : last_frame_rate_log_time_(), 555 : last_frame_rate_log_time_(),
461 count_frames_rendered_(0) { 556 count_frames_rendered_(0) {
462 } 557 }
463 558
464 void VideoFrameDeliveryLog::ChronicleFrameDelivery(base::TimeTicks frame_time) { 559 void VideoFrameDeliveryLog::ChronicleFrameDelivery(base::TimeTicks frame_time) {
465 // Log frame rate, if verbose logging is turned on. 560 // Log frame rate, if verbose logging is turned on.
466 static const base::TimeDelta kFrameRateLogInterval = 561 static const base::TimeDelta kFrameRateLogInterval =
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 const base::TimeTicks& start_time, 685 const base::TimeTicks& start_time,
591 const scoped_refptr<media::VideoFrame>& target, 686 const scoped_refptr<media::VideoFrame>& target,
592 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 687 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
593 deliver_frame_cb) { 688 deliver_frame_cb) {
594 DCHECK_CURRENTLY_ON(BrowserThread::UI); 689 DCHECK_CURRENTLY_ON(BrowserThread::UI);
595 690
596 RenderWidgetHost* rwh = tracker_->GetTargetRenderWidgetHost(); 691 RenderWidgetHost* rwh = tracker_->GetTargetRenderWidgetHost();
597 RenderWidgetHostViewBase* view = 692 RenderWidgetHostViewBase* view =
598 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL; 693 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL;
599 if (!view) { 694 if (!view) {
600 deliver_frame_cb.Run(base::TimeTicks(), false); 695 deliver_frame_cb.Run(base::TimeTicks(), gfx::Rect(), false);
601 return; 696 return;
602 } 697 }
603 698
604 gfx::Size view_size = view->GetViewBounds().size(); 699 gfx::Size view_size = view->GetViewBounds().size();
605 if (view_size != last_view_size_) { 700 if (view_size != last_view_size_) {
606 last_view_size_ = view_size; 701 last_view_size_ = view_size;
607 702
608 // Measure the number of kilopixels. 703 // Measure the number of kilopixels.
609 UMA_HISTOGRAM_COUNTS_10000( 704 UMA_HISTOGRAM_COUNTS_10000(
610 "TabCapture.ViewChangeKiloPixels", 705 "TabCapture.ViewChangeKiloPixels",
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 if (response == READBACK_SUCCESS) { 810 if (response == READBACK_SUCCESS) {
716 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); 811 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
717 TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", target.get(), 812 TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", target.get(),
718 "Render"); 813 "Render");
719 render_thread_->task_runner()->PostTask( 814 render_thread_->task_runner()->PostTask(
720 FROM_HERE, base::Bind(&RenderVideoFrame, bitmap, target, 815 FROM_HERE, base::Bind(&RenderVideoFrame, bitmap, target,
721 base::Bind(deliver_frame_cb, start_time))); 816 base::Bind(deliver_frame_cb, start_time)));
722 } else { 817 } else {
723 // Capture can fail due to transient issues, so just skip this frame. 818 // Capture can fail due to transient issues, so just skip this frame.
724 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; 819 DVLOG(1) << "CopyFromBackingStore failed; skipping frame.";
725 deliver_frame_cb.Run(start_time, false); 820 deliver_frame_cb.Run(start_time, gfx::Rect(), false);
726 } 821 }
727 } 822 }
728 823
729 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( 824 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
730 const base::TimeTicks& start_time, 825 const base::TimeTicks& start_time,
731 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 826 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
732 deliver_frame_cb, 827 deliver_frame_cb,
828 const gfx::Rect& region_in_frame,
733 bool success) { 829 bool success) {
734 DCHECK_CURRENTLY_ON(BrowserThread::UI); 830 DCHECK_CURRENTLY_ON(BrowserThread::UI);
735 base::TimeTicks now = base::TimeTicks::Now(); 831 base::TimeTicks now = base::TimeTicks::Now();
736 832
737 if (success) { 833 if (success) {
738 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time); 834 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time);
739 } else { 835 } else {
740 // Capture can fail due to transient issues, so just skip this frame. 836 // Capture can fail due to transient issues, so just skip this frame.
741 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; 837 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame.";
742 } 838 }
743 deliver_frame_cb.Run(start_time, success); 839 deliver_frame_cb.Run(start_time, region_in_frame, success);
744 } 840 }
745 841
746 void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) { 842 void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) {
747 DCHECK_CURRENTLY_ON(BrowserThread::UI); 843 DCHECK_CURRENTLY_ON(BrowserThread::UI);
748 844
749 RenderWidgetHost* const rwh = 845 RenderWidgetHost* const rwh =
750 had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr; 846 had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr;
751 847
752 // Always destroy the old subscription before creating a new one. 848 // Always destroy the old subscription before creating a new one.
753 const bool had_subscription = !!subscription_; 849 const bool had_subscription = !!subscription_;
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
836 scoped_ptr<Client> client) { 932 scoped_ptr<Client> client) {
837 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); 933 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString();
838 core_->AllocateAndStart(params, client.Pass()); 934 core_->AllocateAndStart(params, client.Pass());
839 } 935 }
840 936
841 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { 937 void WebContentsVideoCaptureDevice::StopAndDeAllocate() {
842 core_->StopAndDeAllocate(); 938 core_->StopAndDeAllocate();
843 } 939 }
844 940
845 } // namespace content 941 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698