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

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

Issue 542863004: Site Isolation: RenderView-->RenderFrame for WebContentsVideoCaptureDevice and WebContentsAudioInpu… (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 // 4 //
5 // Implementation notes: This needs to work on a variety of hardware 5 // Implementation notes: This needs to work on a variety of hardware
6 // configurations where the speed of the CPU and GPU greatly affect overall 6 // configurations where the speed of the CPU and GPU greatly affect overall
7 // performance. Spanning several threads, the process of capturing has been 7 // performance. Spanning several threads, the process of capturing has been
8 // split up into four conceptual stages: 8 // split up into four conceptual stages:
9 // 9 //
10 // 1. Reserve Buffer: Before a frame can be captured, a slot in the client's 10 // 1. Reserve Buffer: Before a frame can be captured, a slot in the client's
11 // shared-memory IPC buffer is reserved. There are only a few of these; 11 // shared-memory IPC buffer is reserved. There are only a few of these;
12 // when they run out, it indicates that the downstream client -- likely a 12 // when they run out, it indicates that the downstream client -- likely a
13 // video encoder -- is the performance bottleneck, and that the rate of 13 // video encoder -- is the performance bottleneck, and that the rate of
14 // frame capture should be throttled back. 14 // frame capture should be throttled back.
15 // 15 //
16 // 2. Capture: A bitmap is snapshotted/copied from the RenderView's backing 16 // 2. Capture: A bitmap is snapshotted/copied from the RenderWidget's backing
17 // store. This is initiated on the UI BrowserThread, and often occurs 17 // store. This is initiated on the UI BrowserThread, and often occurs
18 // asynchronously. Where supported, the GPU scales and color converts 18 // asynchronously. Where supported, the GPU scales and color converts
19 // frames to our desired size, and the readback happens directly into the 19 // frames to our desired size, and the readback happens directly into the
20 // shared-memory buffer. But this is not always possible, particularly when 20 // shared-memory buffer. But this is not always possible, particularly when
21 // accelerated compositing is disabled. 21 // accelerated compositing is disabled.
22 // 22 //
23 // 3. Render (if needed): If the web contents cannot be captured directly into 23 // 3. Render (if needed): If the web contents cannot be captured directly into
24 // our target size and color format, scaling and colorspace conversion must 24 // our target size and color format, scaling and colorspace conversion must
25 // be done on the CPU. A dedicated thread is used for this operation, to 25 // be done on the CPU. A dedicated thread is used for this operation, to
26 // avoid blocking the UI thread. The Render stage always reads from a 26 // avoid blocking the UI thread. The Render stage always reads from a
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 #include "base/memory/weak_ptr.h" 58 #include "base/memory/weak_ptr.h"
59 #include "base/message_loop/message_loop_proxy.h" 59 #include "base/message_loop/message_loop_proxy.h"
60 #include "base/metrics/histogram.h" 60 #include "base/metrics/histogram.h"
61 #include "base/sequenced_task_runner.h" 61 #include "base/sequenced_task_runner.h"
62 #include "base/threading/thread.h" 62 #include "base/threading/thread.h"
63 #include "base/threading/thread_checker.h" 63 #include "base/threading/thread_checker.h"
64 #include "base/time/time.h" 64 #include "base/time/time.h"
65 #include "content/browser/media/capture/content_video_capture_device_core.h" 65 #include "content/browser/media/capture/content_video_capture_device_core.h"
66 #include "content/browser/media/capture/video_capture_oracle.h" 66 #include "content/browser/media/capture/video_capture_oracle.h"
67 #include "content/browser/media/capture/web_contents_capture_util.h" 67 #include "content/browser/media/capture/web_contents_capture_util.h"
68 #include "content/browser/media/capture/web_contents_tracker.h"
68 #include "content/browser/renderer_host/render_widget_host_impl.h" 69 #include "content/browser/renderer_host/render_widget_host_impl.h"
69 #include "content/browser/renderer_host/render_widget_host_view_base.h" 70 #include "content/browser/renderer_host/render_widget_host_view_base.h"
70 #include "content/browser/web_contents/web_contents_impl.h"
71 #include "content/public/browser/browser_thread.h" 71 #include "content/public/browser/browser_thread.h"
72 #include "content/public/browser/notification_observer.h"
73 #include "content/public/browser/notification_registrar.h"
72 #include "content/public/browser/notification_source.h" 74 #include "content/public/browser/notification_source.h"
73 #include "content/public/browser/notification_types.h" 75 #include "content/public/browser/notification_types.h"
74 #include "content/public/browser/render_view_host.h" 76 #include "content/public/browser/render_process_host.h"
75 #include "content/public/browser/render_widget_host_view.h" 77 #include "content/public/browser/render_widget_host_view.h"
76 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" 78 #include "content/public/browser/render_widget_host_view_frame_subscriber.h"
77 #include "content/public/browser/web_contents_observer.h" 79 #include "content/public/browser/web_contents.h"
78 #include "media/base/video_util.h" 80 #include "media/base/video_util.h"
79 #include "media/video/capture/video_capture_types.h" 81 #include "media/video/capture/video_capture_types.h"
80 #include "skia/ext/image_operations.h" 82 #include "skia/ext/image_operations.h"
81 #include "third_party/skia/include/core/SkBitmap.h" 83 #include "third_party/skia/include/core/SkBitmap.h"
82 #include "third_party/skia/include/core/SkColor.h" 84 #include "third_party/skia/include/core/SkColor.h"
83 #include "ui/gfx/display.h" 85 #include "ui/gfx/display.h"
84 #include "ui/gfx/geometry/size.h" 86 #include "ui/gfx/geometry/size.h"
85 #include "ui/gfx/geometry/size_conversions.h" 87 #include "ui/gfx/geometry/size_conversions.h"
86 #include "ui/gfx/screen.h" 88 #include "ui/gfx/screen.h"
87 89
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 virtual ~ContentCaptureSubscription(); 188 virtual ~ContentCaptureSubscription();
187 189
188 // content::NotificationObserver implementation. 190 // content::NotificationObserver implementation.
189 virtual void Observe(int type, 191 virtual void Observe(int type,
190 const content::NotificationSource& source, 192 const content::NotificationSource& source,
191 const content::NotificationDetails& details) OVERRIDE; 193 const content::NotificationDetails& details) OVERRIDE;
192 194
193 private: 195 private:
194 void OnTimer(); 196 void OnTimer();
195 197
198 // Maintain a weak reference to the RenderWidgetHost (via its routing ID),
199 // since the instance could be destroyed externally during the lifetime of
200 // |this|.
196 const int render_process_id_; 201 const int render_process_id_;
197 const int render_view_id_; 202 const int render_widget_id_;
198 203
199 VideoFrameDeliveryLog delivery_log_; 204 VideoFrameDeliveryLog delivery_log_;
200 FrameSubscriber paint_subscriber_; 205 FrameSubscriber paint_subscriber_;
201 FrameSubscriber timer_subscriber_; 206 FrameSubscriber timer_subscriber_;
202 content::NotificationRegistrar registrar_; 207 content::NotificationRegistrar registrar_;
203 CaptureCallback capture_callback_; 208 CaptureCallback capture_callback_;
204 base::Timer timer_; 209 base::Timer timer_;
205 210
206 DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription); 211 DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription);
207 }; 212 };
208 213
209 // Render the SkBitmap |input| into the given VideoFrame buffer |output|, then 214 // Render the SkBitmap |input| into the given VideoFrame buffer |output|, then
210 // invoke |done_cb| to indicate success or failure. |input| is expected to be 215 // invoke |done_cb| to indicate success or failure. |input| is expected to be
211 // ARGB. |output| must be YV12 or I420. Colorspace conversion is always done. 216 // ARGB. |output| must be YV12 or I420. Colorspace conversion is always done.
212 // Scaling and letterboxing will be done as needed. 217 // Scaling and letterboxing will be done as needed.
213 // 218 //
214 // This software implementation should be used only when GPU acceleration of 219 // This software implementation should be used only when GPU acceleration of
215 // these activities is not possible. This operation may be expensive (tens to 220 // these activities is not possible. This operation may be expensive (tens to
216 // hundreds of milliseconds), so the caller should ensure that it runs on a 221 // hundreds of milliseconds), so the caller should ensure that it runs on a
217 // thread where such a pause would cause UI jank. 222 // thread where such a pause would cause UI jank.
218 void RenderVideoFrame(const SkBitmap& input, 223 void RenderVideoFrame(const SkBitmap& input,
219 const scoped_refptr<media::VideoFrame>& output, 224 const scoped_refptr<media::VideoFrame>& output,
220 const base::Callback<void(bool)>& done_cb); 225 const base::Callback<void(bool)>& done_cb);
221 226
222 // Keeps track of the RenderView to be sourced, and executes copying of the 227 // Renews capture subscriptions based on feedback from WebContentsTracker, and
223 // backing store on the UI BrowserThread. 228 // also executes copying of the backing store on the UI BrowserThread.
224 // 229 class WebContentsCaptureMachine : public VideoCaptureMachine {
225 // TODO(nick): It would be nice to merge this with WebContentsTracker, but its
226 // implementation is currently asynchronous -- in our case, the "rvh changed"
227 // notification would get posted back to the UI thread and processed later, and
228 // this seems disadvantageous.
229 class WebContentsCaptureMachine
230 : public VideoCaptureMachine,
231 public WebContentsObserver {
232 public: 230 public:
233 WebContentsCaptureMachine(int render_process_id, int main_render_frame_id); 231 WebContentsCaptureMachine(int render_process_id, int main_render_frame_id);
234 virtual ~WebContentsCaptureMachine(); 232 virtual ~WebContentsCaptureMachine();
235 233
236 // VideoCaptureMachine overrides. 234 // VideoCaptureMachine overrides.
237 virtual bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, 235 virtual bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
238 const media::VideoCaptureParams& params) OVERRIDE; 236 const media::VideoCaptureParams& params) OVERRIDE;
239 virtual void Stop(const base::Closure& callback) OVERRIDE; 237 virtual void Stop(const base::Closure& callback) OVERRIDE;
240 238
241 // Starts a copy from the backing store or the composited surface. Must be run 239 // Starts a copy from the backing store or the composited surface. Must be run
242 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation 240 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation
243 // completes. The copy will occur to |target|. 241 // completes. The copy will occur to |target|.
244 // 242 //
245 // This may be used as a ContentCaptureSubscription::CaptureCallback. 243 // This may be used as a ContentCaptureSubscription::CaptureCallback.
246 void Capture(const base::TimeTicks& start_time, 244 void Capture(const base::TimeTicks& start_time,
247 const scoped_refptr<media::VideoFrame>& target, 245 const scoped_refptr<media::VideoFrame>& target,
248 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 246 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
249 deliver_frame_cb); 247 deliver_frame_cb);
250 248
251 // content::WebContentsObserver implementation. 249 private:
252 virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE { 250 bool IsStarted() const;
253 fullscreen_widget_id_ = routing_id;
254 RenewFrameSubscription();
255 }
256 251
257 virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE {
258 DCHECK_EQ(fullscreen_widget_id_, routing_id);
259 fullscreen_widget_id_ = MSG_ROUTING_NONE;
260 RenewFrameSubscription();
261 }
262
263 virtual void RenderViewReady() OVERRIDE {
264 RenewFrameSubscription();
265 }
266
267 virtual void AboutToNavigateRenderView(RenderViewHost* rvh) OVERRIDE {
268 RenewFrameSubscription();
269 }
270
271 virtual void DidNavigateMainFrame(
272 const LoadCommittedDetails& details,
273 const FrameNavigateParams& params) OVERRIDE {
274 RenewFrameSubscription();
275 }
276
277 virtual void WebContentsDestroyed() OVERRIDE;
278
279 private:
280 // Computes the preferred size of the target RenderWidget for optimal capture. 252 // Computes the preferred size of the target RenderWidget for optimal capture.
281 gfx::Size ComputeOptimalTargetSize() const; 253 gfx::Size ComputeOptimalTargetSize() const;
282 254
283 // Starts observing the web contents, returning false if lookup fails.
284 bool StartObservingWebContents();
285
286 // Helper function to determine the view that we are currently tracking.
287 RenderWidgetHost* GetTarget() const;
288
289 // Response callback for RenderWidgetHost::CopyFromBackingStore(). 255 // Response callback for RenderWidgetHost::CopyFromBackingStore().
290 void DidCopyFromBackingStore( 256 void DidCopyFromBackingStore(
291 const base::TimeTicks& start_time, 257 const base::TimeTicks& start_time,
292 const scoped_refptr<media::VideoFrame>& target, 258 const scoped_refptr<media::VideoFrame>& target,
293 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 259 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
294 deliver_frame_cb, 260 deliver_frame_cb,
295 bool success, 261 bool success,
296 const SkBitmap& bitmap); 262 const SkBitmap& bitmap);
297 263
298 // Response callback for RWHVP::CopyFromCompositingSurfaceToVideoFrame(). 264 // Response callback for RWHVP::CopyFromCompositingSurfaceToVideoFrame().
299 void DidCopyFromCompositingSurfaceToVideoFrame( 265 void DidCopyFromCompositingSurfaceToVideoFrame(
300 const base::TimeTicks& start_time, 266 const base::TimeTicks& start_time,
301 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 267 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
302 deliver_frame_cb, 268 deliver_frame_cb,
303 bool success); 269 bool success);
304 270
305 // Remove the old subscription, and start a new one. This should be called 271 // Remove the old subscription, and start a new one if |rwh| is not NULL.
306 // after any change to the WebContents that affects the RenderWidgetHost or 272 void RenewFrameSubscription(RenderWidgetHost* rwh);
307 // attached views.
308 void RenewFrameSubscription();
309 273
310 // Parameters saved in constructor. 274 // Parameters saved in constructor.
311 const int initial_render_process_id_; 275 const int initial_render_process_id_;
312 const int initial_main_render_frame_id_; 276 const int initial_main_render_frame_id_;
313 277
278 // Tracks events and calls back to RenewFrameSubscription() to maintain
279 // capture on the correct RenderWidgetHost.
280 const scoped_refptr<WebContentsTracker> tracker_;
281
314 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will 282 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will
315 // occur. Only used when this activity cannot be done on the GPU. 283 // occur. Only used when this activity cannot be done on the GPU.
316 scoped_ptr<base::Thread> render_thread_; 284 scoped_ptr<base::Thread> render_thread_;
317 285
318 // Makes all the decisions about which frames to copy, and how. 286 // Makes all the decisions about which frames to copy, and how.
319 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; 287 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
320 288
321 // Video capture parameters that this machine is started with. 289 // Video capture parameters that this machine is started with.
322 media::VideoCaptureParams capture_params_; 290 media::VideoCaptureParams capture_params_;
323 291
324 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE
325 // otherwise.
326 int fullscreen_widget_id_;
327
328 // Last known RenderView size. 292 // Last known RenderView size.
329 gfx::Size last_view_size_; 293 gfx::Size last_view_size_;
330 294
331 // Responsible for forwarding events from the active RenderWidgetHost to the 295 // Responsible for forwarding events from the active RenderWidgetHost to the
332 // oracle, and initiating captures accordingly. 296 // oracle, and initiating captures accordingly.
333 scoped_ptr<ContentCaptureSubscription> subscription_; 297 scoped_ptr<ContentCaptureSubscription> subscription_;
334 298
335 // Weak pointer factory used to invalidate callbacks. 299 // Weak pointer factory used to invalidate callbacks.
336 // NOTE: Weak pointers must be invalidated before all other member variables. 300 // NOTE: Weak pointers must be invalidated before all other member variables.
337 base::WeakPtrFactory<WebContentsCaptureMachine> weak_ptr_factory_; 301 base::WeakPtrFactory<WebContentsCaptureMachine> weak_ptr_factory_;
(...skipping 18 matching lines...) Expand all
356 if (oracle_decision) 320 if (oracle_decision)
357 delivery_log_->ChronicleFrameDelivery(present_time); 321 delivery_log_->ChronicleFrameDelivery(present_time);
358 return oracle_decision; 322 return oracle_decision;
359 } 323 }
360 324
361 ContentCaptureSubscription::ContentCaptureSubscription( 325 ContentCaptureSubscription::ContentCaptureSubscription(
362 const RenderWidgetHost& source, 326 const RenderWidgetHost& source,
363 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, 327 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
364 const CaptureCallback& capture_callback) 328 const CaptureCallback& capture_callback)
365 : render_process_id_(source.GetProcess()->GetID()), 329 : render_process_id_(source.GetProcess()->GetID()),
366 render_view_id_(source.GetRoutingID()), 330 render_widget_id_(source.GetRoutingID()),
367 delivery_log_(), 331 delivery_log_(),
368 paint_subscriber_(VideoCaptureOracle::kSoftwarePaint, oracle_proxy, 332 paint_subscriber_(VideoCaptureOracle::kSoftwarePaint, oracle_proxy,
369 &delivery_log_), 333 &delivery_log_),
370 timer_subscriber_(VideoCaptureOracle::kTimerPoll, oracle_proxy, 334 timer_subscriber_(VideoCaptureOracle::kTimerPoll, oracle_proxy,
371 &delivery_log_), 335 &delivery_log_),
372 capture_callback_(capture_callback), 336 capture_callback_(capture_callback),
373 timer_(true, true) { 337 timer_(true, true) {
374 DCHECK_CURRENTLY_ON(BrowserThread::UI); 338 DCHECK_CURRENTLY_ON(BrowserThread::UI);
375 339
376 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 340 RenderWidgetHostView* const view = source.GetView();
377 source.GetView());
378 341
379 // Subscribe to accelerated presents. These will be serviced directly by the 342 // Subscribe to accelerated presents. These will be serviced directly by the
380 // oracle. 343 // oracle.
381 if (view && kAcceleratedSubscriberIsSupported) { 344 if (view && kAcceleratedSubscriberIsSupported) {
382 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( 345 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber(
383 new FrameSubscriber(VideoCaptureOracle::kCompositorUpdate, 346 new FrameSubscriber(VideoCaptureOracle::kCompositorUpdate,
384 oracle_proxy, &delivery_log_)); 347 oracle_proxy, &delivery_log_));
385 view->BeginFrameSubscription(subscriber.Pass()); 348 view->BeginFrameSubscription(subscriber.Pass());
386 } 349 }
387 350
(...skipping 12 matching lines...) Expand all
400 363
401 ContentCaptureSubscription::~ContentCaptureSubscription() { 364 ContentCaptureSubscription::~ContentCaptureSubscription() {
402 // If the BrowserThreads have been torn down, then the browser is in the final 365 // If the BrowserThreads have been torn down, then the browser is in the final
403 // stages of exiting and it is dangerous to take any further action. We must 366 // stages of exiting and it is dangerous to take any further action. We must
404 // return early. http://crbug.com/396413 367 // return early. http://crbug.com/396413
405 if (!BrowserThread::IsMessageLoopValid(BrowserThread::UI)) 368 if (!BrowserThread::IsMessageLoopValid(BrowserThread::UI))
406 return; 369 return;
407 370
408 DCHECK_CURRENTLY_ON(BrowserThread::UI); 371 DCHECK_CURRENTLY_ON(BrowserThread::UI);
409 if (kAcceleratedSubscriberIsSupported) { 372 if (kAcceleratedSubscriberIsSupported) {
410 RenderViewHost* source = RenderViewHost::FromID(render_process_id_, 373 RenderWidgetHost* const source =
411 render_view_id_); 374 RenderWidgetHost::FromID(render_process_id_, render_widget_id_);
412 if (source) { 375 RenderWidgetHostView* const view = source ? source->GetView() : NULL;
413 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 376 if (view)
414 source->GetView()); 377 view->EndFrameSubscription();
415 if (view)
416 view->EndFrameSubscription();
417 }
418 } 378 }
419 } 379 }
420 380
421 void ContentCaptureSubscription::Observe( 381 void ContentCaptureSubscription::Observe(
422 int type, 382 int type,
423 const content::NotificationSource& source, 383 const content::NotificationSource& source,
424 const content::NotificationDetails& details) { 384 const content::NotificationDetails& details) {
425 DCHECK_CURRENTLY_ON(BrowserThread::UI); 385 DCHECK_CURRENTLY_ON(BrowserThread::UI);
426 DCHECK_EQ(NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, type); 386 DCHECK_EQ(NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, type);
427 387
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
571 last_frame_rate_log_time_ = frame_time; 531 last_frame_rate_log_time_ = frame_time;
572 count_frames_rendered_ = 0; 532 count_frames_rendered_ = 0;
573 } 533 }
574 } 534 }
575 } 535 }
576 536
577 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id, 537 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id,
578 int main_render_frame_id) 538 int main_render_frame_id)
579 : initial_render_process_id_(render_process_id), 539 : initial_render_process_id_(render_process_id),
580 initial_main_render_frame_id_(main_render_frame_id), 540 initial_main_render_frame_id_(main_render_frame_id),
581 fullscreen_widget_id_(MSG_ROUTING_NONE), 541 tracker_(new WebContentsTracker(true)),
582 weak_ptr_factory_(this) {} 542 weak_ptr_factory_(this) {}
583 543
584 WebContentsCaptureMachine::~WebContentsCaptureMachine() {} 544 WebContentsCaptureMachine::~WebContentsCaptureMachine() {}
585 545
546 bool WebContentsCaptureMachine::IsStarted() const {
547 DCHECK_CURRENTLY_ON(BrowserThread::UI);
548 return weak_ptr_factory_.HasWeakPtrs();
549 }
550
586 bool WebContentsCaptureMachine::Start( 551 bool WebContentsCaptureMachine::Start(
587 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, 552 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy,
588 const media::VideoCaptureParams& params) { 553 const media::VideoCaptureParams& params) {
589 DCHECK_CURRENTLY_ON(BrowserThread::UI); 554 DCHECK_CURRENTLY_ON(BrowserThread::UI);
590 DCHECK(!weak_ptr_factory_.HasWeakPtrs()); // Should not be started. 555 DCHECK(!IsStarted());
591 556
592 DCHECK(oracle_proxy.get()); 557 DCHECK(oracle_proxy.get());
593 oracle_proxy_ = oracle_proxy; 558 oracle_proxy_ = oracle_proxy;
594 capture_params_ = params; 559 capture_params_ = params;
595 560
596 render_thread_.reset(new base::Thread("WebContentsVideo_RenderThread")); 561 render_thread_.reset(new base::Thread("WebContentsVideo_RenderThread"));
597 if (!render_thread_->Start()) { 562 if (!render_thread_->Start()) {
598 DVLOG(1) << "Failed to spawn render thread."; 563 DVLOG(1) << "Failed to spawn render thread.";
599 render_thread_.reset(); 564 render_thread_.reset();
600 return false; 565 return false;
601 } 566 }
602 567
603 if (!StartObservingWebContents()) { 568 // Note: Creation of the first WeakPtr in the following statement will cause
604 DVLOG(1) << "Failed to observe web contents."; 569 // IsStarted() to return true from now on.
605 render_thread_.reset(); 570 tracker_->Start(initial_render_process_id_, initial_main_render_frame_id_,
606 return false; 571 base::Bind(&WebContentsCaptureMachine::RenewFrameSubscription,
607 } 572 weak_ptr_factory_.GetWeakPtr()));
608 573
609 return true; 574 return true;
610 } 575 }
611 576
612 void WebContentsCaptureMachine::Stop(const base::Closure& callback) { 577 void WebContentsCaptureMachine::Stop(const base::Closure& callback) {
613 DCHECK_CURRENTLY_ON(BrowserThread::UI); 578 DCHECK_CURRENTLY_ON(BrowserThread::UI);
614 subscription_.reset(); 579
615 if (web_contents()) { 580 if (!IsStarted()) {
616 web_contents()->DecrementCapturerCount(); 581 callback.Run();
617 Observe(NULL); 582 return;
618 } 583 }
619 584
620 // Any callback that intend to use render_thread_ will not work after it is 585 // The following cancels any outstanding callbacks and causes IsStarted() to
621 // passed. 586 // return false from here onward.
622 weak_ptr_factory_.InvalidateWeakPtrs(); 587 weak_ptr_factory_.InvalidateWeakPtrs();
623 588
589 // Note: RenewFrameSubscription() must be called before stopping |tracker_| so
590 // the web_contents() can be notified that the capturing is ending.
591 RenewFrameSubscription(NULL);
592 tracker_->Stop();
593
624 // The render thread cannot be stopped on the UI thread, so post a message 594 // The render thread cannot be stopped on the UI thread, so post a message
625 // to the thread pool used for blocking operations. 595 // to the thread pool used for blocking operations.
626 if (render_thread_.get()) { 596 if (render_thread_.get()) {
627 BrowserThread::PostBlockingPoolTask( 597 BrowserThread::PostBlockingPoolTask(
628 FROM_HERE, 598 FROM_HERE,
629 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), 599 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_),
630 callback)); 600 callback));
631 } 601 }
632 } 602 }
633 603
634 void WebContentsCaptureMachine::Capture( 604 void WebContentsCaptureMachine::Capture(
635 const base::TimeTicks& start_time, 605 const base::TimeTicks& start_time,
636 const scoped_refptr<media::VideoFrame>& target, 606 const scoped_refptr<media::VideoFrame>& target,
637 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 607 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
638 deliver_frame_cb) { 608 deliver_frame_cb) {
639 DCHECK_CURRENTLY_ON(BrowserThread::UI); 609 DCHECK_CURRENTLY_ON(BrowserThread::UI);
640 610
641 RenderWidgetHost* rwh = GetTarget(); 611 RenderWidgetHost* rwh = tracker_->GetTargetRenderWidgetHost();
642 RenderWidgetHostViewBase* view = 612 RenderWidgetHostViewBase* view =
643 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL; 613 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL;
644 if (!view || !rwh) { 614 if (!view) {
645 deliver_frame_cb.Run(base::TimeTicks(), false); 615 deliver_frame_cb.Run(base::TimeTicks(), false);
646 return; 616 return;
647 } 617 }
648 618
649 gfx::Size video_size = target->coded_size(); 619 gfx::Size video_size = target->coded_size();
650 gfx::Size view_size = view->GetViewBounds().size(); 620 gfx::Size view_size = view->GetViewBounds().size();
651 gfx::Size fitted_size; 621 gfx::Size fitted_size;
652 if (!view_size.IsEmpty()) { 622 if (!view_size.IsEmpty()) {
653 fitted_size = ComputeYV12LetterboxRegion(video_size, view_size).size(); 623 fitted_size = ComputeYV12LetterboxRegion(video_size, view_size).size();
654 } 624 }
(...skipping 30 matching lines...) Expand all
685 gfx::Size WebContentsCaptureMachine::ComputeOptimalTargetSize() const { 655 gfx::Size WebContentsCaptureMachine::ComputeOptimalTargetSize() const {
686 DCHECK_CURRENTLY_ON(BrowserThread::UI); 656 DCHECK_CURRENTLY_ON(BrowserThread::UI);
687 657
688 gfx::Size optimal_size = oracle_proxy_->GetCaptureSize(); 658 gfx::Size optimal_size = oracle_proxy_->GetCaptureSize();
689 659
690 // If the ratio between physical and logical pixels is greater than 1:1, 660 // If the ratio between physical and logical pixels is greater than 1:1,
691 // shrink |optimal_size| by that amount. Then, when external code resizes the 661 // shrink |optimal_size| by that amount. Then, when external code resizes the
692 // render widget to the "preferred size," the widget will be physically 662 // render widget to the "preferred size," the widget will be physically
693 // rendered at the exact capture size, thereby eliminating unnecessary scaling 663 // rendered at the exact capture size, thereby eliminating unnecessary scaling
694 // operations in the graphics pipeline. 664 // operations in the graphics pipeline.
695 RenderWidgetHost* const rwh = GetTarget(); 665 RenderWidgetHost* const rwh = tracker_->GetTargetRenderWidgetHost();
696 RenderWidgetHostView* const rwhv = rwh ? rwh->GetView() : NULL; 666 RenderWidgetHostView* const rwhv = rwh ? rwh->GetView() : NULL;
697 if (rwhv) { 667 if (rwhv) {
698 const gfx::NativeView view = rwhv->GetNativeView(); 668 const gfx::NativeView view = rwhv->GetNativeView();
699 gfx::Screen* const screen = gfx::Screen::GetScreenFor(view); 669 gfx::Screen* const screen = gfx::Screen::GetScreenFor(view);
700 if (screen->IsDIPEnabled()) { 670 if (screen->IsDIPEnabled()) {
701 const gfx::Display display = screen->GetDisplayNearestWindow(view); 671 const gfx::Display display = screen->GetDisplayNearestWindow(view);
702 const float scale = display.device_scale_factor(); 672 const float scale = display.device_scale_factor();
703 if (scale > 1.0f) { 673 if (scale > 1.0f) {
704 const gfx::Size shrunk_size( 674 const gfx::Size shrunk_size(
705 gfx::ToFlooredSize(gfx::ScaleSize(optimal_size, 1.0f / scale))); 675 gfx::ToFlooredSize(gfx::ScaleSize(optimal_size, 1.0f / scale)));
706 if (shrunk_size.width() > 0 && shrunk_size.height() > 0) 676 if (shrunk_size.width() > 0 && shrunk_size.height() > 0)
707 optimal_size = shrunk_size; 677 optimal_size = shrunk_size;
708 } 678 }
709 } 679 }
710 } 680 }
711 681
712 VLOG(1) << "Computed optimal target size: " << optimal_size.ToString(); 682 VLOG(1) << "Computed optimal target size: " << optimal_size.ToString();
713 return optimal_size; 683 return optimal_size;
714 } 684 }
715 685
716 bool WebContentsCaptureMachine::StartObservingWebContents() {
717 DCHECK_CURRENTLY_ON(BrowserThread::UI);
718
719 // Look-up the RenderFrameHost and, from that, the WebContents that wraps it.
720 // If successful, begin observing the WebContents instance.
721 //
722 // Why this can be unsuccessful: The request for mirroring originates in a
723 // render process, and this request is based on the current main RenderFrame
724 // associated with a tab. However, by the time we get up-and-running here,
725 // there have been multiple back-and-forth IPCs between processes, as well as
726 // a bit of indirection across threads. It's easily possible that, in the
727 // meantime, the original RenderFrame may have gone away.
728 Observe(WebContents::FromRenderFrameHost(RenderFrameHost::FromID(
729 initial_render_process_id_, initial_main_render_frame_id_)));
730 DVLOG_IF(1, !web_contents())
731 << "Could not find WebContents associated with main RenderFrameHost "
732 << "referenced by render_process_id=" << initial_render_process_id_
733 << ", routing_id=" << initial_main_render_frame_id_;
734
735 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents());
736 if (contents) {
737 contents->IncrementCapturerCount(ComputeOptimalTargetSize());
738 fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID();
739 RenewFrameSubscription();
740 return true;
741 }
742 return false;
743 }
744
745 void WebContentsCaptureMachine::WebContentsDestroyed() {
746 DCHECK_CURRENTLY_ON(BrowserThread::UI);
747
748 subscription_.reset();
749 web_contents()->DecrementCapturerCount();
750 oracle_proxy_->ReportError("WebContentsDestroyed()");
751 }
752
753 RenderWidgetHost* WebContentsCaptureMachine::GetTarget() const {
754 DCHECK_CURRENTLY_ON(BrowserThread::UI);
755 if (!web_contents())
756 return NULL;
757
758 RenderWidgetHost* rwh = NULL;
759 if (fullscreen_widget_id_ != MSG_ROUTING_NONE) {
760 RenderProcessHost* process = web_contents()->GetRenderProcessHost();
761 if (process)
762 rwh = RenderWidgetHost::FromID(process->GetID(), fullscreen_widget_id_);
763 } else {
764 rwh = web_contents()->GetRenderViewHost();
765 }
766
767 return rwh;
768 }
769
770 void WebContentsCaptureMachine::DidCopyFromBackingStore( 686 void WebContentsCaptureMachine::DidCopyFromBackingStore(
771 const base::TimeTicks& start_time, 687 const base::TimeTicks& start_time,
772 const scoped_refptr<media::VideoFrame>& target, 688 const scoped_refptr<media::VideoFrame>& target,
773 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 689 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
774 deliver_frame_cb, 690 deliver_frame_cb,
775 bool success, 691 bool success,
776 const SkBitmap& bitmap) { 692 const SkBitmap& bitmap) {
777 DCHECK_CURRENTLY_ON(BrowserThread::UI); 693 DCHECK_CURRENTLY_ON(BrowserThread::UI);
778 694
779 base::TimeTicks now = base::TimeTicks::Now(); 695 base::TimeTicks now = base::TimeTicks::Now();
(...skipping 22 matching lines...) Expand all
802 718
803 if (success) { 719 if (success) {
804 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time); 720 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time);
805 } else { 721 } else {
806 // Capture can fail due to transient issues, so just skip this frame. 722 // Capture can fail due to transient issues, so just skip this frame.
807 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; 723 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame.";
808 } 724 }
809 deliver_frame_cb.Run(start_time, success); 725 deliver_frame_cb.Run(start_time, success);
810 } 726 }
811 727
812 void WebContentsCaptureMachine::RenewFrameSubscription() { 728 void WebContentsCaptureMachine::RenewFrameSubscription(RenderWidgetHost* rwh) {
813 DCHECK_CURRENTLY_ON(BrowserThread::UI); 729 DCHECK_CURRENTLY_ON(BrowserThread::UI);
814 730
815 // Always destroy the old subscription before creating a new one. 731 // Always destroy the old subscription before creating a new one.
732 const bool had_subscription = !!subscription_;
816 subscription_.reset(); 733 subscription_.reset();
817 734
818 RenderWidgetHost* rwh = GetTarget(); 735 DVLOG(1) << "Renewing frame subscription to RWH@" << rwh
819 if (!rwh || !rwh->GetView()) 736 << ", had_subscription=" << had_subscription;
737
738 if (!rwh) {
739 if (had_subscription && tracker_->web_contents())
740 tracker_->web_contents()->DecrementCapturerCount();
741 if (IsStarted()) {
742 // Tracking of WebContents and/or its main frame has failed before Stop()
743 // was called, so report this as an error:
744 oracle_proxy_->ReportError("WebContents and/or main frame are gone.");
745 }
820 return; 746 return;
747 }
748
749 if (!had_subscription && tracker_->web_contents()) {
750 tracker_->web_contents()->IncrementCapturerCount(
751 ComputeOptimalTargetSize());
752 }
821 753
822 subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_, 754 subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_,
823 base::Bind(&WebContentsCaptureMachine::Capture, 755 base::Bind(&WebContentsCaptureMachine::Capture,
824 weak_ptr_factory_.GetWeakPtr()))); 756 weak_ptr_factory_.GetWeakPtr())));
825 } 757 }
826 758
827 } // namespace 759 } // namespace
828 760
829 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( 761 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
830 int render_process_id, int main_render_frame_id) 762 int render_process_id, int main_render_frame_id)
(...skipping 25 matching lines...) Expand all
856 scoped_ptr<Client> client) { 788 scoped_ptr<Client> client) {
857 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); 789 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString();
858 core_->AllocateAndStart(params, client.Pass()); 790 core_->AllocateAndStart(params, client.Pass());
859 } 791 }
860 792
861 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { 793 void WebContentsVideoCaptureDevice::StopAndDeAllocate() {
862 core_->StopAndDeAllocate(); 794 core_->StopAndDeAllocate();
863 } 795 }
864 796
865 } // namespace content 797 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698