Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(554)

Side by Side Diff: content/browser/renderer_host/media/web_contents_video_capture_device.cc

Issue 12179007: While screencasting a tab, do not disable rendering updates while hidden. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Finer-grained increment/decrement, per sky@'s comments. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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. Therefore, the process of capturing has been split up into a 7 // performance. Therefore, the process of capturing has been split up into a
8 // pipeline of three stages. Each stage executes on its own thread: 8 // pipeline of three stages. Each stage executes on its own thread:
9 // 9 //
10 // 1. Capture: A bitmap is snapshotted/copied from the RenderView's backing 10 // 1. Capture: A bitmap is snapshotted/copied from the RenderView's backing
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
145 OK, 145 OK,
146 TRANSIENT_ERROR, 146 TRANSIENT_ERROR,
147 NO_SOURCE, 147 NO_SOURCE,
148 }; 148 };
149 typedef base::Callback<void(Result result, 149 typedef base::Callback<void(Result result,
150 scoped_ptr<skia::PlatformBitmap> capture, 150 scoped_ptr<skia::PlatformBitmap> capture,
151 const base::Time& capture_time)> DoneCB; 151 const base::Time& capture_time)> DoneCB;
152 152
153 BackingStoreCopier(int render_process_id, int render_view_id); 153 BackingStoreCopier(int render_process_id, int render_view_id);
154 154
155 virtual ~BackingStoreCopier();
156
155 // If non-NULL, use the given |override| to access the backing store. 157 // If non-NULL, use the given |override| to access the backing store.
156 // This is used for unit testing. 158 // This is used for unit testing.
157 void SetRenderWidgetHostForTesting(RenderWidgetHost* override); 159 void SetRenderWidgetHostForTesting(RenderWidgetHost* override);
158 160
159 // Starts the copy from the backing store. Must be run on the UI 161 // Starts the copy from the backing store. Must be run on the UI
160 // BrowserThread. |done_cb| is invoked with result status. When successful 162 // BrowserThread. |done_cb| is invoked with result status. When successful
161 // (OK), the bitmap of the capture is transferred to the callback along with 163 // (OK), the bitmap of the capture is transferred to the callback along with
162 // the timestamp at which the capture was completed. 164 // the timestamp at which the capture was completed.
163 void StartCopy(int frame_number, int desired_width, int desired_height, 165 void StartCopy(int frame_number, int desired_width, int desired_height,
164 const DoneCB& done_cb); 166 const DoneCB& done_cb);
165 167
168 // Stops observing an existing WebContents instance, if any. This must be
169 // called before BackingStoreCopier is destroyed. Must be run on the UI
170 // BrowserThread.
171 void StopObservingWebContents();
172
166 virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE { 173 virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE {
167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
168 fullscreen_widget_id_ = routing_id; 175 fullscreen_widget_id_ = routing_id;
169 } 176 }
170 177
171 virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE { 178 virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE {
172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 179 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
173 DCHECK_EQ(fullscreen_widget_id_, routing_id); 180 DCHECK_EQ(fullscreen_widget_id_, routing_id);
174 fullscreen_widget_id_ = MSG_ROUTING_NONE; 181 fullscreen_widget_id_ = MSG_ROUTING_NONE;
175 } 182 }
176 183
177 private: 184 private:
185 virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
186
178 void LookUpAndObserveWebContents(); 187 void LookUpAndObserveWebContents();
179 188
180 void CopyFromBackingStoreComplete(int frame_number, 189 void CopyFromBackingStoreComplete(int frame_number,
181 scoped_ptr<skia::PlatformBitmap> capture, 190 scoped_ptr<skia::PlatformBitmap> capture,
182 const DoneCB& done_cb, bool success); 191 const DoneCB& done_cb, bool success);
183 192
184 // The "starting point" to find the capture source. 193 // The "starting point" to find the capture source.
185 const int render_process_id_; 194 const int render_process_id_;
186 const int render_view_id_; 195 const int render_view_id_;
187 196
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 int last_frame_number_; 292 int last_frame_number_;
284 293
285 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliverer); 294 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliverer);
286 }; 295 };
287 296
288 BackingStoreCopier::BackingStoreCopier(int render_process_id, 297 BackingStoreCopier::BackingStoreCopier(int render_process_id,
289 int render_view_id) 298 int render_view_id)
290 : render_process_id_(render_process_id), render_view_id_(render_view_id), 299 : render_process_id_(render_process_id), render_view_id_(render_view_id),
291 fullscreen_widget_id_(MSG_ROUTING_NONE), rwh_for_testing_(NULL) {} 300 fullscreen_widget_id_(MSG_ROUTING_NONE), rwh_for_testing_(NULL) {}
292 301
302 BackingStoreCopier::~BackingStoreCopier() {
303 DCHECK(!web_contents());
304 }
305
306 void BackingStoreCopier::StopObservingWebContents() {
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
308
309 if (web_contents()) {
310 web_contents()->DecrementCapturerCount();
311 Observe(NULL);
312 }
313 }
314
315 void BackingStoreCopier::WebContentsDestroyed(WebContents* web_contents) {
316 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
317
318 web_contents->DecrementCapturerCount();
319 }
320
293 void BackingStoreCopier::LookUpAndObserveWebContents() { 321 void BackingStoreCopier::LookUpAndObserveWebContents() {
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 322 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
295 323
296 // Look-up the RenderViewHost and, from that, the WebContents that wraps it. 324 // Look-up the RenderViewHost and, from that, the WebContents that wraps it.
297 // If successful, begin observing the WebContents instance. If unsuccessful, 325 // If successful, begin observing the WebContents instance. If unsuccessful,
298 // stop observing and post an error. 326 // stop observing and post an error.
299 // 327 //
300 // Why this can be unsuccessful: The request for mirroring originates in a 328 // Why this can be unsuccessful: The request for mirroring originates in a
301 // render process, and this request is based on the current RenderView 329 // render process, and this request is based on the current RenderView
302 // associated with a tab. However, by the time we get up-and-running here, 330 // associated with a tab. However, by the time we get up-and-running here,
303 // there have been multiple back-and-forth IPCs between processes, as well as 331 // there have been multiple back-and-forth IPCs between processes, as well as
304 // a bit of indirection across threads. It's easily possible that, in the 332 // a bit of indirection across threads. It's easily possible that, in the
305 // meantime, the original RenderView may have gone away. 333 // meantime, the original RenderView may have gone away.
306 RenderViewHost* const rvh = 334 RenderViewHost* const rvh =
307 RenderViewHost::FromID(render_process_id_, render_view_id_); 335 RenderViewHost::FromID(render_process_id_, render_view_id_);
308 DVLOG_IF(1, !rvh) << "RenderViewHost::FromID(" 336 DVLOG_IF(1, !rvh) << "RenderViewHost::FromID("
309 << render_process_id_ << ", " << render_view_id_ 337 << render_process_id_ << ", " << render_view_id_
310 << ") returned NULL."; 338 << ") returned NULL.";
311 Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL); 339 Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL);
312 DVLOG_IF(1, !web_contents()) 340 if (web_contents())
313 << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL."; 341 web_contents()->IncrementCapturerCount();
342 else
343 DVLOG(1) << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL.";
314 344
315 if (fullscreen_widget_id_ == MSG_ROUTING_NONE && web_contents()) { 345 if (fullscreen_widget_id_ == MSG_ROUTING_NONE && web_contents()) {
316 fullscreen_widget_id_ = static_cast<WebContentsImpl*>(web_contents())-> 346 fullscreen_widget_id_ = static_cast<WebContentsImpl*>(web_contents())->
317 GetFullscreenWidgetRoutingID(); 347 GetFullscreenWidgetRoutingID();
318 } 348 }
319 } 349 }
320 350
321 void BackingStoreCopier::SetRenderWidgetHostForTesting( 351 void BackingStoreCopier::SetRenderWidgetHostForTesting(
322 RenderWidgetHost* override) { 352 RenderWidgetHost* override) {
323 rwh_for_testing_ = override; 353 rwh_for_testing_ = override;
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
714 void SnapshotComplete(int frame_number, 744 void SnapshotComplete(int frame_number,
715 const base::Time& start_time, 745 const base::Time& start_time,
716 BackingStoreCopier::Result result, 746 BackingStoreCopier::Result result,
717 scoped_ptr<skia::PlatformBitmap> capture, 747 scoped_ptr<skia::PlatformBitmap> capture,
718 const base::Time& capture_time); 748 const base::Time& capture_time);
719 void RenderComplete(int frame_number, 749 void RenderComplete(int frame_number,
720 const base::Time& capture_time, 750 const base::Time& capture_time,
721 const SkBitmap* frame_buffer); 751 const SkBitmap* frame_buffer);
722 void DeliverComplete(const SkBitmap* frame_buffer); 752 void DeliverComplete(const SkBitmap* frame_buffer);
723 753
754 void DoShutdownTasksOnUIThread();
755
724 // Specialized RefCounted traits for CaptureMachine, so that operator delete 756 // Specialized RefCounted traits for CaptureMachine, so that operator delete
725 // is called from an "outside" thread. See comments for "traits" in 757 // is called from an "outside" thread. See comments for "traits" in
726 // base/memory/ref_counted.h. 758 // base/memory/ref_counted.h.
727 static void Destruct(const CaptureMachine* x); 759 static void Destruct(const CaptureMachine* x);
728 static void DeleteFromOutsideThread(const CaptureMachine* x); 760 static void DeleteFromOutsideThread(const CaptureMachine* x);
729 761
730 SynchronizedConsumer consumer_; // Recipient of frames. 762 SynchronizedConsumer consumer_; // Recipient of frames.
731 763
732 // Used to ensure state machine transitions occur synchronously, and that 764 // Used to ensure state machine transitions occur synchronously, and that
733 // capturing executes at regular intervals. 765 // capturing executes at regular intervals.
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
840 } 872 }
841 873
842 void CaptureMachine::DeAllocate() { 874 void CaptureMachine::DeAllocate() {
843 ENSURE_INVOKED_ON_THREAD(manager_thread_, 875 ENSURE_INVOKED_ON_THREAD(manager_thread_,
844 &CaptureMachine::DeAllocate, this); 876 &CaptureMachine::DeAllocate, this);
845 877
846 if (state_ == kCapturing) { 878 if (state_ == kCapturing) {
847 Stop(); 879 Stop();
848 } 880 }
849 if (state_ == kAllocated) { 881 if (state_ == kAllocated) {
882 BrowserThread::PostTask(
883 BrowserThread::UI, FROM_HERE,
884 base::Bind(&CaptureMachine::DoShutdownTasksOnUIThread, this));
885
850 TransitionStateTo(kIdle); 886 TransitionStateTo(kIdle);
851 } 887 }
852 } 888 }
853 889
854 CaptureMachine::~CaptureMachine() { 890 CaptureMachine::~CaptureMachine() {
855 DVLOG(1) << "CaptureMachine@" << this << " destroying."; 891 DVLOG(1) << "CaptureMachine@" << this << " destroying.";
856 state_ = kDestroyed; 892 state_ = kDestroyed;
857 // Note: Implicit destructors will be called after this, which will block the 893 // Note: Implicit destructors will be called after this, which will block the
858 // current thread while joining on the other threads. However, this should be 894 // current thread while joining on the other threads. However, this should be
859 // instantaneous since the other threads' task queues *must* be empty at this 895 // instantaneous since the other threads' task queues *must* be empty at this
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1020 DCHECK(frame_buffer); 1056 DCHECK(frame_buffer);
1021 deliverer_.Deliver( 1057 deliverer_.Deliver(
1022 frame_number, *frame_buffer, capture_time, 1058 frame_number, *frame_buffer, capture_time,
1023 base::Bind(&CaptureMachine::DeliverComplete, this, frame_buffer)); 1059 base::Bind(&CaptureMachine::DeliverComplete, this, frame_buffer));
1024 } 1060 }
1025 1061
1026 void CaptureMachine::DeliverComplete(const SkBitmap* frame_buffer) { 1062 void CaptureMachine::DeliverComplete(const SkBitmap* frame_buffer) {
1027 renderer_.Release(frame_buffer); 1063 renderer_.Release(frame_buffer);
1028 } 1064 }
1029 1065
1066 void CaptureMachine::DoShutdownTasksOnUIThread() {
1067 copier_.StopObservingWebContents();
1068 }
1069
1030 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( 1070 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
1031 const media::VideoCaptureDevice::Name& name, 1071 const media::VideoCaptureDevice::Name& name,
1032 int render_process_id, int render_view_id) 1072 int render_process_id, int render_view_id)
1033 : device_name_(name), 1073 : device_name_(name),
1034 capturer_(new CaptureMachine(render_process_id, render_view_id)) {} 1074 capturer_(new CaptureMachine(render_process_id, render_view_id)) {}
1035 1075
1036 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( 1076 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice(
1037 RenderWidgetHost* test_source, const base::Closure& destroy_cb) 1077 RenderWidgetHost* test_source, const base::Closure& destroy_cb)
1038 : capturer_(new CaptureMachine(-1, -1)) { 1078 : capturer_(new CaptureMachine(-1, -1)) {
1039 device_name_.device_name = "WebContentsForTesting"; 1079 device_name_.device_name = "WebContentsForTesting";
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1095 capturer_->SetConsumer(NULL); 1135 capturer_->SetConsumer(NULL);
1096 capturer_->DeAllocate(); 1136 capturer_->DeAllocate();
1097 } 1137 }
1098 1138
1099 const media::VideoCaptureDevice::Name& 1139 const media::VideoCaptureDevice::Name&
1100 WebContentsVideoCaptureDevice::device_name() { 1140 WebContentsVideoCaptureDevice::device_name() {
1101 return device_name_; 1141 return device_name_;
1102 } 1142 }
1103 1143
1104 } // namespace content 1144 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698