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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
62 #include "base/memory/scoped_ptr.h" | 62 #include "base/memory/scoped_ptr.h" |
63 #include "base/memory/weak_ptr.h" | 63 #include "base/memory/weak_ptr.h" |
64 #include "base/metrics/histogram.h" | 64 #include "base/metrics/histogram.h" |
65 #include "base/sequenced_task_runner.h" | 65 #include "base/sequenced_task_runner.h" |
66 #include "base/single_thread_task_runner.h" | 66 #include "base/single_thread_task_runner.h" |
67 #include "base/threading/thread.h" | 67 #include "base/threading/thread.h" |
68 #include "base/threading/thread_checker.h" | 68 #include "base/threading/thread_checker.h" |
69 #include "base/time/time.h" | 69 #include "base/time/time.h" |
70 #include "build/build_config.h" | 70 #include "build/build_config.h" |
71 #include "content/browser/media/capture/cursor_renderer.h" | 71 #include "content/browser/media/capture/cursor_renderer.h" |
72 #include "content/browser/media/capture/desktop_capture_device_uma_types.h" | |
72 #include "content/browser/media/capture/web_contents_tracker.h" | 73 #include "content/browser/media/capture/web_contents_tracker.h" |
73 #include "content/browser/media/capture/window_activity_tracker.h" | 74 #include "content/browser/media/capture/window_activity_tracker.h" |
74 #include "content/browser/renderer_host/render_widget_host_impl.h" | 75 #include "content/browser/renderer_host/render_widget_host_impl.h" |
75 #include "content/browser/renderer_host/render_widget_host_view_base.h" | 76 #include "content/browser/renderer_host/render_widget_host_view_base.h" |
76 #include "content/public/browser/browser_thread.h" | 77 #include "content/public/browser/browser_thread.h" |
77 #include "content/public/browser/render_process_host.h" | 78 #include "content/public/browser/render_process_host.h" |
78 #include "content/public/browser/render_widget_host_view.h" | 79 #include "content/public/browser/render_widget_host_view.h" |
79 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" | 80 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" |
80 #include "content/public/browser/web_contents.h" | 81 #include "content/public/browser/web_contents.h" |
81 #include "content/public/browser/web_contents_media_capture_id.h" | 82 #include "content/public/browser/web_contents_media_capture_id.h" |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
253 const SkBitmap& input, | 254 const SkBitmap& input, |
254 const scoped_refptr<media::VideoFrame>& output, | 255 const scoped_refptr<media::VideoFrame>& output, |
255 const base::Callback<void(const gfx::Rect&, bool)>& done_cb); | 256 const base::Callback<void(const gfx::Rect&, bool)>& done_cb); |
256 | 257 |
257 // Renews capture subscriptions based on feedback from WebContentsTracker, and | 258 // Renews capture subscriptions based on feedback from WebContentsTracker, and |
258 // also executes copying of the backing store on the UI BrowserThread. | 259 // also executes copying of the backing store on the UI BrowserThread. |
259 class WebContentsCaptureMachine : public media::VideoCaptureMachine { | 260 class WebContentsCaptureMachine : public media::VideoCaptureMachine { |
260 public: | 261 public: |
261 WebContentsCaptureMachine(int render_process_id, | 262 WebContentsCaptureMachine(int render_process_id, |
262 int main_render_frame_id, | 263 int main_render_frame_id, |
263 bool enable_auto_throttling); | 264 bool enable_auto_throttling, |
265 WebContentsVideoCaptureDevice::JavaScriptType type); | |
264 ~WebContentsCaptureMachine() override; | 266 ~WebContentsCaptureMachine() override; |
265 | 267 |
266 // VideoCaptureMachine overrides. | 268 // VideoCaptureMachine overrides. |
267 void Start(const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, | 269 void Start(const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, |
268 const media::VideoCaptureParams& params, | 270 const media::VideoCaptureParams& params, |
269 const base::Callback<void(bool)> callback) override; | 271 const base::Callback<void(bool)> callback) override; |
270 void Stop(const base::Closure& callback) override; | 272 void Stop(const base::Closure& callback) override; |
271 bool IsAutoThrottlingEnabled() const override { | 273 bool IsAutoThrottlingEnabled() const override { |
272 return auto_throttling_enabled_; | 274 return auto_throttling_enabled_; |
273 } | 275 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
322 | 324 |
323 // Tracks events and calls back to RenewFrameSubscription() to maintain | 325 // Tracks events and calls back to RenewFrameSubscription() to maintain |
324 // capture on the correct RenderWidgetHost. | 326 // capture on the correct RenderWidgetHost. |
325 const scoped_refptr<WebContentsTracker> tracker_; | 327 const scoped_refptr<WebContentsTracker> tracker_; |
326 | 328 |
327 // Set to false to prevent the capture size from automatically adjusting in | 329 // Set to false to prevent the capture size from automatically adjusting in |
328 // response to end-to-end utilization. This is enabled via the throttling | 330 // response to end-to-end utilization. This is enabled via the throttling |
329 // option in the WebContentsVideoCaptureDevice device ID. | 331 // option in the WebContentsVideoCaptureDevice device ID. |
330 const bool auto_throttling_enabled_; | 332 const bool auto_throttling_enabled_; |
331 | 333 |
334 bool is_first_capture_; | |
335 const WebContentsVideoCaptureDevice::JavaScriptType js_type_; | |
336 | |
332 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will | 337 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will |
333 // occur. Only used when this activity cannot be done on the GPU. | 338 // occur. Only used when this activity cannot be done on the GPU. |
334 scoped_ptr<base::Thread> render_thread_; | 339 scoped_ptr<base::Thread> render_thread_; |
335 | 340 |
336 // Makes all the decisions about which frames to copy, and how. | 341 // Makes all the decisions about which frames to copy, and how. |
337 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; | 342 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; |
338 | 343 |
339 // Video capture parameters that this machine is started with. | 344 // Video capture parameters that this machine is started with. |
340 media::VideoCaptureParams capture_params_; | 345 media::VideoCaptureParams capture_params_; |
341 | 346 |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
622 << "WebContentsVideoCaptureDevice is " << measured_fps << " FPS."; | 627 << "WebContentsVideoCaptureDevice is " << measured_fps << " FPS."; |
623 last_frame_rate_log_time_ = frame_time; | 628 last_frame_rate_log_time_ = frame_time; |
624 count_frames_rendered_ = 0; | 629 count_frames_rendered_ = 0; |
625 } | 630 } |
626 } | 631 } |
627 } | 632 } |
628 | 633 |
629 WebContentsCaptureMachine::WebContentsCaptureMachine( | 634 WebContentsCaptureMachine::WebContentsCaptureMachine( |
630 int render_process_id, | 635 int render_process_id, |
631 int main_render_frame_id, | 636 int main_render_frame_id, |
632 bool enable_auto_throttling) | 637 bool enable_auto_throttling, |
638 WebContentsVideoCaptureDevice::JavaScriptType type) | |
633 : initial_render_process_id_(render_process_id), | 639 : initial_render_process_id_(render_process_id), |
634 initial_main_render_frame_id_(main_render_frame_id), | 640 initial_main_render_frame_id_(main_render_frame_id), |
635 tracker_(new WebContentsTracker(true)), | 641 tracker_(new WebContentsTracker(true)), |
636 auto_throttling_enabled_(enable_auto_throttling), | 642 auto_throttling_enabled_(enable_auto_throttling), |
643 js_type_(type), | |
637 weak_ptr_factory_(this) { | 644 weak_ptr_factory_(this) { |
638 DVLOG(1) << "Created WebContentsCaptureMachine for " | 645 DVLOG(1) << "Created WebContentsCaptureMachine for " |
639 << render_process_id << ':' << main_render_frame_id | 646 << render_process_id << ':' << main_render_frame_id |
640 << (auto_throttling_enabled_ ? " with auto-throttling enabled" : ""); | 647 << (auto_throttling_enabled_ ? " with auto-throttling enabled" : ""); |
641 } | 648 } |
642 | 649 |
643 WebContentsCaptureMachine::~WebContentsCaptureMachine() {} | 650 WebContentsCaptureMachine::~WebContentsCaptureMachine() {} |
644 | 651 |
645 bool WebContentsCaptureMachine::IsStarted() const { | 652 bool WebContentsCaptureMachine::IsStarted() const { |
646 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 653 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
647 return weak_ptr_factory_.HasWeakPtrs(); | 654 return weak_ptr_factory_.HasWeakPtrs(); |
648 } | 655 } |
649 | 656 |
650 void WebContentsCaptureMachine::Start( | 657 void WebContentsCaptureMachine::Start( |
651 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, | 658 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, |
652 const media::VideoCaptureParams& params, | 659 const media::VideoCaptureParams& params, |
653 const base::Callback<void(bool)> callback) { | 660 const base::Callback<void(bool)> callback) { |
661 is_first_capture_ = true; | |
662 | |
654 // Starts the capture machine asynchronously. | 663 // Starts the capture machine asynchronously. |
655 BrowserThread::PostTaskAndReplyWithResult( | 664 BrowserThread::PostTaskAndReplyWithResult( |
656 BrowserThread::UI, | 665 BrowserThread::UI, |
657 FROM_HERE, | 666 FROM_HERE, |
658 base::Bind(&WebContentsCaptureMachine::InternalStart, | 667 base::Bind(&WebContentsCaptureMachine::InternalStart, |
659 base::Unretained(this), | 668 base::Unretained(this), |
660 oracle_proxy, | 669 oracle_proxy, |
661 params), | 670 params), |
662 callback); | 671 callback); |
663 } | 672 } |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
859 "Render"); | 868 "Render"); |
860 render_thread_->task_runner()->PostTask( | 869 render_thread_->task_runner()->PostTask( |
861 FROM_HERE, media::BindToCurrentLoop( | 870 FROM_HERE, media::BindToCurrentLoop( |
862 base::Bind(&RenderVideoFrame, bitmap, target, | 871 base::Bind(&RenderVideoFrame, bitmap, target, |
863 base::Bind(deliver_frame_cb, start_time)))); | 872 base::Bind(deliver_frame_cb, start_time)))); |
864 } else { | 873 } else { |
865 // Capture can fail due to transient issues, so just skip this frame. | 874 // Capture can fail due to transient issues, so just skip this frame. |
866 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; | 875 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; |
867 deliver_frame_cb.Run(start_time, gfx::Rect(), false); | 876 deliver_frame_cb.Run(start_time, gfx::Rect(), false); |
868 } | 877 } |
878 | |
879 if (is_first_capture_) { | |
880 is_first_capture_ = false; | |
881 if (js_type_ == | |
882 WebContentsVideoCaptureDevice::CHROME_CHOOSE_DESKTOP_MEDIA) { | |
883 if (response == READBACK_SUCCESS) | |
miu
2016/03/24 20:51:02
It's very possible for the first few frames to fai
GeorgeZ
2016/03/25 16:35:04
Very valuable comments. I guess this is why a owne
| |
884 IncrementDesktopCaptureCounter(FIRST_TAB_CAPTURE_SUCCEEDED); | |
885 else | |
886 IncrementDesktopCaptureCounter(FIRST_TAB_CAPTURE_FAILED); | |
887 } | |
888 } | |
869 } | 889 } |
870 | 890 |
871 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( | 891 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( |
872 const base::TimeTicks& start_time, | 892 const base::TimeTicks& start_time, |
873 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& | 893 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
874 deliver_frame_cb, | 894 deliver_frame_cb, |
875 const gfx::Rect& region_in_frame, | 895 const gfx::Rect& region_in_frame, |
876 bool success) { | 896 bool success) { |
877 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 897 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
878 base::TimeTicks now = base::TimeTicks::Now(); | 898 base::TimeTicks now = base::TimeTicks::Now(); |
879 | 899 |
880 if (success) { | 900 if (success) { |
881 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time); | 901 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time); |
882 } else { | 902 } else { |
883 // Capture can fail due to transient issues, so just skip this frame. | 903 // Capture can fail due to transient issues, so just skip this frame. |
884 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; | 904 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; |
885 } | 905 } |
906 | |
907 if (is_first_capture_) { | |
908 is_first_capture_ = false; | |
909 if (js_type_ == | |
910 WebContentsVideoCaptureDevice::CHROME_CHOOSE_DESKTOP_MEDIA) { | |
911 if (success) | |
912 IncrementDesktopCaptureCounter(FIRST_TAB_CAPTURE_SUCCEEDED); | |
913 else | |
914 IncrementDesktopCaptureCounter(FIRST_TAB_CAPTURE_FAILED); | |
915 } | |
916 } | |
917 | |
886 deliver_frame_cb.Run(start_time, region_in_frame, success); | 918 deliver_frame_cb.Run(start_time, region_in_frame, success); |
887 } | 919 } |
888 | 920 |
889 void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) { | 921 void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) { |
890 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 922 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
891 | 923 |
892 RenderWidgetHost* const rwh = | 924 RenderWidgetHost* const rwh = |
893 had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr; | 925 had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr; |
894 | 926 |
895 // Always destroy the old subscription before creating a new one. | 927 // Always destroy the old subscription before creating a new one. |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
940 << ") from view size (" << view_size.ToString() << ")."; | 972 << ") from view size (" << view_size.ToString() << ")."; |
941 | 973 |
942 oracle_proxy_->UpdateCaptureSize(physical_size); | 974 oracle_proxy_->UpdateCaptureSize(physical_size); |
943 } | 975 } |
944 | 976 |
945 } // namespace | 977 } // namespace |
946 | 978 |
947 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( | 979 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( |
948 int render_process_id, | 980 int render_process_id, |
949 int main_render_frame_id, | 981 int main_render_frame_id, |
950 bool enable_auto_throttling) | 982 bool enable_auto_throttling, |
983 JavaScriptType type) | |
951 : core_(new media::ScreenCaptureDeviceCore( | 984 : core_(new media::ScreenCaptureDeviceCore( |
952 scoped_ptr<media::VideoCaptureMachine>(new WebContentsCaptureMachine( | 985 scoped_ptr<media::VideoCaptureMachine>( |
953 render_process_id, | 986 new WebContentsCaptureMachine(render_process_id, |
954 main_render_frame_id, | 987 main_render_frame_id, |
955 enable_auto_throttling)))) {} | 988 enable_auto_throttling, |
989 type)))) {} | |
956 | 990 |
957 WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() { | 991 WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() { |
958 DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying."; | 992 DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying."; |
959 } | 993 } |
960 | 994 |
961 // static | 995 // static |
962 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create( | 996 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create( |
963 const std::string& device_id) { | 997 const std::string& device_id, |
998 JavaScriptType type) { | |
964 // Parse device_id into render_process_id and main_render_frame_id. | 999 // Parse device_id into render_process_id and main_render_frame_id. |
965 int render_process_id = -1; | 1000 int render_process_id = -1; |
966 int main_render_frame_id = -1; | 1001 int main_render_frame_id = -1; |
967 if (!WebContentsMediaCaptureId::ExtractTabCaptureTarget( | 1002 if (!WebContentsMediaCaptureId::ExtractTabCaptureTarget( |
968 device_id, &render_process_id, &main_render_frame_id)) { | 1003 device_id, &render_process_id, &main_render_frame_id)) { |
969 return NULL; | 1004 return NULL; |
970 } | 1005 } |
971 | 1006 |
1007 if (type == CHROME_CHOOSE_DESKTOP_MEDIA) | |
1008 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED); | |
1009 | |
972 return new WebContentsVideoCaptureDevice( | 1010 return new WebContentsVideoCaptureDevice( |
973 render_process_id, main_render_frame_id, | 1011 render_process_id, main_render_frame_id, |
974 WebContentsMediaCaptureId::IsAutoThrottlingOptionSet(device_id)); | 1012 WebContentsMediaCaptureId::IsAutoThrottlingOptionSet(device_id), type); |
975 } | 1013 } |
976 | 1014 |
977 void WebContentsVideoCaptureDevice::AllocateAndStart( | 1015 void WebContentsVideoCaptureDevice::AllocateAndStart( |
978 const media::VideoCaptureParams& params, | 1016 const media::VideoCaptureParams& params, |
979 scoped_ptr<Client> client) { | 1017 scoped_ptr<Client> client) { |
980 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); | 1018 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); |
981 core_->AllocateAndStart(params, std::move(client)); | 1019 core_->AllocateAndStart(params, std::move(client)); |
982 } | 1020 } |
983 | 1021 |
984 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { | 1022 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { |
985 core_->StopAndDeAllocate(); | 1023 core_->StopAndDeAllocate(); |
986 } | 1024 } |
987 | 1025 |
988 } // namespace content | 1026 } // namespace content |
OLD | NEW |