Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 364 const CaptureCallback& capture_callback) | 364 const CaptureCallback& capture_callback) |
| 365 : render_process_id_(source.GetProcess()->GetID()), | 365 : render_process_id_(source.GetProcess()->GetID()), |
| 366 render_view_id_(source.GetRoutingID()), | 366 render_view_id_(source.GetRoutingID()), |
| 367 delivery_log_(), | 367 delivery_log_(), |
| 368 paint_subscriber_(VideoCaptureOracle::kSoftwarePaint, oracle_proxy, | 368 paint_subscriber_(VideoCaptureOracle::kSoftwarePaint, oracle_proxy, |
| 369 &delivery_log_), | 369 &delivery_log_), |
| 370 timer_subscriber_(VideoCaptureOracle::kTimerPoll, oracle_proxy, | 370 timer_subscriber_(VideoCaptureOracle::kTimerPoll, oracle_proxy, |
| 371 &delivery_log_), | 371 &delivery_log_), |
| 372 capture_callback_(capture_callback), | 372 capture_callback_(capture_callback), |
| 373 timer_(true, true) { | 373 timer_(true, true) { |
| 374 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 374 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 375 | 375 |
| 376 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( | 376 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( |
| 377 source.GetView()); | 377 source.GetView()); |
| 378 | 378 |
| 379 // Subscribe to accelerated presents. These will be serviced directly by the | 379 // Subscribe to accelerated presents. These will be serviced directly by the |
| 380 // oracle. | 380 // oracle. |
| 381 if (view && kAcceleratedSubscriberIsSupported) { | 381 if (view && kAcceleratedSubscriberIsSupported) { |
| 382 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( | 382 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( |
| 383 new FrameSubscriber(VideoCaptureOracle::kCompositorUpdate, | 383 new FrameSubscriber(VideoCaptureOracle::kCompositorUpdate, |
| 384 oracle_proxy, &delivery_log_)); | 384 oracle_proxy, &delivery_log_)); |
| 385 view->BeginFrameSubscription(subscriber.Pass()); | 385 view->BeginFrameSubscription(subscriber.Pass()); |
| 386 } | 386 } |
| 387 | 387 |
| 388 // Subscribe to software paint events. This instance will service these by | 388 // Subscribe to software paint events. This instance will service these by |
| 389 // reflecting them back to the WebContentsCaptureMachine via | 389 // reflecting them back to the WebContentsCaptureMachine via |
| 390 // |capture_callback|. | 390 // |capture_callback|. |
| 391 registrar_.Add( | 391 registrar_.Add( |
| 392 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, | 392 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, |
| 393 Source<RenderWidgetHost>(&source)); | 393 Source<RenderWidgetHost>(&source)); |
| 394 | 394 |
| 395 // Subscribe to timer events. This instance will service these as well. | 395 // Subscribe to timer events. This instance will service these as well. |
| 396 timer_.Start(FROM_HERE, oracle_proxy->min_capture_period(), | 396 timer_.Start(FROM_HERE, oracle_proxy->min_capture_period(), |
| 397 base::Bind(&ContentCaptureSubscription::OnTimer, | 397 base::Bind(&ContentCaptureSubscription::OnTimer, |
| 398 base::Unretained(this))); | 398 base::Unretained(this))); |
| 399 } | 399 } |
| 400 | 400 |
| 401 ContentCaptureSubscription::~ContentCaptureSubscription() { | 401 ContentCaptureSubscription::~ContentCaptureSubscription() { |
| 402 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 402 // 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 | |
| 404 // return early. http://crbug.com/396413 | |
| 405 if (!BrowserThread::IsMessageLoopValid(BrowserThread::UI)) | |
|
miu
2014/08/28 01:59:56
This is the fix: Calling RenderViewHost::FromID(..
| |
| 406 return; | |
| 407 | |
| 408 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 403 if (kAcceleratedSubscriberIsSupported) { | 409 if (kAcceleratedSubscriberIsSupported) { |
| 404 RenderViewHost* source = RenderViewHost::FromID(render_process_id_, | 410 RenderViewHost* source = RenderViewHost::FromID(render_process_id_, |
| 405 render_view_id_); | 411 render_view_id_); |
| 406 if (source) { | 412 if (source) { |
| 407 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( | 413 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( |
| 408 source->GetView()); | 414 source->GetView()); |
| 409 if (view) | 415 if (view) |
| 410 view->EndFrameSubscription(); | 416 view->EndFrameSubscription(); |
| 411 } | 417 } |
| 412 } | 418 } |
| 413 } | 419 } |
| 414 | 420 |
| 415 void ContentCaptureSubscription::Observe( | 421 void ContentCaptureSubscription::Observe( |
| 416 int type, | 422 int type, |
| 417 const content::NotificationSource& source, | 423 const content::NotificationSource& source, |
| 418 const content::NotificationDetails& details) { | 424 const content::NotificationDetails& details) { |
| 419 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 425 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 420 DCHECK_EQ(NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, type); | 426 DCHECK_EQ(NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, type); |
| 421 | 427 |
| 422 RenderWidgetHostImpl* rwh = | 428 RenderWidgetHostImpl* rwh = |
| 423 RenderWidgetHostImpl::From(Source<RenderWidgetHost>(source).ptr()); | 429 RenderWidgetHostImpl::From(Source<RenderWidgetHost>(source).ptr()); |
| 424 | 430 |
| 425 // This message occurs on window resizes and visibility changes even when | 431 // This message occurs on window resizes and visibility changes even when |
| 426 // accelerated compositing is active, so we need to filter out these cases. | 432 // accelerated compositing is active, so we need to filter out these cases. |
| 427 if (!rwh || !rwh->GetView()) | 433 if (!rwh || !rwh->GetView()) |
| 428 return; | 434 return; |
| 429 // Mac sends DID_UPDATE_BACKING_STORE messages to inform the capture system | 435 // Mac sends DID_UPDATE_BACKING_STORE messages to inform the capture system |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 448 &deliver_frame_cb)) { | 454 &deliver_frame_cb)) { |
| 449 // This message happens just before paint. If we post a task to do the copy, | 455 // This message happens just before paint. If we post a task to do the copy, |
| 450 // it should run soon after the paint. | 456 // it should run soon after the paint. |
| 451 BrowserThread::PostTask( | 457 BrowserThread::PostTask( |
| 452 BrowserThread::UI, FROM_HERE, | 458 BrowserThread::UI, FROM_HERE, |
| 453 base::Bind(capture_callback_, start_time, frame, deliver_frame_cb)); | 459 base::Bind(capture_callback_, start_time, frame, deliver_frame_cb)); |
| 454 } | 460 } |
| 455 } | 461 } |
| 456 | 462 |
| 457 void ContentCaptureSubscription::OnTimer() { | 463 void ContentCaptureSubscription::OnTimer() { |
| 458 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 464 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 459 TRACE_EVENT0("mirroring", "ContentCaptureSubscription::OnTimer"); | 465 TRACE_EVENT0("mirroring", "ContentCaptureSubscription::OnTimer"); |
| 460 | 466 |
| 461 scoped_refptr<media::VideoFrame> frame; | 467 scoped_refptr<media::VideoFrame> frame; |
| 462 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb; | 468 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb; |
| 463 | 469 |
| 464 const base::TimeTicks start_time = base::TimeTicks::Now(); | 470 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 465 if (timer_subscriber_.ShouldCaptureFrame(gfx::Rect(), | 471 if (timer_subscriber_.ShouldCaptureFrame(gfx::Rect(), |
| 466 start_time, | 472 start_time, |
| 467 &frame, | 473 &frame, |
| 468 &deliver_frame_cb)) { | 474 &deliver_frame_cb)) { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 568 } | 574 } |
| 569 } | 575 } |
| 570 | 576 |
| 571 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id, | 577 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id, |
| 572 int main_render_frame_id) | 578 int main_render_frame_id) |
| 573 : initial_render_process_id_(render_process_id), | 579 : initial_render_process_id_(render_process_id), |
| 574 initial_main_render_frame_id_(main_render_frame_id), | 580 initial_main_render_frame_id_(main_render_frame_id), |
| 575 fullscreen_widget_id_(MSG_ROUTING_NONE), | 581 fullscreen_widget_id_(MSG_ROUTING_NONE), |
| 576 weak_ptr_factory_(this) {} | 582 weak_ptr_factory_(this) {} |
| 577 | 583 |
| 578 WebContentsCaptureMachine::~WebContentsCaptureMachine() { | 584 WebContentsCaptureMachine::~WebContentsCaptureMachine() {} |
| 579 BrowserThread::PostBlockingPoolTask( | |
| 580 FROM_HERE, | |
| 581 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), | |
| 582 base::Bind(&base::DoNothing))); | |
| 583 } | |
| 584 | 585 |
| 585 bool WebContentsCaptureMachine::Start( | 586 bool WebContentsCaptureMachine::Start( |
| 586 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, | 587 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, |
| 587 const media::VideoCaptureParams& params) { | 588 const media::VideoCaptureParams& params) { |
| 588 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 589 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 589 DCHECK(!started_); | 590 DCHECK(!weak_ptr_factory_.HasWeakPtrs()); // Should not be started. |
| 590 | 591 |
| 591 DCHECK(oracle_proxy.get()); | 592 DCHECK(oracle_proxy.get()); |
| 592 oracle_proxy_ = oracle_proxy; | 593 oracle_proxy_ = oracle_proxy; |
| 593 capture_params_ = params; | 594 capture_params_ = params; |
| 594 | 595 |
| 595 render_thread_.reset(new base::Thread("WebContentsVideo_RenderThread")); | 596 render_thread_.reset(new base::Thread("WebContentsVideo_RenderThread")); |
| 596 if (!render_thread_->Start()) { | 597 if (!render_thread_->Start()) { |
| 597 DVLOG(1) << "Failed to spawn render thread."; | 598 DVLOG(1) << "Failed to spawn render thread."; |
| 598 render_thread_.reset(); | 599 render_thread_.reset(); |
| 599 return false; | 600 return false; |
| 600 } | 601 } |
| 601 | 602 |
| 602 if (!StartObservingWebContents()) { | 603 if (!StartObservingWebContents()) { |
| 603 DVLOG(1) << "Failed to observe web contents."; | 604 DVLOG(1) << "Failed to observe web contents."; |
| 604 render_thread_.reset(); | 605 render_thread_.reset(); |
| 605 return false; | 606 return false; |
| 606 } | 607 } |
| 607 | 608 |
| 608 started_ = true; | |
| 609 return true; | 609 return true; |
| 610 } | 610 } |
| 611 | 611 |
| 612 void WebContentsCaptureMachine::Stop(const base::Closure& callback) { | 612 void WebContentsCaptureMachine::Stop(const base::Closure& callback) { |
| 613 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 613 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 614 subscription_.reset(); | 614 subscription_.reset(); |
| 615 if (web_contents()) { | 615 if (web_contents()) { |
| 616 web_contents()->DecrementCapturerCount(); | 616 web_contents()->DecrementCapturerCount(); |
| 617 Observe(NULL); | 617 Observe(NULL); |
| 618 } | 618 } |
| 619 | 619 |
| 620 // Any callback that intend to use render_thread_ will not work after it is | 620 // Any callback that intend to use render_thread_ will not work after it is |
| 621 // passed. | 621 // passed. |
| 622 weak_ptr_factory_.InvalidateWeakPtrs(); | 622 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 623 | 623 |
| 624 // The render thread cannot be stopped on the UI thread, so post a message | 624 // The render thread cannot be stopped on the UI thread, so post a message |
| 625 // to the thread pool used for blocking operations. | 625 // to the thread pool used for blocking operations. |
| 626 BrowserThread::PostBlockingPoolTask( | 626 if (render_thread_.get()) { |
| 627 FROM_HERE, | 627 BrowserThread::PostBlockingPoolTask( |
| 628 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), | 628 FROM_HERE, |
| 629 callback)); | 629 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), |
| 630 | 630 callback)); |
| 631 started_ = false; | 631 } |
| 632 } | 632 } |
| 633 | 633 |
| 634 void WebContentsCaptureMachine::Capture( | 634 void WebContentsCaptureMachine::Capture( |
| 635 const base::TimeTicks& start_time, | 635 const base::TimeTicks& start_time, |
| 636 const scoped_refptr<media::VideoFrame>& target, | 636 const scoped_refptr<media::VideoFrame>& target, |
| 637 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& | 637 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
| 638 deliver_frame_cb) { | 638 deliver_frame_cb) { |
| 639 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 639 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 640 | 640 |
| 641 RenderWidgetHost* rwh = GetTarget(); | 641 RenderWidgetHost* rwh = GetTarget(); |
| 642 RenderWidgetHostViewBase* view = | 642 RenderWidgetHostViewBase* view = |
| 643 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL; | 643 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL; |
| 644 if (!view || !rwh) { | 644 if (!view || !rwh) { |
| 645 deliver_frame_cb.Run(base::TimeTicks(), false); | 645 deliver_frame_cb.Run(base::TimeTicks(), false); |
| 646 return; | 646 return; |
| 647 } | 647 } |
| 648 | 648 |
| 649 gfx::Size video_size = target->coded_size(); | 649 gfx::Size video_size = target->coded_size(); |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 676 base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore, | 676 base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore, |
| 677 weak_ptr_factory_.GetWeakPtr(), | 677 weak_ptr_factory_.GetWeakPtr(), |
| 678 start_time, | 678 start_time, |
| 679 target, | 679 target, |
| 680 deliver_frame_cb), | 680 deliver_frame_cb), |
| 681 kN32_SkColorType); | 681 kN32_SkColorType); |
| 682 } | 682 } |
| 683 } | 683 } |
| 684 | 684 |
| 685 gfx::Size WebContentsCaptureMachine::ComputeOptimalTargetSize() const { | 685 gfx::Size WebContentsCaptureMachine::ComputeOptimalTargetSize() const { |
| 686 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 686 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 687 | 687 |
| 688 gfx::Size optimal_size = oracle_proxy_->GetCaptureSize(); | 688 gfx::Size optimal_size = oracle_proxy_->GetCaptureSize(); |
| 689 | 689 |
| 690 // If the ratio between physical and logical pixels is greater than 1:1, | 690 // 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 | 691 // shrink |optimal_size| by that amount. Then, when external code resizes the |
| 692 // render widget to the "preferred size," the widget will be physically | 692 // render widget to the "preferred size," the widget will be physically |
| 693 // rendered at the exact capture size, thereby eliminating unnecessary scaling | 693 // rendered at the exact capture size, thereby eliminating unnecessary scaling |
| 694 // operations in the graphics pipeline. | 694 // operations in the graphics pipeline. |
| 695 RenderWidgetHost* const rwh = GetTarget(); | 695 RenderWidgetHost* const rwh = GetTarget(); |
| 696 RenderWidgetHostView* const rwhv = rwh ? rwh->GetView() : NULL; | 696 RenderWidgetHostView* const rwhv = rwh ? rwh->GetView() : NULL; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 707 optimal_size = shrunk_size; | 707 optimal_size = shrunk_size; |
| 708 } | 708 } |
| 709 } | 709 } |
| 710 } | 710 } |
| 711 | 711 |
| 712 VLOG(1) << "Computed optimal target size: " << optimal_size.ToString(); | 712 VLOG(1) << "Computed optimal target size: " << optimal_size.ToString(); |
| 713 return optimal_size; | 713 return optimal_size; |
| 714 } | 714 } |
| 715 | 715 |
| 716 bool WebContentsCaptureMachine::StartObservingWebContents() { | 716 bool WebContentsCaptureMachine::StartObservingWebContents() { |
| 717 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 717 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 718 | 718 |
| 719 // Look-up the RenderFrameHost and, from that, the WebContents that wraps it. | 719 // Look-up the RenderFrameHost and, from that, the WebContents that wraps it. |
| 720 // If successful, begin observing the WebContents instance. | 720 // If successful, begin observing the WebContents instance. |
| 721 // | 721 // |
| 722 // Why this can be unsuccessful: The request for mirroring originates in a | 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 | 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, | 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 | 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 | 726 // a bit of indirection across threads. It's easily possible that, in the |
| 727 // meantime, the original RenderFrame may have gone away. | 727 // meantime, the original RenderFrame may have gone away. |
| 728 Observe(WebContents::FromRenderFrameHost(RenderFrameHost::FromID( | 728 Observe(WebContents::FromRenderFrameHost(RenderFrameHost::FromID( |
| 729 initial_render_process_id_, initial_main_render_frame_id_))); | 729 initial_render_process_id_, initial_main_render_frame_id_))); |
| 730 DVLOG_IF(1, !web_contents()) | 730 DVLOG_IF(1, !web_contents()) |
| 731 << "Could not find WebContents associated with main RenderFrameHost " | 731 << "Could not find WebContents associated with main RenderFrameHost " |
| 732 << "referenced by render_process_id=" << initial_render_process_id_ | 732 << "referenced by render_process_id=" << initial_render_process_id_ |
| 733 << ", routing_id=" << initial_main_render_frame_id_; | 733 << ", routing_id=" << initial_main_render_frame_id_; |
| 734 | 734 |
| 735 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents()); | 735 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents()); |
| 736 if (contents) { | 736 if (contents) { |
| 737 contents->IncrementCapturerCount(ComputeOptimalTargetSize()); | 737 contents->IncrementCapturerCount(ComputeOptimalTargetSize()); |
| 738 fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID(); | 738 fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID(); |
| 739 RenewFrameSubscription(); | 739 RenewFrameSubscription(); |
| 740 return true; | 740 return true; |
| 741 } | 741 } |
| 742 return false; | 742 return false; |
| 743 } | 743 } |
| 744 | 744 |
| 745 void WebContentsCaptureMachine::WebContentsDestroyed() { | 745 void WebContentsCaptureMachine::WebContentsDestroyed() { |
| 746 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 746 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 747 | 747 |
| 748 subscription_.reset(); | 748 subscription_.reset(); |
| 749 web_contents()->DecrementCapturerCount(); | 749 web_contents()->DecrementCapturerCount(); |
| 750 oracle_proxy_->ReportError("WebContentsDestroyed()"); | 750 oracle_proxy_->ReportError("WebContentsDestroyed()"); |
| 751 } | 751 } |
| 752 | 752 |
| 753 RenderWidgetHost* WebContentsCaptureMachine::GetTarget() const { | 753 RenderWidgetHost* WebContentsCaptureMachine::GetTarget() const { |
| 754 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 754 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 755 if (!web_contents()) | 755 if (!web_contents()) |
| 756 return NULL; | 756 return NULL; |
| 757 | 757 |
| 758 RenderWidgetHost* rwh = NULL; | 758 RenderWidgetHost* rwh = NULL; |
| 759 if (fullscreen_widget_id_ != MSG_ROUTING_NONE) { | 759 if (fullscreen_widget_id_ != MSG_ROUTING_NONE) { |
| 760 RenderProcessHost* process = web_contents()->GetRenderProcessHost(); | 760 RenderProcessHost* process = web_contents()->GetRenderProcessHost(); |
| 761 if (process) | 761 if (process) |
| 762 rwh = RenderWidgetHost::FromID(process->GetID(), fullscreen_widget_id_); | 762 rwh = RenderWidgetHost::FromID(process->GetID(), fullscreen_widget_id_); |
| 763 } else { | 763 } else { |
| 764 rwh = web_contents()->GetRenderViewHost(); | 764 rwh = web_contents()->GetRenderViewHost(); |
| 765 } | 765 } |
| 766 | 766 |
| 767 return rwh; | 767 return rwh; |
| 768 } | 768 } |
| 769 | 769 |
| 770 void WebContentsCaptureMachine::DidCopyFromBackingStore( | 770 void WebContentsCaptureMachine::DidCopyFromBackingStore( |
| 771 const base::TimeTicks& start_time, | 771 const base::TimeTicks& start_time, |
| 772 const scoped_refptr<media::VideoFrame>& target, | 772 const scoped_refptr<media::VideoFrame>& target, |
| 773 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& | 773 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
| 774 deliver_frame_cb, | 774 deliver_frame_cb, |
| 775 bool success, | 775 bool success, |
| 776 const SkBitmap& bitmap) { | 776 const SkBitmap& bitmap) { |
| 777 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 777 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 778 | 778 |
| 779 base::TimeTicks now = base::TimeTicks::Now(); | 779 base::TimeTicks now = base::TimeTicks::Now(); |
| 780 DCHECK(render_thread_.get()); | 780 DCHECK(render_thread_.get()); |
| 781 if (success) { | 781 if (success) { |
| 782 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); | 782 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); |
| 783 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(), | 783 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(), |
| 784 "Render"); | 784 "Render"); |
| 785 render_thread_->message_loop_proxy()->PostTask(FROM_HERE, base::Bind( | 785 render_thread_->message_loop_proxy()->PostTask(FROM_HERE, base::Bind( |
| 786 &RenderVideoFrame, bitmap, target, | 786 &RenderVideoFrame, bitmap, target, |
| 787 base::Bind(deliver_frame_cb, start_time))); | 787 base::Bind(deliver_frame_cb, start_time))); |
| 788 } else { | 788 } else { |
| 789 // Capture can fail due to transient issues, so just skip this frame. | 789 // Capture can fail due to transient issues, so just skip this frame. |
| 790 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; | 790 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; |
| 791 deliver_frame_cb.Run(start_time, false); | 791 deliver_frame_cb.Run(start_time, false); |
| 792 } | 792 } |
| 793 } | 793 } |
| 794 | 794 |
| 795 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( | 795 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( |
| 796 const base::TimeTicks& start_time, | 796 const base::TimeTicks& start_time, |
| 797 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& | 797 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
| 798 deliver_frame_cb, | 798 deliver_frame_cb, |
| 799 bool success) { | 799 bool success) { |
| 800 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 800 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 801 base::TimeTicks now = base::TimeTicks::Now(); | 801 base::TimeTicks now = base::TimeTicks::Now(); |
| 802 | 802 |
| 803 if (success) { | 803 if (success) { |
| 804 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time); | 804 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time); |
| 805 } else { | 805 } else { |
| 806 // Capture can fail due to transient issues, so just skip this frame. | 806 // Capture can fail due to transient issues, so just skip this frame. |
| 807 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; | 807 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; |
| 808 } | 808 } |
| 809 deliver_frame_cb.Run(start_time, success); | 809 deliver_frame_cb.Run(start_time, success); |
| 810 } | 810 } |
| 811 | 811 |
| 812 void WebContentsCaptureMachine::RenewFrameSubscription() { | 812 void WebContentsCaptureMachine::RenewFrameSubscription() { |
| 813 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 813 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 814 | 814 |
| 815 // Always destroy the old subscription before creating a new one. | 815 // Always destroy the old subscription before creating a new one. |
| 816 subscription_.reset(); | 816 subscription_.reset(); |
| 817 | 817 |
| 818 RenderWidgetHost* rwh = GetTarget(); | 818 RenderWidgetHost* rwh = GetTarget(); |
| 819 if (!rwh || !rwh->GetView()) | 819 if (!rwh || !rwh->GetView()) |
| 820 return; | 820 return; |
| 821 | 821 |
| 822 subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_, | 822 subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_, |
| 823 base::Bind(&WebContentsCaptureMachine::Capture, | 823 base::Bind(&WebContentsCaptureMachine::Capture, |
| 824 weak_ptr_factory_.GetWeakPtr()))); | 824 weak_ptr_factory_.GetWeakPtr()))); |
| 825 } | 825 } |
| 826 | 826 |
| 827 } // namespace | 827 } // namespace |
| 828 | 828 |
| 829 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( | 829 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( |
| 830 int render_process_id, int main_render_frame_id) | 830 int render_process_id, int main_render_frame_id) |
| 831 : core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>( | 831 : core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>( |
| 832 new WebContentsCaptureMachine( | 832 new WebContentsCaptureMachine( |
| 833 render_process_id, main_render_frame_id)))) {} | 833 render_process_id, main_render_frame_id)))) {} |
| 834 | 834 |
| 835 WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() { | 835 WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() { |
| 836 DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying."; | 836 DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying."; |
| 837 } | 837 } |
| 838 | 838 |
| 839 // static | 839 // static |
| 840 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create( | 840 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create( |
| 841 const std::string& device_id) { | 841 const std::string& device_id) { |
| 842 // Parse device_id into render_process_id and render_view_id. | 842 // Parse device_id into render_process_id and main_render_frame_id. |
| 843 int render_process_id = -1; | 843 int render_process_id = -1; |
| 844 int main_render_frame_id = -1; | 844 int main_render_frame_id = -1; |
| 845 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget( | 845 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget( |
| 846 device_id, &render_process_id, &main_render_frame_id)) { | 846 device_id, &render_process_id, &main_render_frame_id)) { |
| 847 return NULL; | 847 return NULL; |
| 848 } | 848 } |
| 849 | 849 |
| 850 return new WebContentsVideoCaptureDevice( | 850 return new WebContentsVideoCaptureDevice( |
| 851 render_process_id, main_render_frame_id); | 851 render_process_id, main_render_frame_id); |
| 852 } | 852 } |
| 853 | 853 |
| 854 void WebContentsVideoCaptureDevice::AllocateAndStart( | 854 void WebContentsVideoCaptureDevice::AllocateAndStart( |
| 855 const media::VideoCaptureParams& params, | 855 const media::VideoCaptureParams& params, |
| 856 scoped_ptr<Client> client) { | 856 scoped_ptr<Client> client) { |
| 857 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); | 857 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); |
| 858 core_->AllocateAndStart(params, client.Pass()); | 858 core_->AllocateAndStart(params, client.Pass()); |
| 859 } | 859 } |
| 860 | 860 |
| 861 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { | 861 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { |
| 862 core_->StopAndDeAllocate(); | 862 core_->StopAndDeAllocate(); |
| 863 } | 863 } |
| 864 | 864 |
| 865 } // namespace content | 865 } // namespace content |
| OLD | NEW |