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. 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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 #include "base/callback_forward.h" | 49 #include "base/callback_forward.h" |
50 #include "base/debug/trace_event.h" | 50 #include "base/debug/trace_event.h" |
51 #include "base/logging.h" | 51 #include "base/logging.h" |
52 #include "base/memory/scoped_ptr.h" | 52 #include "base/memory/scoped_ptr.h" |
53 #include "base/metrics/histogram.h" | 53 #include "base/metrics/histogram.h" |
54 #include "base/stringprintf.h" | 54 #include "base/stringprintf.h" |
55 #include "base/synchronization/lock.h" | 55 #include "base/synchronization/lock.h" |
56 #include "base/threading/thread.h" | 56 #include "base/threading/thread.h" |
57 #include "base/time.h" | 57 #include "base/time.h" |
58 #include "content/browser/renderer_host/media/web_contents_capture_util.h" | 58 #include "content/browser/renderer_host/media/web_contents_capture_util.h" |
| 59 #include "content/browser/web_contents/web_contents_impl.h" |
59 #include "content/public/browser/browser_thread.h" | 60 #include "content/public/browser/browser_thread.h" |
60 #include "content/public/browser/render_process_host.h" | 61 #include "content/public/browser/render_process_host.h" |
61 #include "content/public/browser/render_view_host.h" | 62 #include "content/public/browser/render_view_host.h" |
62 #include "content/public/browser/render_widget_host_view.h" | 63 #include "content/public/browser/render_widget_host_view.h" |
63 #include "content/public/browser/web_contents.h" | 64 #include "content/public/browser/web_contents.h" |
64 #include "content/public/browser/web_contents_observer.h" | 65 #include "content/public/browser/web_contents_observer.h" |
65 #include "media/base/bind_to_loop.h" | 66 #include "media/base/bind_to_loop.h" |
66 #include "media/video/capture/video_capture_types.h" | 67 #include "media/video/capture/video_capture_types.h" |
67 #include "skia/ext/image_operations.h" | 68 #include "skia/ext/image_operations.h" |
68 #include "skia/ext/platform_canvas.h" | 69 #include "skia/ext/platform_canvas.h" |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 // This is used for unit testing. | 156 // This is used for unit testing. |
156 void SetRenderWidgetHostForTesting(RenderWidgetHost* override); | 157 void SetRenderWidgetHostForTesting(RenderWidgetHost* override); |
157 | 158 |
158 // Starts the copy from the backing store. Must be run on the UI | 159 // Starts the copy from the backing store. Must be run on the UI |
159 // BrowserThread. |done_cb| is invoked with result status. When successful | 160 // BrowserThread. |done_cb| is invoked with result status. When successful |
160 // (OK), the bitmap of the capture is transferred to the callback along with | 161 // (OK), the bitmap of the capture is transferred to the callback along with |
161 // the timestamp at which the capture was completed. | 162 // the timestamp at which the capture was completed. |
162 void StartCopy(int frame_number, int desired_width, int desired_height, | 163 void StartCopy(int frame_number, int desired_width, int desired_height, |
163 const DoneCB& done_cb); | 164 const DoneCB& done_cb); |
164 | 165 |
| 166 virtual void DidShowFullscreenWidget(int routing_id) OVERRIDE { |
| 167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 168 fullscreen_widget_id_ = routing_id; |
| 169 } |
| 170 |
| 171 virtual void DidDestroyFullscreenWidget(int routing_id) OVERRIDE { |
| 172 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 173 DCHECK_EQ(fullscreen_widget_id_, routing_id); |
| 174 fullscreen_widget_id_ = MSG_ROUTING_NONE; |
| 175 } |
| 176 |
165 private: | 177 private: |
166 void LookUpAndObserveWebContents(); | 178 void LookUpAndObserveWebContents(); |
167 | 179 |
168 void CopyFromBackingStoreComplete(int frame_number, | 180 void CopyFromBackingStoreComplete(int frame_number, |
169 scoped_ptr<skia::PlatformBitmap> capture, | 181 scoped_ptr<skia::PlatformBitmap> capture, |
170 const DoneCB& done_cb, bool success); | 182 const DoneCB& done_cb, bool success); |
171 | 183 |
172 // The "starting point" to find the capture source. | 184 // The "starting point" to find the capture source. |
173 const int render_process_id_; | 185 const int render_process_id_; |
174 const int render_view_id_; | 186 const int render_view_id_; |
175 | 187 |
| 188 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE |
| 189 // otherwise. |
| 190 int fullscreen_widget_id_; |
| 191 |
176 // Last known RenderView size. | 192 // Last known RenderView size. |
177 gfx::Size last_view_size_; | 193 gfx::Size last_view_size_; |
178 | 194 |
179 // If the following is NULL (normal behavior), the implementation should | 195 // If the following is NULL (normal behavior), the implementation should |
180 // access RenderWidgetHost via web_contents(). | 196 // access RenderWidgetHost via web_contents(). |
181 RenderWidgetHost* rwh_for_testing_; | 197 RenderWidgetHost* rwh_for_testing_; |
182 | 198 |
183 DISALLOW_COPY_AND_ASSIGN(BackingStoreCopier); | 199 DISALLOW_COPY_AND_ASSIGN(BackingStoreCopier); |
184 }; | 200 }; |
185 | 201 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 base::Time last_frame_rate_log_time_; | 281 base::Time last_frame_rate_log_time_; |
266 int count_frames_rendered_; | 282 int count_frames_rendered_; |
267 int last_frame_number_; | 283 int last_frame_number_; |
268 | 284 |
269 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliverer); | 285 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliverer); |
270 }; | 286 }; |
271 | 287 |
272 BackingStoreCopier::BackingStoreCopier(int render_process_id, | 288 BackingStoreCopier::BackingStoreCopier(int render_process_id, |
273 int render_view_id) | 289 int render_view_id) |
274 : render_process_id_(render_process_id), render_view_id_(render_view_id), | 290 : render_process_id_(render_process_id), render_view_id_(render_view_id), |
275 rwh_for_testing_(NULL) {} | 291 fullscreen_widget_id_(MSG_ROUTING_NONE), rwh_for_testing_(NULL) {} |
276 | 292 |
277 void BackingStoreCopier::LookUpAndObserveWebContents() { | 293 void BackingStoreCopier::LookUpAndObserveWebContents() { |
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
279 | 295 |
280 // Look-up the RenderViewHost and, from that, the WebContents that wraps it. | 296 // Look-up the RenderViewHost and, from that, the WebContents that wraps it. |
281 // If successful, begin observing the WebContents instance. If unsuccessful, | 297 // If successful, begin observing the WebContents instance. If unsuccessful, |
282 // stop observing and post an error. | 298 // stop observing and post an error. |
283 // | 299 // |
284 // Why this can be unsuccessful: The request for mirroring originates in a | 300 // Why this can be unsuccessful: The request for mirroring originates in a |
285 // render process, and this request is based on the current RenderView | 301 // render process, and this request is based on the current RenderView |
286 // associated with a tab. However, by the time we get up-and-running here, | 302 // associated with a tab. However, by the time we get up-and-running here, |
287 // there have been multiple back-and-forth IPCs between processes, as well as | 303 // there have been multiple back-and-forth IPCs between processes, as well as |
288 // a bit of indirection across threads. It's easily possible that, in the | 304 // a bit of indirection across threads. It's easily possible that, in the |
289 // meantime, the original RenderView may have gone away. | 305 // meantime, the original RenderView may have gone away. |
290 RenderViewHost* const rvh = | 306 RenderViewHost* const rvh = |
291 RenderViewHost::FromID(render_process_id_, render_view_id_); | 307 RenderViewHost::FromID(render_process_id_, render_view_id_); |
292 DVLOG_IF(1, !rvh) << "RenderViewHost::FromID(" | 308 DVLOG_IF(1, !rvh) << "RenderViewHost::FromID(" |
293 << render_process_id_ << ", " << render_view_id_ | 309 << render_process_id_ << ", " << render_view_id_ |
294 << ") returned NULL."; | 310 << ") returned NULL."; |
295 Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL); | 311 Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL); |
296 DVLOG_IF(1, !web_contents()) | 312 DVLOG_IF(1, !web_contents()) |
297 << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL."; | 313 << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL."; |
| 314 |
| 315 if (fullscreen_widget_id_ == MSG_ROUTING_NONE && web_contents()) { |
| 316 fullscreen_widget_id_ = static_cast<WebContentsImpl*>(web_contents())-> |
| 317 GetFullscreenWidgetRoutingID(); |
| 318 } |
298 } | 319 } |
299 | 320 |
300 void BackingStoreCopier::SetRenderWidgetHostForTesting( | 321 void BackingStoreCopier::SetRenderWidgetHostForTesting( |
301 RenderWidgetHost* override) { | 322 RenderWidgetHost* override) { |
302 rwh_for_testing_ = override; | 323 rwh_for_testing_ = override; |
303 } | 324 } |
304 | 325 |
305 void BackingStoreCopier::StartCopy(int frame_number, | 326 void BackingStoreCopier::StartCopy(int frame_number, |
306 int desired_width, int desired_height, | 327 int desired_width, int desired_height, |
307 const DoneCB& done_cb) { | 328 const DoneCB& done_cb) { |
308 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 329 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
309 | 330 |
310 TRACE_EVENT_ASYNC_BEGIN1("mirroring", "Capture", this, | 331 TRACE_EVENT_ASYNC_BEGIN1("mirroring", "Capture", this, |
311 "frame_number", frame_number); | 332 "frame_number", frame_number); |
312 | 333 |
313 RenderWidgetHost* rwh; | 334 RenderWidgetHost* rwh; |
314 if (rwh_for_testing_) { | 335 if (rwh_for_testing_) { |
315 rwh = rwh_for_testing_; | 336 rwh = rwh_for_testing_; |
316 } else { | 337 } else { |
317 if (!web_contents()) { // No source yet. | 338 if (!web_contents()) { // No source yet. |
318 LookUpAndObserveWebContents(); | 339 LookUpAndObserveWebContents(); |
319 if (!web_contents()) { // No source ever. | 340 if (!web_contents()) { // No source ever. |
320 done_cb.Run(NO_SOURCE, | 341 done_cb.Run(NO_SOURCE, |
321 scoped_ptr<skia::PlatformBitmap>(NULL), base::Time()); | 342 scoped_ptr<skia::PlatformBitmap>(NULL), base::Time()); |
322 return; | 343 return; |
323 } | 344 } |
324 } | 345 } |
325 rwh = web_contents()->GetRenderViewHost(); | 346 |
| 347 if (fullscreen_widget_id_ != MSG_ROUTING_NONE) { |
| 348 RenderProcessHost* process = web_contents()->GetRenderProcessHost(); |
| 349 rwh = process ? process->GetRenderWidgetHostByID(fullscreen_widget_id_) |
| 350 : NULL; |
| 351 } else { |
| 352 rwh = web_contents()->GetRenderViewHost(); |
| 353 } |
| 354 |
326 if (!rwh) { | 355 if (!rwh) { |
327 // Transient failure state (e.g., a RenderView is being replaced). | 356 // Transient failure state (e.g., a RenderView is being replaced). |
328 done_cb.Run(TRANSIENT_ERROR, | 357 done_cb.Run(TRANSIENT_ERROR, |
329 scoped_ptr<skia::PlatformBitmap>(NULL), base::Time()); | 358 scoped_ptr<skia::PlatformBitmap>(NULL), base::Time()); |
330 return; | 359 return; |
331 } | 360 } |
332 } | 361 } |
333 | 362 |
334 gfx::Size fitted_size; | 363 gfx::Size fitted_size; |
335 if (RenderWidgetHostView* const view = rwh->GetView()) { | 364 if (RenderWidgetHostView* const view = rwh->GetView()) { |
(...skipping 730 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1066 capturer_->SetConsumer(NULL); | 1095 capturer_->SetConsumer(NULL); |
1067 capturer_->DeAllocate(); | 1096 capturer_->DeAllocate(); |
1068 } | 1097 } |
1069 | 1098 |
1070 const media::VideoCaptureDevice::Name& | 1099 const media::VideoCaptureDevice::Name& |
1071 WebContentsVideoCaptureDevice::device_name() { | 1100 WebContentsVideoCaptureDevice::device_name() { |
1072 return device_name_; | 1101 return device_name_; |
1073 } | 1102 } |
1074 | 1103 |
1075 } // namespace content | 1104 } // namespace content |
OLD | NEW |