Chromium Code Reviews| 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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 77 #include "media/base/video_util.h" | 77 #include "media/base/video_util.h" |
| 78 #include "media/video/capture/video_capture_types.h" | 78 #include "media/video/capture/video_capture_types.h" |
| 79 #include "skia/ext/image_operations.h" | 79 #include "skia/ext/image_operations.h" |
| 80 #include "third_party/skia/include/core/SkBitmap.h" | 80 #include "third_party/skia/include/core/SkBitmap.h" |
| 81 #include "third_party/skia/include/core/SkColor.h" | 81 #include "third_party/skia/include/core/SkColor.h" |
| 82 | 82 |
| 83 namespace content { | 83 namespace content { |
| 84 | 84 |
| 85 namespace { | 85 namespace { |
| 86 | 86 |
| 87 const char kRenderThreadName[] = "WebContentsVideo_RenderThread"; | |
| 88 | |
| 87 // Compute a letterbox region, aligned to even coordinates. | 89 // Compute a letterbox region, aligned to even coordinates. |
| 88 gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size, | 90 gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size, |
| 89 const gfx::Size& content_size) { | 91 const gfx::Size& content_size) { |
| 90 | 92 |
| 91 gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size), | 93 gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size), |
| 92 content_size); | 94 content_size); |
| 93 | 95 |
| 94 result.set_x(MakeEven(result.x())); | 96 result.set_x(MakeEven(result.x())); |
| 95 result.set_y(MakeEven(result.y())); | 97 result.set_y(MakeEven(result.y())); |
| 96 result.set_width(std::max(kMinFrameWidth, MakeEven(result.width()))); | 98 result.set_width(std::max(kMinFrameWidth, MakeEven(result.width()))); |
| 97 result.set_height(std::max(kMinFrameHeight, MakeEven(result.height()))); | 99 result.set_height(std::max(kMinFrameHeight, MakeEven(result.height()))); |
| 98 | 100 |
| 99 return result; | 101 return result; |
| 100 } | 102 } |
| 101 | 103 |
| 102 // Wrapper function to invoke ThreadSafeCaptureOracle::CaptureFrameCallback, is | 104 // Wrapper function to invoke ThreadSafeCaptureOracle::CaptureFrameCallback, is |
| 103 // compatible with RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback. | 105 // compatible with RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback. |
| 104 void InvokeCaptureFrameCallback( | 106 void InvokeCaptureFrameCallback( |
| 105 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | 107 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, |
| 106 base::TimeTicks timestamp, | 108 base::TimeTicks timestamp, |
| 107 bool frame_captured) { | 109 bool frame_captured) { |
| 108 capture_frame_cb.Run(timestamp, frame_captured); | 110 capture_frame_cb.Run(timestamp, frame_captured); |
| 109 } | 111 } |
| 110 | 112 |
| 113 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread, | |
| 114 const base::Closure& callback) { | |
| 115 render_thread.reset(); | |
| 116 | |
| 117 // After thread join call the callback on UI thread. | |
| 118 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | |
| 119 } | |
| 120 | |
| 111 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible | 121 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible |
| 112 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. | 122 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. |
| 113 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { | 123 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { |
| 114 public: | 124 public: |
| 115 FrameSubscriber(VideoCaptureOracle::Event event_type, | 125 FrameSubscriber(VideoCaptureOracle::Event event_type, |
| 116 const scoped_refptr<ThreadSafeCaptureOracle>& oracle) | 126 const scoped_refptr<ThreadSafeCaptureOracle>& oracle) |
| 117 : event_type_(event_type), | 127 : event_type_(event_type), |
| 118 oracle_proxy_(oracle) {} | 128 oracle_proxy_(oracle) {} |
| 119 | 129 |
| 120 virtual bool ShouldCaptureFrame( | 130 virtual bool ShouldCaptureFrame( |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 204 : public VideoCaptureMachine, | 214 : public VideoCaptureMachine, |
| 205 public WebContentsObserver, | 215 public WebContentsObserver, |
| 206 public base::SupportsWeakPtr<WebContentsCaptureMachine> { | 216 public base::SupportsWeakPtr<WebContentsCaptureMachine> { |
| 207 public: | 217 public: |
| 208 WebContentsCaptureMachine(int render_process_id, int render_view_id); | 218 WebContentsCaptureMachine(int render_process_id, int render_view_id); |
| 209 virtual ~WebContentsCaptureMachine(); | 219 virtual ~WebContentsCaptureMachine(); |
| 210 | 220 |
| 211 // VideoCaptureMachine overrides. | 221 // VideoCaptureMachine overrides. |
| 212 virtual bool Start( | 222 virtual bool Start( |
| 213 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE; | 223 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE; |
| 214 virtual void Stop() OVERRIDE; | 224 virtual void Stop(const base::Closure& callback) OVERRIDE; |
| 215 | 225 |
| 216 // Starts a copy from the backing store or the composited surface. Must be run | 226 // Starts a copy from the backing store or the composited surface. Must be run |
| 217 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation | 227 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation |
| 218 // completes. The copy will occur to |target|. | 228 // completes. The copy will occur to |target|. |
| 219 // | 229 // |
| 220 // This may be used as a ContentCaptureSubscription::CaptureCallback. | 230 // This may be used as a ContentCaptureSubscription::CaptureCallback. |
| 221 void Capture(const base::TimeTicks& start_time, | 231 void Capture(const base::TimeTicks& start_time, |
| 222 const scoped_refptr<media::VideoFrame>& target, | 232 const scoped_refptr<media::VideoFrame>& target, |
| 223 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& | 233 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
| 224 deliver_frame_cb); | 234 deliver_frame_cb); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 278 // after any change to the WebContents that affects the RenderWidgetHost or | 288 // after any change to the WebContents that affects the RenderWidgetHost or |
| 279 // attached views. | 289 // attached views. |
| 280 void RenewFrameSubscription(); | 290 void RenewFrameSubscription(); |
| 281 | 291 |
| 282 // Parameters saved in constructor. | 292 // Parameters saved in constructor. |
| 283 const int initial_render_process_id_; | 293 const int initial_render_process_id_; |
| 284 const int initial_render_view_id_; | 294 const int initial_render_view_id_; |
| 285 | 295 |
| 286 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will | 296 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will |
| 287 // occur. Only used when this activity cannot be done on the GPU. | 297 // occur. Only used when this activity cannot be done on the GPU. |
| 288 base::Thread render_thread_; | 298 scoped_ptr<base::Thread> render_thread_; |
| 289 | 299 |
| 290 // Makes all the decisions about which frames to copy, and how. | 300 // Makes all the decisions about which frames to copy, and how. |
| 291 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; | 301 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; |
| 292 | 302 |
| 293 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE | 303 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE |
| 294 // otherwise. | 304 // otherwise. |
| 295 int fullscreen_widget_id_; | 305 int fullscreen_widget_id_; |
| 296 | 306 |
| 297 // Last known RenderView size. | 307 // Last known RenderView size. |
| 298 gfx::Size last_view_size_; | 308 gfx::Size last_view_size_; |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 544 count_frames_rendered_ = 0; | 554 count_frames_rendered_ = 0; |
| 545 last_frame_number_ = frame_number; | 555 last_frame_number_ = frame_number; |
| 546 } | 556 } |
| 547 } | 557 } |
| 548 } | 558 } |
| 549 | 559 |
| 550 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id, | 560 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id, |
| 551 int render_view_id) | 561 int render_view_id) |
| 552 : initial_render_process_id_(render_process_id), | 562 : initial_render_process_id_(render_process_id), |
| 553 initial_render_view_id_(render_view_id), | 563 initial_render_view_id_(render_view_id), |
| 554 render_thread_("WebContentsVideo_RenderThread"), | 564 render_thread_(new base::Thread("WebContentsVideo_RenderThread")), |
| 555 fullscreen_widget_id_(MSG_ROUTING_NONE) {} | 565 fullscreen_widget_id_(MSG_ROUTING_NONE) {} |
| 556 | 566 |
| 557 WebContentsCaptureMachine::~WebContentsCaptureMachine() {} | 567 WebContentsCaptureMachine::~WebContentsCaptureMachine() { |
| 568 BrowserThread::PostBlockingPoolTask( | |
| 569 FROM_HERE, | |
| 570 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), | |
| 571 base::Bind(&base::DoNothing))); | |
| 572 } | |
| 558 | 573 |
| 559 bool WebContentsCaptureMachine::Start( | 574 bool WebContentsCaptureMachine::Start( |
| 560 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) { | 575 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) { |
| 561 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 562 DCHECK(!started_); | 577 DCHECK(!started_); |
| 563 | 578 |
| 564 DCHECK(oracle_proxy.get()); | 579 DCHECK(oracle_proxy.get()); |
| 565 oracle_proxy_ = oracle_proxy; | 580 oracle_proxy_ = oracle_proxy; |
| 566 | 581 |
| 567 if (!render_thread_.Start()) { | 582 if (!render_thread_->Start()) { |
| 568 DVLOG(1) << "Failed to spawn render thread."; | 583 DVLOG(1) << "Failed to spawn render thread."; |
| 569 return false; | 584 return false; |
| 570 } | 585 } |
| 571 | 586 |
| 572 if (!StartObservingWebContents()) | 587 if (!StartObservingWebContents()) |
| 573 return false; | 588 return false; |
| 574 | 589 |
| 575 started_ = true; | 590 started_ = true; |
| 576 return true; | 591 return true; |
| 577 } | 592 } |
| 578 | 593 |
| 579 void WebContentsCaptureMachine::Stop() { | 594 void WebContentsCaptureMachine::Stop(const base::Closure& callback) { |
| 580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 595 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 581 subscription_.reset(); | 596 subscription_.reset(); |
| 582 if (web_contents()) { | 597 if (web_contents()) { |
| 583 web_contents()->DecrementCapturerCount(); | 598 web_contents()->DecrementCapturerCount(); |
| 584 Observe(NULL); | 599 Observe(NULL); |
| 585 } | 600 } |
| 586 render_thread_.Stop(); | 601 |
| 602 // The render thread cannot be stopped on the UI thread, so post a message | |
| 603 // to the thread pool used for blocking operations. | |
| 604 BrowserThread::PostBlockingPoolTask( | |
| 605 FROM_HERE, | |
| 606 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_), | |
| 607 callback)); | |
| 608 | |
| 609 render_thread_.reset(new base::Thread(kRenderThreadName)); | |
|
miu
2014/01/11 03:48:36
Seems strange to create a new thread as part of th
imcheng
2014/01/13 20:23:24
Done.
| |
| 610 | |
| 587 started_ = false; | 611 started_ = false; |
| 588 } | 612 } |
| 589 | 613 |
| 590 void WebContentsCaptureMachine::Capture( | 614 void WebContentsCaptureMachine::Capture( |
| 591 const base::TimeTicks& start_time, | 615 const base::TimeTicks& start_time, |
| 592 const scoped_refptr<media::VideoFrame>& target, | 616 const scoped_refptr<media::VideoFrame>& target, |
| 593 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& | 617 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
| 594 deliver_frame_cb) { | 618 deliver_frame_cb) { |
| 595 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 619 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 596 | 620 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 699 void WebContentsCaptureMachine::DidCopyFromBackingStore( | 723 void WebContentsCaptureMachine::DidCopyFromBackingStore( |
| 700 const base::TimeTicks& start_time, | 724 const base::TimeTicks& start_time, |
| 701 const scoped_refptr<media::VideoFrame>& target, | 725 const scoped_refptr<media::VideoFrame>& target, |
| 702 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& | 726 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
| 703 deliver_frame_cb, | 727 deliver_frame_cb, |
| 704 bool success, | 728 bool success, |
| 705 const SkBitmap& bitmap) { | 729 const SkBitmap& bitmap) { |
| 706 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 730 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 707 | 731 |
| 708 base::TimeTicks now = base::TimeTicks::Now(); | 732 base::TimeTicks now = base::TimeTicks::Now(); |
| 709 if (success) { | 733 if (success && render_thread_->message_loop_proxy()) { |
| 710 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); | 734 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); |
| 711 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(), | 735 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(), |
| 712 "Render"); | 736 "Render"); |
| 713 render_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( | 737 render_thread_->message_loop_proxy()->PostTask(FROM_HERE, base::Bind( |
| 714 &RenderVideoFrame, bitmap, target, | 738 &RenderVideoFrame, bitmap, target, |
| 715 base::Bind(deliver_frame_cb, start_time))); | 739 base::Bind(deliver_frame_cb, start_time))); |
| 716 } else { | 740 } else { |
| 717 // Capture can fail due to transient issues, so just skip this frame. | 741 // Capture can fail due to transient issues, so just skip this frame. |
| 718 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; | 742 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; |
| 719 deliver_frame_cb.Run(start_time, false); | 743 deliver_frame_cb.Run(start_time, false); |
| 720 } | 744 } |
| 721 } | 745 } |
| 722 | 746 |
| 723 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( | 747 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 781 scoped_ptr<Client> client) { | 805 scoped_ptr<Client> client) { |
| 782 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); | 806 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); |
| 783 impl_->AllocateAndStart(params, client.Pass()); | 807 impl_->AllocateAndStart(params, client.Pass()); |
| 784 } | 808 } |
| 785 | 809 |
| 786 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { | 810 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { |
| 787 impl_->StopAndDeAllocate(); | 811 impl_->StopAndDeAllocate(); |
| 788 } | 812 } |
| 789 | 813 |
| 790 } // namespace content | 814 } // namespace content |
| OLD | NEW |