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 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 #include "content/public/browser/web_contents_observer.h" | 66 #include "content/public/browser/web_contents_observer.h" |
67 #include "media/base/bind_to_loop.h" | 67 #include "media/base/bind_to_loop.h" |
68 #include "media/base/video_frame.h" | 68 #include "media/base/video_frame.h" |
69 #include "media/video/capture/video_capture_types.h" | 69 #include "media/video/capture/video_capture_types.h" |
70 #include "skia/ext/image_operations.h" | 70 #include "skia/ext/image_operations.h" |
71 #include "third_party/skia/include/core/SkBitmap.h" | 71 #include "third_party/skia/include/core/SkBitmap.h" |
72 #include "third_party/skia/include/core/SkColor.h" | 72 #include "third_party/skia/include/core/SkColor.h" |
73 #include "ui/gfx/rect.h" | 73 #include "ui/gfx/rect.h" |
74 #include "ui/gfx/skia_util.h" | 74 #include "ui/gfx/skia_util.h" |
75 | 75 |
76 // Used to self-trampoline invocation of methods to the approprate thread. This | 76 // Used to self-trampoline invocation of methods to the appropriate thread. This |
77 // should be used sparingly, only when it's not clear which thread is invoking a | 77 // should be used sparingly, only when it's not clear which thread is invoking a |
78 // method. | 78 // method. |
79 #define ENSURE_INVOKED_ON_THREAD(thread, ...) { \ | 79 #define ENSURE_INVOKED_ON_THREAD(thread, ...) { \ |
80 DCHECK(thread.IsRunning()); \ | 80 DCHECK(thread.IsRunning()); \ |
81 if (MessageLoop::current() != thread.message_loop()) { \ | 81 if (MessageLoop::current() != thread.message_loop()) { \ |
82 thread.message_loop()->PostTask(FROM_HERE, base::Bind(__VA_ARGS__)); \ | 82 thread.message_loop()->PostTask(FROM_HERE, base::Bind(__VA_ARGS__)); \ |
83 return; \ | 83 return; \ |
84 } \ | 84 } \ |
85 } | 85 } |
86 | 86 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
139 } | 139 } |
140 | 140 |
141 // Keeps track of the RenderView to be sourced, and executes copying of the | 141 // Keeps track of the RenderView to be sourced, and executes copying of the |
142 // backing store on the UI BrowserThread. | 142 // backing store on the UI BrowserThread. |
143 class BackingStoreCopier : public WebContentsObserver { | 143 class BackingStoreCopier : public WebContentsObserver { |
144 public: | 144 public: |
145 BackingStoreCopier(int render_process_id, int render_view_id); | 145 BackingStoreCopier(int render_process_id, int render_view_id); |
146 | 146 |
147 virtual ~BackingStoreCopier(); | 147 virtual ~BackingStoreCopier(); |
148 | 148 |
149 // If non-NULL, use the given |override| to access the backing store. | |
150 // This is used for unit testing. | |
151 void SetRenderWidgetHostForTesting(RenderWidgetHost* override); | |
152 | |
153 // Starts the copy from the backing store. Must be run on the UI | 149 // Starts the copy from the backing store. Must be run on the UI |
154 // BrowserThread. Resulting frame is conveyed back to |consumer|. | 150 // BrowserThread. Resulting frame is conveyed back to |consumer|. |
155 void StartCopy(const scoped_refptr<CaptureMachine>& consumer, | 151 void StartCopy(const scoped_refptr<CaptureMachine>& consumer, |
156 int frame_number, | 152 int frame_number, |
157 int desired_width, | 153 int desired_width, |
158 int desired_height); | 154 int desired_height); |
159 | 155 |
160 // Stops observing an existing WebContents instance, if any. This must be | 156 // Stops observing an existing WebContents instance, if any. This must be |
161 // called before BackingStoreCopier is destroyed. Must be run on the UI | 157 // called before BackingStoreCopier is destroyed. Must be run on the UI |
162 // BrowserThread. | 158 // BrowserThread. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
198 const int render_process_id_; | 194 const int render_process_id_; |
199 const int render_view_id_; | 195 const int render_view_id_; |
200 | 196 |
201 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE | 197 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE |
202 // otherwise. | 198 // otherwise. |
203 int fullscreen_widget_id_; | 199 int fullscreen_widget_id_; |
204 | 200 |
205 // Last known RenderView size. | 201 // Last known RenderView size. |
206 gfx::Size last_view_size_; | 202 gfx::Size last_view_size_; |
207 | 203 |
208 // If the following is NULL (normal behavior), the implementation should | |
209 // access RenderWidgetHost via web_contents(). | |
210 RenderWidgetHost* rwh_for_testing_; | |
211 | |
212 DISALLOW_COPY_AND_ASSIGN(BackingStoreCopier); | 204 DISALLOW_COPY_AND_ASSIGN(BackingStoreCopier); |
213 }; | 205 }; |
214 | 206 |
215 // Renders captures (from the backing store) into video frame buffers on a | 207 // Renders captures (from the backing store) into video frame buffers on a |
216 // separate thread. Manages use of internally-owned video frame buffers. | 208 // separate thread. Manages use of internally-owned video frame buffers. |
217 class VideoFrameRenderer { | 209 class VideoFrameRenderer { |
218 public: | 210 public: |
219 typedef base::Callback<void(const SkBitmap*)> DoneCB; | 211 typedef base::Callback<void(const SkBitmap*)> DoneCB; |
220 | 212 |
221 VideoFrameRenderer(); | 213 VideoFrameRenderer(); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
312 // deliver stage) whenever verbose logging is turned on. | 304 // deliver stage) whenever verbose logging is turned on. |
313 base::Time last_frame_rate_log_time_; | 305 base::Time last_frame_rate_log_time_; |
314 int count_frames_rendered_; | 306 int count_frames_rendered_; |
315 int last_frame_number_; | 307 int last_frame_number_; |
316 | 308 |
317 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliverer); | 309 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliverer); |
318 }; | 310 }; |
319 | 311 |
320 BackingStoreCopier::BackingStoreCopier(int render_process_id, | 312 BackingStoreCopier::BackingStoreCopier(int render_process_id, |
321 int render_view_id) | 313 int render_view_id) |
322 : render_process_id_(render_process_id), render_view_id_(render_view_id), | 314 : render_process_id_(render_process_id), |
323 fullscreen_widget_id_(MSG_ROUTING_NONE), rwh_for_testing_(NULL) {} | 315 render_view_id_(render_view_id), |
| 316 fullscreen_widget_id_(MSG_ROUTING_NONE) {} |
324 | 317 |
325 BackingStoreCopier::~BackingStoreCopier() { | 318 BackingStoreCopier::~BackingStoreCopier() { |
326 DCHECK(!web_contents()); | 319 DCHECK(!web_contents()); |
327 } | 320 } |
328 | 321 |
329 void BackingStoreCopier::StopObservingWebContents() { | 322 void BackingStoreCopier::StopObservingWebContents() { |
330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 323 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
331 | 324 |
332 if (web_contents()) { | 325 if (web_contents()) { |
333 web_contents()->DecrementCapturerCount(); | 326 web_contents()->DecrementCapturerCount(); |
(...skipping 28 matching lines...) Expand all Loading... |
362 Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL); | 355 Observe(rvh ? WebContents::FromRenderViewHost(rvh) : NULL); |
363 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents()); | 356 WebContentsImpl* contents = static_cast<WebContentsImpl*>(web_contents()); |
364 if (contents) { | 357 if (contents) { |
365 contents->IncrementCapturerCount(); | 358 contents->IncrementCapturerCount(); |
366 fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID(); | 359 fullscreen_widget_id_ = contents->GetFullscreenWidgetRoutingID(); |
367 } else { | 360 } else { |
368 DVLOG(1) << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL."; | 361 DVLOG(1) << "WebContents::FromRenderViewHost(" << rvh << ") returned NULL."; |
369 } | 362 } |
370 } | 363 } |
371 | 364 |
372 void BackingStoreCopier::SetRenderWidgetHostForTesting( | |
373 RenderWidgetHost* override) { | |
374 rwh_for_testing_ = override; | |
375 } | |
376 | |
377 VideoFrameRenderer::VideoFrameRenderer() | 365 VideoFrameRenderer::VideoFrameRenderer() |
378 : render_thread_("WebContentsVideo_RenderThread") { | 366 : render_thread_("WebContentsVideo_RenderThread") { |
379 output_[0].in_use = false; | 367 output_[0].in_use = false; |
380 output_[1].in_use = false; | 368 output_[1].in_use = false; |
381 render_thread_.Start(); | 369 render_thread_.Start(); |
382 } | 370 } |
383 | 371 |
384 void VideoFrameRenderer::Render(int frame_number, | 372 void VideoFrameRenderer::Render(int frame_number, |
385 const SkBitmap& capture, | 373 const SkBitmap& capture, |
386 int frame_width, int frame_height, | 374 int frame_width, int frame_height, |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
664 // top of this file). It times the start of successive captures and | 652 // top of this file). It times the start of successive captures and |
665 // facilitates the processing of each through the stages of the pipeline. | 653 // facilitates the processing of each through the stages of the pipeline. |
666 class CaptureMachine | 654 class CaptureMachine |
667 : public base::RefCountedThreadSafe<CaptureMachine, CaptureMachine> { | 655 : public base::RefCountedThreadSafe<CaptureMachine, CaptureMachine> { |
668 public: | 656 public: |
669 enum SnapshotError { | 657 enum SnapshotError { |
670 NO_SOURCE, | 658 NO_SOURCE, |
671 TRANSIENT_ERROR | 659 TRANSIENT_ERROR |
672 }; | 660 }; |
673 | 661 |
674 CaptureMachine(int render_process_id, int render_view_id); | 662 // |destroy_cb| will be invoked after CaptureMachine is fully destroyed, |
675 | 663 // to synchronize tear-down. |
676 // Sets the capture source to the given |override| for unit testing. | 664 CaptureMachine(int render_process_id, |
677 // Also, |destroy_cb| will be invoked after CaptureMachine is fully destroyed | 665 int render_view_id, |
678 // (to synchronize tear-down). | 666 const base::Closure& destroy_cb); |
679 void InitializeForTesting(RenderWidgetHost* override, | |
680 const base::Closure& destroy_cb); | |
681 | 667 |
682 // Synchronously sets/unsets the consumer. Pass |consumer| as NULL to remove | 668 // Synchronously sets/unsets the consumer. Pass |consumer| as NULL to remove |
683 // the reference to the consumer; then, once this method returns, | 669 // the reference to the consumer; then, once this method returns, |
684 // CaptureMachine will no longer invoke callbacks on the old consumer from any | 670 // CaptureMachine will no longer invoke callbacks on the old consumer from any |
685 // thread. | 671 // thread. |
686 void SetConsumer(media::VideoCaptureDevice::EventHandler* consumer); | 672 void SetConsumer(media::VideoCaptureDevice::EventHandler* consumer); |
687 | 673 |
688 // Asynchronous requests to change CaptureMachine state. | 674 // Asynchronous requests to change CaptureMachine state. |
689 void Allocate(int width, int height, int frame_rate); | 675 void Allocate(int width, int height, int frame_rate); |
690 void Start(); | 676 void Start(); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
771 // The three pipeline stages. | 757 // The three pipeline stages. |
772 BackingStoreCopier copier_; | 758 BackingStoreCopier copier_; |
773 VideoFrameRenderer renderer_; | 759 VideoFrameRenderer renderer_; |
774 VideoFrameDeliverer deliverer_; | 760 VideoFrameDeliverer deliverer_; |
775 | 761 |
776 base::Closure destroy_cb_; // Invoked once CaptureMachine is destroyed. | 762 base::Closure destroy_cb_; // Invoked once CaptureMachine is destroyed. |
777 | 763 |
778 DISALLOW_COPY_AND_ASSIGN(CaptureMachine); | 764 DISALLOW_COPY_AND_ASSIGN(CaptureMachine); |
779 }; | 765 }; |
780 | 766 |
781 CaptureMachine::CaptureMachine(int render_process_id, int render_view_id) | 767 CaptureMachine::CaptureMachine(int render_process_id, |
| 768 int render_view_id, |
| 769 const base::Closure& destroy_cb) |
782 : manager_thread_("WebContentsVideo_ManagerThread"), | 770 : manager_thread_("WebContentsVideo_ManagerThread"), |
783 state_(kIdle), | 771 state_(kIdle), |
784 is_snapshotting_(false), | 772 is_snapshotting_(false), |
785 num_renders_pending_(0), | 773 num_renders_pending_(0), |
786 copier_(render_process_id, render_view_id), | 774 copier_(render_process_id, render_view_id), |
787 deliverer_(&consumer_) { | 775 deliverer_(&consumer_), |
| 776 destroy_cb_(destroy_cb) { |
788 manager_thread_.Start(); | 777 manager_thread_.Start(); |
789 } | 778 } |
790 | 779 |
791 void CaptureMachine::InitializeForTesting(RenderWidgetHost* override, | |
792 const base::Closure& destroy_cb) { | |
793 copier_.SetRenderWidgetHostForTesting(override); | |
794 destroy_cb_ = destroy_cb; | |
795 } | |
796 | |
797 void CaptureMachine::SetConsumer( | 780 void CaptureMachine::SetConsumer( |
798 media::VideoCaptureDevice::EventHandler* consumer) { | 781 media::VideoCaptureDevice::EventHandler* consumer) { |
799 consumer_.SetConsumer(consumer); | 782 consumer_.SetConsumer(consumer); |
800 } | 783 } |
801 | 784 |
802 void CaptureMachine::Allocate(int width, int height, int frame_rate) { | 785 void CaptureMachine::Allocate(int width, int height, int frame_rate) { |
803 ENSURE_INVOKED_ON_THREAD(manager_thread_, | 786 ENSURE_INVOKED_ON_THREAD(manager_thread_, |
804 &CaptureMachine::Allocate, this, | 787 &CaptureMachine::Allocate, this, |
805 width, height, frame_rate); | 788 width, height, frame_rate); |
806 | 789 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
901 // another thread. | 884 // another thread. |
902 BrowserThread::PostBlockingPoolTask( | 885 BrowserThread::PostBlockingPoolTask( |
903 FROM_HERE, base::Bind(&DeleteFromOutsideThread, x)); | 886 FROM_HERE, base::Bind(&DeleteFromOutsideThread, x)); |
904 } | 887 } |
905 | 888 |
906 // static | 889 // static |
907 void CaptureMachine::DeleteFromOutsideThread(const CaptureMachine* x) { | 890 void CaptureMachine::DeleteFromOutsideThread(const CaptureMachine* x) { |
908 const base::Closure run_after_delete = x->destroy_cb_; | 891 const base::Closure run_after_delete = x->destroy_cb_; |
909 // Note: Thread joins are about to happen here (in ~CaptureThread()). | 892 // Note: Thread joins are about to happen here (in ~CaptureThread()). |
910 delete x; | 893 delete x; |
911 if (!run_after_delete.is_null()) { | 894 if (!run_after_delete.is_null()) |
912 run_after_delete.Run(); | 895 run_after_delete.Run(); |
913 } | |
914 } | 896 } |
915 | 897 |
916 void CaptureMachine::TransitionStateTo(State next_state) { | 898 void CaptureMachine::TransitionStateTo(State next_state) { |
917 DCHECK_EQ(manager_thread_.message_loop(), MessageLoop::current()); | 899 DCHECK_EQ(manager_thread_.message_loop(), MessageLoop::current()); |
918 | 900 |
919 #ifndef NDEBUG | 901 #ifndef NDEBUG |
920 static const char* kStateNames[] = { | 902 static const char* kStateNames[] = { |
921 "Idle", "Allocated", "Capturing", "Error", "Destroyed" | 903 "Idle", "Allocated", "Capturing", "Error", "Destroyed" |
922 }; | 904 }; |
923 DVLOG(1) << "State change: " << kStateNames[state_] | 905 DVLOG(1) << "State change: " << kStateNames[state_] |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1094 copier_.StopObservingWebContents(); | 1076 copier_.StopObservingWebContents(); |
1095 } | 1077 } |
1096 | 1078 |
1097 void BackingStoreCopier::StartCopy( | 1079 void BackingStoreCopier::StartCopy( |
1098 const scoped_refptr<CaptureMachine>& consumer, | 1080 const scoped_refptr<CaptureMachine>& consumer, |
1099 int frame_number, | 1081 int frame_number, |
1100 int desired_width, | 1082 int desired_width, |
1101 int desired_height) { | 1083 int desired_height) { |
1102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1084 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1103 | 1085 |
1104 RenderWidgetHost* rwh; | 1086 if (!web_contents()) { // No source yet. |
1105 if (rwh_for_testing_) { | 1087 LookUpAndObserveWebContents(); |
1106 rwh = rwh_for_testing_; | 1088 if (!web_contents()) { // No source ever. |
1107 } else { | 1089 consumer->OnSnapshotFailed(CaptureMachine::NO_SOURCE, frame_number); |
1108 if (!web_contents()) { // No source yet. | |
1109 LookUpAndObserveWebContents(); | |
1110 if (!web_contents()) { // No source ever. | |
1111 consumer->OnSnapshotFailed(CaptureMachine::NO_SOURCE, frame_number); | |
1112 return; | |
1113 } | |
1114 } | |
1115 | |
1116 if (fullscreen_widget_id_ != MSG_ROUTING_NONE) { | |
1117 RenderProcessHost* process = web_contents()->GetRenderProcessHost(); | |
1118 rwh = process ? process->GetRenderWidgetHostByID(fullscreen_widget_id_) | |
1119 : NULL; | |
1120 } else { | |
1121 rwh = web_contents()->GetRenderViewHost(); | |
1122 } | |
1123 | |
1124 if (!rwh) { | |
1125 // Transient failure state (e.g., a RenderView is being replaced). | |
1126 consumer->OnSnapshotFailed(CaptureMachine::TRANSIENT_ERROR, frame_number); | |
1127 return; | 1090 return; |
1128 } | 1091 } |
1129 } | 1092 } |
1130 | 1093 |
| 1094 RenderWidgetHost* rwh; |
| 1095 if (fullscreen_widget_id_ != MSG_ROUTING_NONE) { |
| 1096 RenderProcessHost* process = web_contents()->GetRenderProcessHost(); |
| 1097 rwh = process ? process->GetRenderWidgetHostByID(fullscreen_widget_id_) |
| 1098 : NULL; |
| 1099 } else { |
| 1100 rwh = web_contents()->GetRenderViewHost(); |
| 1101 } |
| 1102 |
| 1103 if (!rwh) { |
| 1104 // Transient failure state (e.g., a RenderView is being replaced). |
| 1105 consumer->OnSnapshotFailed(CaptureMachine::TRANSIENT_ERROR, frame_number); |
| 1106 return; |
| 1107 } |
| 1108 |
1131 RenderWidgetHostViewPort* view = | 1109 RenderWidgetHostViewPort* view = |
1132 RenderWidgetHostViewPort::FromRWHV(rwh->GetView()); | 1110 RenderWidgetHostViewPort::FromRWHV(rwh->GetView()); |
1133 | 1111 |
1134 gfx::Size fitted_size; | 1112 gfx::Size fitted_size; |
1135 if (view) { | 1113 if (view) { |
1136 gfx::Size view_size = view->GetViewBounds().size(); | 1114 gfx::Size view_size = view->GetViewBounds().size(); |
1137 if (!view_size.IsEmpty()) { | 1115 if (!view_size.IsEmpty()) { |
1138 CalculateFittedSize(view_size.width(), view_size.height(), | 1116 CalculateFittedSize(view_size.width(), view_size.height(), |
1139 desired_width, desired_height, | 1117 desired_width, desired_height, |
1140 &fitted_size); | 1118 &fitted_size); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1221 } else { | 1199 } else { |
1222 // Capture can fail due to transient issues, so just skip this frame. | 1200 // Capture can fail due to transient issues, so just skip this frame. |
1223 DVLOG(1) << "CopyFromBackingStoreToVideoFrame failure; skipping frame."; | 1201 DVLOG(1) << "CopyFromBackingStoreToVideoFrame failure; skipping frame."; |
1224 consumer->OnSnapshotFailed( | 1202 consumer->OnSnapshotFailed( |
1225 CaptureMachine::TRANSIENT_ERROR, frame_number); | 1203 CaptureMachine::TRANSIENT_ERROR, frame_number); |
1226 } | 1204 } |
1227 } | 1205 } |
1228 | 1206 |
1229 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( | 1207 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( |
1230 const media::VideoCaptureDevice::Name& name, | 1208 const media::VideoCaptureDevice::Name& name, |
1231 int render_process_id, int render_view_id) | 1209 int render_process_id, |
| 1210 int render_view_id, |
| 1211 const base::Closure& destroy_cb) |
1232 : device_name_(name), | 1212 : device_name_(name), |
1233 capturer_(new CaptureMachine(render_process_id, render_view_id)) {} | 1213 capturer_(new CaptureMachine(render_process_id, render_view_id, |
1234 | 1214 destroy_cb)) {} |
1235 WebContentsVideoCaptureDevice::WebContentsVideoCaptureDevice( | |
1236 RenderWidgetHost* test_source, const base::Closure& destroy_cb) | |
1237 : capturer_(new CaptureMachine(-1, -1)) { | |
1238 device_name_.device_name = "WebContentsForTesting"; | |
1239 device_name_.unique_id = "-1:-1"; | |
1240 capturer_->InitializeForTesting(test_source, destroy_cb); | |
1241 } | |
1242 | 1215 |
1243 WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() { | 1216 WebContentsVideoCaptureDevice::~WebContentsVideoCaptureDevice() { |
1244 DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying."; | 1217 DVLOG(2) << "WebContentsVideoCaptureDevice@" << this << " destroying."; |
1245 } | 1218 } |
1246 | 1219 |
1247 // static | 1220 // static |
1248 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create( | 1221 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::Create( |
1249 const std::string& device_id) { | 1222 const std::string& device_id, |
| 1223 const base::Closure& destroy_cb) { |
1250 // Parse device_id into render_process_id and render_view_id. | 1224 // Parse device_id into render_process_id and render_view_id. |
1251 int render_process_id = -1; | 1225 int render_process_id = -1; |
1252 int render_view_id = -1; | 1226 int render_view_id = -1; |
1253 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget(device_id, | 1227 if (!WebContentsCaptureUtil::ExtractTabCaptureTarget(device_id, |
1254 &render_process_id, | 1228 &render_process_id, |
1255 &render_view_id)) | 1229 &render_view_id)) |
1256 return NULL; | 1230 return NULL; |
1257 | 1231 |
1258 media::VideoCaptureDevice::Name name; | 1232 media::VideoCaptureDevice::Name name; |
1259 base::SStringPrintf(&name.device_name, | 1233 base::SStringPrintf(&name.device_name, |
1260 "WebContents[%.*s]", | 1234 "WebContents[%.*s]", |
1261 static_cast<int>(device_id.size()), device_id.data()); | 1235 static_cast<int>(device_id.size()), device_id.data()); |
1262 name.unique_id = device_id; | 1236 name.unique_id = device_id; |
1263 | 1237 |
1264 return new WebContentsVideoCaptureDevice( | 1238 return new WebContentsVideoCaptureDevice( |
1265 name, render_process_id, render_view_id); | 1239 name, render_process_id, render_view_id, destroy_cb); |
1266 } | |
1267 | |
1268 // static | |
1269 media::VideoCaptureDevice* WebContentsVideoCaptureDevice::CreateForTesting( | |
1270 RenderWidgetHost* test_source, const base::Closure& destroy_cb) { | |
1271 return new WebContentsVideoCaptureDevice(test_source, destroy_cb); | |
1272 } | 1240 } |
1273 | 1241 |
1274 void WebContentsVideoCaptureDevice::Allocate( | 1242 void WebContentsVideoCaptureDevice::Allocate( |
1275 int width, int height, int frame_rate, | 1243 int width, int height, int frame_rate, |
1276 VideoCaptureDevice::EventHandler* consumer) { | 1244 VideoCaptureDevice::EventHandler* consumer) { |
1277 DCHECK(capturer_); | 1245 DCHECK(capturer_); |
1278 capturer_->SetConsumer(consumer); | 1246 capturer_->SetConsumer(consumer); |
1279 capturer_->Allocate(width, height, frame_rate); | 1247 capturer_->Allocate(width, height, frame_rate); |
1280 } | 1248 } |
1281 | 1249 |
(...skipping 12 matching lines...) Expand all Loading... |
1294 capturer_->SetConsumer(NULL); | 1262 capturer_->SetConsumer(NULL); |
1295 capturer_->DeAllocate(); | 1263 capturer_->DeAllocate(); |
1296 } | 1264 } |
1297 | 1265 |
1298 const media::VideoCaptureDevice::Name& | 1266 const media::VideoCaptureDevice::Name& |
1299 WebContentsVideoCaptureDevice::device_name() { | 1267 WebContentsVideoCaptureDevice::device_name() { |
1300 return device_name_; | 1268 return device_name_; |
1301 } | 1269 } |
1302 | 1270 |
1303 } // namespace content | 1271 } // namespace content |
OLD | NEW |