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 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 // backing store on the UI BrowserThread. | 218 // backing store on the UI BrowserThread. |
219 // | 219 // |
220 // TODO(nick): It would be nice to merge this with WebContentsTracker, but its | 220 // TODO(nick): It would be nice to merge this with WebContentsTracker, but its |
221 // implementation is currently asynchronous -- in our case, the "rvh changed" | 221 // implementation is currently asynchronous -- in our case, the "rvh changed" |
222 // notification would get posted back to the UI thread and processed later, and | 222 // notification would get posted back to the UI thread and processed later, and |
223 // this seems disadvantageous. | 223 // this seems disadvantageous. |
224 class WebContentsCaptureMachine | 224 class WebContentsCaptureMachine |
225 : public VideoCaptureMachine, | 225 : public VideoCaptureMachine, |
226 public WebContentsObserver { | 226 public WebContentsObserver { |
227 public: | 227 public: |
228 WebContentsCaptureMachine(int render_process_id, int render_view_id); | 228 WebContentsCaptureMachine(int render_process_id, int main_render_frame_id); |
229 virtual ~WebContentsCaptureMachine(); | 229 virtual ~WebContentsCaptureMachine(); |
230 | 230 |
231 // VideoCaptureMachine overrides. | 231 // VideoCaptureMachine overrides. |
232 virtual bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, | 232 virtual bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, |
233 const media::VideoCaptureParams& params) OVERRIDE; | 233 const media::VideoCaptureParams& params) OVERRIDE; |
234 virtual void Stop(const base::Closure& callback) OVERRIDE; | 234 virtual void Stop(const base::Closure& callback) OVERRIDE; |
235 | 235 |
236 // Starts a copy from the backing store or the composited surface. Must be run | 236 // Starts a copy from the backing store or the composited surface. Must be run |
237 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation | 237 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation |
238 // completes. The copy will occur to |target|. | 238 // completes. The copy will occur to |target|. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
294 deliver_frame_cb, | 294 deliver_frame_cb, |
295 bool success); | 295 bool success); |
296 | 296 |
297 // Remove the old subscription, and start a new one. This should be called | 297 // Remove the old subscription, and start a new one. This should be called |
298 // after any change to the WebContents that affects the RenderWidgetHost or | 298 // after any change to the WebContents that affects the RenderWidgetHost or |
299 // attached views. | 299 // attached views. |
300 void RenewFrameSubscription(); | 300 void RenewFrameSubscription(); |
301 | 301 |
302 // Parameters saved in constructor. | 302 // Parameters saved in constructor. |
303 const int initial_render_process_id_; | 303 const int initial_render_process_id_; |
304 const int initial_render_view_id_; | 304 const int initial_main_render_frame_id_; |
305 | 305 |
306 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will | 306 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will |
307 // occur. Only used when this activity cannot be done on the GPU. | 307 // occur. Only used when this activity cannot be done on the GPU. |
308 scoped_ptr<base::Thread> render_thread_; | 308 scoped_ptr<base::Thread> render_thread_; |
309 | 309 |
310 // Makes all the decisions about which frames to copy, and how. | 310 // Makes all the decisions about which frames to copy, and how. |
311 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; | 311 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; |
312 | 312 |
313 // Video capture parameters that this machine is started with. | 313 // Video capture parameters that this machine is started with. |
314 media::VideoCaptureParams capture_params_; | 314 media::VideoCaptureParams capture_params_; |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 static_cast<int>(measured_fps)); | 551 static_cast<int>(measured_fps)); |
552 VLOG(1) << "Current measured frame rate for " | 552 VLOG(1) << "Current measured frame rate for " |
553 << "WebContentsVideoCaptureDevice is " << measured_fps << " FPS."; | 553 << "WebContentsVideoCaptureDevice is " << measured_fps << " FPS."; |
554 last_frame_rate_log_time_ = frame_time; | 554 last_frame_rate_log_time_ = frame_time; |
555 count_frames_rendered_ = 0; | 555 count_frames_rendered_ = 0; |
556 } | 556 } |
557 } | 557 } |
558 } | 558 } |
559 | 559 |
560 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id, | 560 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id, |
561 int render_view_id) | 561 int main_render_frame_id) |
562 : initial_render_process_id_(render_process_id), | 562 : initial_render_process_id_(render_process_id), |
563 initial_render_view_id_(render_view_id), | 563 initial_main_render_frame_id_(main_render_frame_id), |
564 fullscreen_widget_id_(MSG_ROUTING_NONE), | 564 fullscreen_widget_id_(MSG_ROUTING_NONE), |
565 weak_ptr_factory_(this) {} | 565 weak_ptr_factory_(this) {} |
566 | 566 |
567 WebContentsCaptureMachine::~WebContentsCaptureMachine() { | 567 WebContentsCaptureMachine::~WebContentsCaptureMachine() { |
568 BrowserThread::PostBlockingPoolTask( | 568 BrowserThread::PostBlockingPoolTask( |
569 FROM_HERE, | 569 FROM_HERE, |
570 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), | 570 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), |
571 base::Bind(&base::DoNothing))); | 571 base::Bind(&base::DoNothing))); |
572 } | 572 } |
573 | 573 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
665 base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore, | 665 base::Bind(&WebContentsCaptureMachine::DidCopyFromBackingStore, |
666 weak_ptr_factory_.GetWeakPtr(), | 666 weak_ptr_factory_.GetWeakPtr(), |
667 start_time, | 667 start_time, |
668 target, | 668 target, |
669 deliver_frame_cb), | 669 deliver_frame_cb), |
670 kN32_SkColorType); | 670 kN32_SkColorType); |
671 } | 671 } |
672 } | 672 } |
673 | 673 |
674 bool WebContentsCaptureMachine::StartObservingWebContents() { | 674 bool WebContentsCaptureMachine::StartObservingWebContents() { |
675 // Look-up the RenderViewHost and, from that, the WebContents that wraps it. | 675 // Look-up the RenderFrameHost and, from that, the WebContents that wraps it. |
676 // If successful, begin observing the WebContents instance. | 676 // If successful, begin observing the WebContents instance. |
677 // | 677 // |
678 // Why this can be unsuccessful: The request for mirroring originates in a | 678 // Why this can be unsuccessful: The request for mirroring originates in a |
679 // render process, and this request is based on the current RenderView | 679 // render process, and this request is based on the current main RenderFrame |
680 // associated with a tab. However, by the time we get up-and-running here, | 680 // associated with a tab. However, by the time we get up-and-running here, |
681 // there have been multiple back-and-forth IPCs between processes, as well as | 681 // there have been multiple back-and-forth IPCs between processes, as well as |
682 // a bit of indirection across threads. It's easily possible that, in the | 682 // a bit of indirection across threads. It's easily possible that, in the |
683 // meantime, the original RenderView may have gone away. | 683 // meantime, the original RenderFrame may have gone away. |
684 RenderViewHost* const rvh = | 684 Observe(WebContents::FromRenderFrameHost(RenderFrameHost::FromID( |
685 RenderViewHost::FromID(initial_render_process_id_, | 685 initial_render_process_id_, initial_main_render_frame_id_))); |
686 initial_render_view_id_); | 686 DVLOG_IF(1, !web_contents()) |
687 DVLOG_IF(1, !rvh) << "RenderViewHost::FromID(" | 687 << "Could not find WebContents associated with main RenderFrameHost " |
688 << initial_render_process_id_ << ", " | 688 << "referenced by render_process_id=" << initial_render_process_id_ |
689 << initial_render_view_id_ << ") returned NULL."; | 689 << ", routing_id=" << initial_main_render_frame_id_; |
690 Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL); | |
691 | 690 |
692 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents()); | 691 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents()); |
693 if (contents) { | 692 if (contents) { |
694 contents->IncrementCapturerCount(oracle_proxy_->GetCaptureSize()); | 693 contents->IncrementCapturerCount(oracle_proxy_->GetCaptureSize()); |
695 fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID(); | 694 fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID(); |
696 RenewFrameSubscription(); | 695 RenewFrameSubscription(); |
697 return true; | 696 return true; |
698 } | 697 } |
699 | |
700 DVLOG(1) << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL."; | |
701 return false; | 698 return false; |
702 } | 699 } |
703 | 700 |
704 void WebContentsCaptureMachine::WebContentsDestroyed() { | 701 void WebContentsCaptureMachine::WebContentsDestroyed() { |
705 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 702 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
706 | 703 |
707 subscription_.reset(); | 704 subscription_.reset(); |
708 web_contents()->DecrementCapturerCount(); | 705 web_contents()->DecrementCapturerCount(); |
709 oracle_proxy_->ReportError("WebContentsDestroyed()"); | 706 oracle_proxy_->ReportError("WebContentsDestroyed()"); |
710 } | 707 } |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
779 return; | 776 return; |
780 | 777 |
781 subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_, | 778 subscription_.reset(new ContentCaptureSubscription(*rwh, oracle_proxy_, |
782 base::Bind(&WebContentsCaptureMachine::Capture, | 779 base::Bind(&WebContentsCaptureMachine::Capture, |
783 weak_ptr_factory_.GetWeakPtr()))); | 780 weak_ptr_factory_.GetWeakPtr()))); |
784 } | 781 } |
785 | 782 |
786 } // namespace | 783 } // namespace |
787 | 784 |
788 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( | 785 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( |
789 int render_process_id, int render_view_id) | 786 int render_process_id, int main_render_frame_id) |
790 : core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>( | 787 : core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>( |
791 new WebContentsCaptureMachine(render_process_id, render_view_id)))) {} | 788 new WebContentsCaptureMachine( |
| 789 render_process_id, main_render_frame_id)))) {} |
792 | 790 |
793 WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() { | 791 WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() { |
794 DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying."; | 792 DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying."; |
795 } | 793 } |
796 | 794 |
797 // static | 795 // static |
798 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create( | 796 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create( |
799 const std::string& device_id) { | 797 const std::string& device_id) { |
800 // Parse device_id into render_process_id and render_view_id. | 798 // Parse device_id into render_process_id and render_view_id. |
801 int render_process_id = -1; | 799 int render_process_id = -1; |
802 int render_view_id = -1; | 800 int main_render_frame_id = -1; |
803 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget( | 801 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget( |
804 device_id, &render_process_id, &render_view_id)) { | 802 device_id, &render_process_id, &main_render_frame_id)) { |
805 return NULL; | 803 return NULL; |
806 } | 804 } |
807 | 805 |
808 return new WebContentsVideoCaptureDevice(render_process_id, render_view_id); | 806 return new WebContentsVideoCaptureDevice( |
| 807 render_process_id, main_render_frame_id); |
809 } | 808 } |
810 | 809 |
811 void WebContentsVideoCaptureDevice::AllocateAndStart( | 810 void WebContentsVideoCaptureDevice::AllocateAndStart( |
812 const media::VideoCaptureParams& params, | 811 const media::VideoCaptureParams& params, |
813 scoped_ptr<Client> client) { | 812 scoped_ptr<Client> client) { |
814 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); | 813 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); |
815 core_->AllocateAndStart(params, client.Pass()); | 814 core_->AllocateAndStart(params, client.Pass()); |
816 } | 815 } |
817 | 816 |
818 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { | 817 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { |
819 core_->StopAndDeAllocate(); | 818 core_->StopAndDeAllocate(); |
820 } | 819 } |
821 | 820 |
822 } // namespace content | 821 } // namespace content |
OLD | NEW |