| 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 |