| 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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 | 87 |
| 88 // Compute a letterbox region, aligned to even coordinates. | 88 // Compute a letterbox region, aligned to even coordinates. |
| 89 gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size, | 89 gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size, |
| 90 const gfx::Size& content_size) { | 90 const gfx::Size& content_size) { |
| 91 | 91 |
| 92 gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size), | 92 gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size), |
| 93 content_size); | 93 content_size); |
| 94 | 94 |
| 95 result.set_x(MakeEven(result.x())); | 95 result.set_x(MakeEven(result.x())); |
| 96 result.set_y(MakeEven(result.y())); | 96 result.set_y(MakeEven(result.y())); |
| 97 result.set_width(std::max(kMinFrameWidth, MakeEven(result.width()))); | |
| 98 result.set_height(std::max(kMinFrameHeight, MakeEven(result.height()))); | |
| 99 | 97 |
| 100 return result; | 98 return result; |
| 101 } | 99 } |
| 102 | 100 |
| 103 // Wrapper function to invoke ThreadSafeCaptureOracle::CaptureFrameCallback, is | |
| 104 // compatible with RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback. | |
| 105 void InvokeCaptureFrameCallback( | |
| 106 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | |
| 107 base::TimeTicks timestamp, | |
| 108 bool frame_captured) { | |
| 109 capture_frame_cb.Run(timestamp, frame_captured); | |
| 110 } | |
| 111 | |
| 112 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread, | 101 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread, |
| 113 const base::Closure& callback) { | 102 const base::Closure& callback) { |
| 114 render_thread.reset(); | 103 render_thread.reset(); |
| 115 | 104 |
| 116 // After thread join call the callback on UI thread. | 105 // After thread join call the callback on UI thread. |
| 117 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | 106 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); |
| 118 } | 107 } |
| 119 | 108 |
| 120 // Responsible for logging the effective frame rate. | 109 // Responsible for logging the effective frame rate. |
| 121 class VideoFrameDeliveryLog { | 110 class VideoFrameDeliveryLog { |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 // notification would get posted back to the UI thread and processed later, and | 220 // notification would get posted back to the UI thread and processed later, and |
| 232 // this seems disadvantageous. | 221 // this seems disadvantageous. |
| 233 class WebContentsCaptureMachine | 222 class WebContentsCaptureMachine |
| 234 : public VideoCaptureMachine, | 223 : public VideoCaptureMachine, |
| 235 public WebContentsObserver { | 224 public WebContentsObserver { |
| 236 public: | 225 public: |
| 237 WebContentsCaptureMachine(int render_process_id, int render_view_id); | 226 WebContentsCaptureMachine(int render_process_id, int render_view_id); |
| 238 virtual ~WebContentsCaptureMachine(); | 227 virtual ~WebContentsCaptureMachine(); |
| 239 | 228 |
| 240 // VideoCaptureMachine overrides. | 229 // VideoCaptureMachine overrides. |
| 241 virtual bool Start( | 230 virtual bool Start(const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, |
| 242 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE; | 231 const media::VideoCaptureParams& params) OVERRIDE; |
| 243 virtual void Stop(const base::Closure& callback) OVERRIDE; | 232 virtual void Stop(const base::Closure& callback) OVERRIDE; |
| 244 | 233 |
| 245 // Starts a copy from the backing store or the composited surface. Must be run | 234 // Starts a copy from the backing store or the composited surface. Must be run |
| 246 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation | 235 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation |
| 247 // completes. The copy will occur to |target|. | 236 // completes. The copy will occur to |target|. |
| 248 // | 237 // |
| 249 // This may be used as a ContentCaptureSubscription::CaptureCallback. | 238 // This may be used as a ContentCaptureSubscription::CaptureCallback. |
| 250 void Capture(const base::TimeTicks& start_time, | 239 void Capture(const base::TimeTicks& start_time, |
| 251 const scoped_refptr<media::VideoFrame>& target, | 240 const scoped_refptr<media::VideoFrame>& target, |
| 252 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& | 241 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 const int initial_render_process_id_; | 301 const int initial_render_process_id_; |
| 313 const int initial_render_view_id_; | 302 const int initial_render_view_id_; |
| 314 | 303 |
| 315 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will | 304 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will |
| 316 // occur. Only used when this activity cannot be done on the GPU. | 305 // occur. Only used when this activity cannot be done on the GPU. |
| 317 scoped_ptr<base::Thread> render_thread_; | 306 scoped_ptr<base::Thread> render_thread_; |
| 318 | 307 |
| 319 // Makes all the decisions about which frames to copy, and how. | 308 // Makes all the decisions about which frames to copy, and how. |
| 320 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; | 309 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; |
| 321 | 310 |
| 311 // Video capture parameters that this machine is started with. |
| 312 media::VideoCaptureParams capture_params_; |
| 313 |
| 322 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE | 314 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE |
| 323 // otherwise. | 315 // otherwise. |
| 324 int fullscreen_widget_id_; | 316 int fullscreen_widget_id_; |
| 325 | 317 |
| 326 // Last known RenderView size. | 318 // Last known RenderView size. |
| 327 gfx::Size last_view_size_; | 319 gfx::Size last_view_size_; |
| 328 | 320 |
| 329 // Responsible for forwarding events from the active RenderWidgetHost to the | 321 // Responsible for forwarding events from the active RenderWidgetHost to the |
| 330 // oracle, and initiating captures accordingly. | 322 // oracle, and initiating captures accordingly. |
| 331 scoped_ptr<ContentCaptureSubscription> subscription_; | 323 scoped_ptr<ContentCaptureSubscription> subscription_; |
| 332 | 324 |
| 333 // Weak pointer factory used to invalidate callbacks. | 325 // Weak pointer factory used to invalidate callbacks. |
| 334 // NOTE: Weak pointers must be invalidated before all other member variables. | 326 // NOTE: Weak pointers must be invalidated before all other member variables. |
| 335 base::WeakPtrFactory<WebContentsCaptureMachine> weak_ptr_factory_; | 327 base::WeakPtrFactory<WebContentsCaptureMachine> weak_ptr_factory_; |
| 336 | 328 |
| 337 DISALLOW_COPY_AND_ASSIGN(WebContentsCaptureMachine); | 329 DISALLOW_COPY_AND_ASSIGN(WebContentsCaptureMachine); |
| 338 }; | 330 }; |
| 339 | 331 |
| 340 bool FrameSubscriber::ShouldCaptureFrame( | 332 bool FrameSubscriber::ShouldCaptureFrame( |
| 341 base::TimeTicks present_time, | 333 base::TimeTicks present_time, |
| 342 scoped_refptr<media::VideoFrame>* storage, | 334 scoped_refptr<media::VideoFrame>* storage, |
| 343 DeliverFrameCallback* deliver_frame_cb) { | 335 DeliverFrameCallback* deliver_frame_cb) { |
| 344 TRACE_EVENT1("mirroring", "FrameSubscriber::ShouldCaptureFrame", | 336 TRACE_EVENT1("mirroring", "FrameSubscriber::ShouldCaptureFrame", |
| 345 "instance", this); | 337 "instance", this); |
| 346 | 338 |
| 347 ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; | 339 ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; |
| 348 bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture( | 340 bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture( |
| 349 event_type_, present_time, storage, &capture_frame_cb); | 341 event_type_, present_time, storage, &capture_frame_cb); |
| 350 | 342 |
| 351 *deliver_frame_cb = base::Bind(&InvokeCaptureFrameCallback, capture_frame_cb); | 343 if (!capture_frame_cb.is_null()) |
| 344 *deliver_frame_cb = base::Bind(capture_frame_cb, *storage); |
| 352 if (oracle_decision) | 345 if (oracle_decision) |
| 353 delivery_log_->ChronicleFrameDelivery(present_time); | 346 delivery_log_->ChronicleFrameDelivery(present_time); |
| 354 return oracle_decision; | 347 return oracle_decision; |
| 355 } | 348 } |
| 356 | 349 |
| 357 ContentCaptureSubscription::ContentCaptureSubscription( | 350 ContentCaptureSubscription::ContentCaptureSubscription( |
| 358 const RenderWidgetHost& source, | 351 const RenderWidgetHost& source, |
| 359 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, | 352 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, |
| 360 const CaptureCallback& capture_callback) | 353 const CaptureCallback& capture_callback) |
| 361 : render_process_id_(source.GetProcess()->GetID()), | 354 : render_process_id_(source.GetProcess()->GetID()), |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 571 weak_ptr_factory_(this) {} | 564 weak_ptr_factory_(this) {} |
| 572 | 565 |
| 573 WebContentsCaptureMachine::~WebContentsCaptureMachine() { | 566 WebContentsCaptureMachine::~WebContentsCaptureMachine() { |
| 574 BrowserThread::PostBlockingPoolTask( | 567 BrowserThread::PostBlockingPoolTask( |
| 575 FROM_HERE, | 568 FROM_HERE, |
| 576 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), | 569 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), |
| 577 base::Bind(&base::DoNothing))); | 570 base::Bind(&base::DoNothing))); |
| 578 } | 571 } |
| 579 | 572 |
| 580 bool WebContentsCaptureMachine::Start( | 573 bool WebContentsCaptureMachine::Start( |
| 581 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) { | 574 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, |
| 575 const media::VideoCaptureParams& params) { |
| 582 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 583 DCHECK(!started_); | 577 DCHECK(!started_); |
| 584 | 578 |
| 585 DCHECK(oracle_proxy.get()); | 579 DCHECK(oracle_proxy.get()); |
| 586 oracle_proxy_ = oracle_proxy; | 580 oracle_proxy_ = oracle_proxy; |
| 581 capture_params_ = params; |
| 587 | 582 |
| 588 render_thread_.reset(new base::Thread("WebContentsVideo_RenderThread")); | 583 render_thread_.reset(new base::Thread("WebContentsVideo_RenderThread")); |
| 589 if (!render_thread_->Start()) { | 584 if (!render_thread_->Start()) { |
| 590 DVLOG(1) << "Failed to spawn render thread."; | 585 DVLOG(1) << "Failed to spawn render thread."; |
| 591 render_thread_.reset(); | 586 render_thread_.reset(); |
| 592 return false; | 587 return false; |
| 593 } | 588 } |
| 594 | 589 |
| 595 if (!StartObservingWebContents()) { | 590 if (!StartObservingWebContents()) { |
| 596 DVLOG(1) << "Failed to observe web contents."; | 591 DVLOG(1) << "Failed to observe web contents."; |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 826 scoped_ptr<Client> client) { | 821 scoped_ptr<Client> client) { |
| 827 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); | 822 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); |
| 828 core_->AllocateAndStart(params, client.Pass()); | 823 core_->AllocateAndStart(params, client.Pass()); |
| 829 } | 824 } |
| 830 | 825 |
| 831 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { | 826 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { |
| 832 core_->StopAndDeAllocate(); | 827 core_->StopAndDeAllocate(); |
| 833 } | 828 } |
| 834 | 829 |
| 835 } // namespace content | 830 } // namespace content |
| OLD | NEW |