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 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 #include "content/public/browser/notification_types.h" | 73 #include "content/public/browser/notification_types.h" |
74 #include "content/public/browser/render_view_host.h" | 74 #include "content/public/browser/render_view_host.h" |
75 #include "content/public/browser/render_widget_host_view.h" | 75 #include "content/public/browser/render_widget_host_view.h" |
76 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" | 76 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" |
77 #include "content/public/browser/web_contents_observer.h" | 77 #include "content/public/browser/web_contents_observer.h" |
78 #include "media/base/video_util.h" | 78 #include "media/base/video_util.h" |
79 #include "media/video/capture/video_capture_types.h" | 79 #include "media/video/capture/video_capture_types.h" |
80 #include "skia/ext/image_operations.h" | 80 #include "skia/ext/image_operations.h" |
81 #include "third_party/skia/include/core/SkBitmap.h" | 81 #include "third_party/skia/include/core/SkBitmap.h" |
82 #include "third_party/skia/include/core/SkColor.h" | 82 #include "third_party/skia/include/core/SkColor.h" |
| 83 #include "ui/gfx/display.h" |
| 84 #include "ui/gfx/geometry/size.h" |
| 85 #include "ui/gfx/geometry/size_conversions.h" |
| 86 #include "ui/gfx/screen.h" |
83 | 87 |
84 namespace content { | 88 namespace content { |
85 | 89 |
86 namespace { | 90 namespace { |
87 | 91 |
88 // Compute a letterbox region, aligned to even coordinates. | 92 // Compute a letterbox region, aligned to even coordinates. |
89 gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size, | 93 gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size, |
90 const gfx::Size& content_size) { | 94 const gfx::Size& content_size) { |
91 | 95 |
92 gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size), | 96 gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size), |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 | 270 |
267 virtual void DidNavigateMainFrame( | 271 virtual void DidNavigateMainFrame( |
268 const LoadCommittedDetails& details, | 272 const LoadCommittedDetails& details, |
269 const FrameNavigateParams& params) OVERRIDE { | 273 const FrameNavigateParams& params) OVERRIDE { |
270 RenewFrameSubscription(); | 274 RenewFrameSubscription(); |
271 } | 275 } |
272 | 276 |
273 virtual void WebContentsDestroyed() OVERRIDE; | 277 virtual void WebContentsDestroyed() OVERRIDE; |
274 | 278 |
275 private: | 279 private: |
| 280 // Computes the preferred size of the target RenderWidget for optimal capture. |
| 281 gfx::Size ComputeOptimalTargetSize() const; |
| 282 |
276 // Starts observing the web contents, returning false if lookup fails. | 283 // Starts observing the web contents, returning false if lookup fails. |
277 bool StartObservingWebContents(); | 284 bool StartObservingWebContents(); |
278 | 285 |
279 // Helper function to determine the view that we are currently tracking. | 286 // Helper function to determine the view that we are currently tracking. |
280 RenderWidgetHost* GetTarget(); | 287 RenderWidgetHost* GetTarget() const; |
281 | 288 |
282 // Response callback for RenderWidgetHost::CopyFromBackingStore(). | 289 // Response callback for RenderWidgetHost::CopyFromBackingStore(). |
283 void DidCopyFromBackingStore( | 290 void DidCopyFromBackingStore( |
284 const base::TimeTicks& start_time, | 291 const base::TimeTicks& start_time, |
285 const scoped_refptr<media::VideoFrame>& target, | 292 const scoped_refptr<media::VideoFrame>& target, |
286 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& | 293 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
287 deliver_frame_cb, | 294 deliver_frame_cb, |
288 bool success, | 295 bool success, |
289 const SkBitmap& bitmap); | 296 const SkBitmap& bitmap); |
290 | 297 |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
668 fitted_size, // Size here is a request not always honored. | 675 fitted_size, // Size here is a request not always honored. |
669 base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore, | 676 base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore, |
670 weak_ptr_factory_.GetWeakPtr(), | 677 weak_ptr_factory_.GetWeakPtr(), |
671 start_time, | 678 start_time, |
672 target, | 679 target, |
673 deliver_frame_cb), | 680 deliver_frame_cb), |
674 kN32_SkColorType); | 681 kN32_SkColorType); |
675 } | 682 } |
676 } | 683 } |
677 | 684 |
| 685 gfx::Size WebContentsCaptureMachine::ComputeOptimalTargetSize() const { |
| 686 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 687 |
| 688 gfx::Size optimal_size = oracle_proxy_->GetCaptureSize(); |
| 689 |
| 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 |
| 692 // render widget to the "preferred size," the widget will be physically |
| 693 // rendered at the exact capture size, thereby eliminating unnecessary scaling |
| 694 // operations in the graphics pipeline. |
| 695 RenderWidgetHost* const rwh = GetTarget(); |
| 696 RenderWidgetHostView* const rwhv = rwh ? rwh->GetView() : NULL; |
| 697 if (rwhv) { |
| 698 const gfx::NativeView view = rwhv->GetNativeView(); |
| 699 gfx::Screen* const screen = gfx::Screen::GetScreenFor(view); |
| 700 if (screen->IsDIPEnabled()) { |
| 701 const gfx::Display display = screen->GetDisplayNearestWindow(view); |
| 702 const float scale = display.device_scale_factor(); |
| 703 if (scale > 1.0f) { |
| 704 const gfx::Size shrunk_size( |
| 705 gfx::ToFlooredSize(gfx::ScaleSize(optimal_size, 1.0f / scale))); |
| 706 if (shrunk_size.width() > 0 && shrunk_size.height() > 0) |
| 707 optimal_size = shrunk_size; |
| 708 } |
| 709 } |
| 710 } |
| 711 |
| 712 VLOG(1) << "Computed optimal target size: " << optimal_size.ToString(); |
| 713 return optimal_size; |
| 714 } |
| 715 |
678 bool WebContentsCaptureMachine::StartObservingWebContents() { | 716 bool WebContentsCaptureMachine::StartObservingWebContents() { |
| 717 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 718 |
679 // 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. |
680 // If successful, begin observing the WebContents instance. | 720 // If successful, begin observing the WebContents instance. |
681 // | 721 // |
682 // 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 |
683 // 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 |
684 // 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, |
685 // 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 |
686 // 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 |
687 // meantime, the original RenderFrame may have gone away. | 727 // meantime, the original RenderFrame may have gone away. |
688 Observe(WebContents::FromRenderFrameHost(RenderFrameHost::FromID( | 728 Observe(WebContents::FromRenderFrameHost(RenderFrameHost::FromID( |
689 initial_render_process_id_, initial_main_render_frame_id_))); | 729 initial_render_process_id_, initial_main_render_frame_id_))); |
690 DVLOG_IF(1, !web_contents()) | 730 DVLOG_IF(1, !web_contents()) |
691 << "Could not find WebContents associated with main RenderFrameHost " | 731 << "Could not find WebContents associated with main RenderFrameHost " |
692 << "referenced by render_process_id=" << initial_render_process_id_ | 732 << "referenced by render_process_id=" << initial_render_process_id_ |
693 << ", routing_id=" << initial_main_render_frame_id_; | 733 << ", routing_id=" << initial_main_render_frame_id_; |
694 | 734 |
695 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents()); | 735 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents()); |
696 if (contents) { | 736 if (contents) { |
697 contents->IncrementCapturerCount(oracle_proxy_->GetCaptureSize()); | 737 contents->IncrementCapturerCount(ComputeOptimalTargetSize()); |
698 fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID(); | 738 fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID(); |
699 RenewFrameSubscription(); | 739 RenewFrameSubscription(); |
700 return true; | 740 return true; |
701 } | 741 } |
702 return false; | 742 return false; |
703 } | 743 } |
704 | 744 |
705 void WebContentsCaptureMachine::WebContentsDestroyed() { | 745 void WebContentsCaptureMachine::WebContentsDestroyed() { |
706 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 746 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
707 | 747 |
708 subscription_.reset(); | 748 subscription_.reset(); |
709 web_contents()->DecrementCapturerCount(); | 749 web_contents()->DecrementCapturerCount(); |
710 oracle_proxy_->ReportError("WebContentsDestroyed()"); | 750 oracle_proxy_->ReportError("WebContentsDestroyed()"); |
711 } | 751 } |
712 | 752 |
713 RenderWidgetHost* WebContentsCaptureMachine::GetTarget() { | 753 RenderWidgetHost* WebContentsCaptureMachine::GetTarget() const { |
714 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 754 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
715 if (!web_contents()) | 755 if (!web_contents()) |
716 return NULL; | 756 return NULL; |
717 | 757 |
718 RenderWidgetHost* rwh = NULL; | 758 RenderWidgetHost* rwh = NULL; |
719 if (fullscreen_widget_id_ != MSG_ROUTING_NONE) { | 759 if (fullscreen_widget_id_ != MSG_ROUTING_NONE) { |
720 RenderProcessHost* process = web_contents()->GetRenderProcessHost(); | 760 RenderProcessHost* process = web_contents()->GetRenderProcessHost(); |
721 if (process) | 761 if (process) |
722 rwh = RenderWidgetHost::FromID(process->GetID(), fullscreen_widget_id_); | 762 rwh = RenderWidgetHost::FromID(process->GetID(), fullscreen_widget_id_); |
723 } else { | 763 } else { |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
816 scoped_ptr<Client> client) { | 856 scoped_ptr<Client> client) { |
817 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); | 857 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); |
818 core_->AllocateAndStart(params, client.Pass()); | 858 core_->AllocateAndStart(params, client.Pass()); |
819 } | 859 } |
820 | 860 |
821 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { | 861 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { |
822 core_->StopAndDeAllocate(); | 862 core_->StopAndDeAllocate(); |
823 } | 863 } |
824 | 864 |
825 } // namespace content | 865 } // namespace content |
OLD | NEW |