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 |