OLD | NEW |
---|---|
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 #include "content/browser/media/capture/desktop_capture_device.h" | 5 #include "content/browser/media/capture/desktop_capture_device.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/location.h" | 8 #include "base/location.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/metrics/histogram.h" | |
10 #include "base/sequenced_task_runner.h" | 11 #include "base/sequenced_task_runner.h" |
11 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
12 #include "base/synchronization/lock.h" | 13 #include "base/synchronization/lock.h" |
13 #include "base/threading/sequenced_worker_pool.h" | 14 #include "base/threading/sequenced_worker_pool.h" |
14 #include "content/public/browser/browser_thread.h" | 15 #include "content/public/browser/browser_thread.h" |
15 #include "content/public/browser/desktop_media_id.h" | 16 #include "content/public/browser/desktop_media_id.h" |
16 #include "media/base/video_util.h" | 17 #include "media/base/video_util.h" |
17 #include "third_party/libyuv/include/libyuv/scale_argb.h" | 18 #include "third_party/libyuv/include/libyuv/scale_argb.h" |
18 #include "third_party/webrtc/modules/desktop_capture/desktop_and_cursor_composer .h" | 19 #include "third_party/webrtc/modules/desktop_capture/desktop_and_cursor_composer .h" |
19 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" | 20 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" |
20 #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" | 21 #include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" |
21 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 22 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
22 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" | 23 #include "third_party/webrtc/modules/desktop_capture/mouse_cursor_monitor.h" |
23 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" | 24 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" |
24 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" | 25 #include "third_party/webrtc/modules/desktop_capture/window_capturer.h" |
25 | 26 |
26 namespace content { | 27 namespace content { |
27 | 28 |
28 namespace { | 29 namespace { |
29 | 30 |
31 enum DesktopCaptureCounters { | |
32 SCREEN_CAPTURER_CREATED, | |
33 WINDOW_CATPTURER_CREATED, | |
34 FIRST_SCREEN_CAPTURE_SUCCEEDED, | |
35 FIRST_SCREEN_CAPTURE_FAILED, | |
36 FIRST_WINDOW_CAPTURE_SUCCEEDED, | |
37 FIRST_WINDOW_CAPTURE_FAILED, | |
38 DESKTOP_CAPTURE_COUNTER_BOUNDARY | |
Ilya Sherman
2014/04/24 01:57:43
nit: Please document that since this enum is used
| |
39 }; | |
40 | |
41 void IncrementCounter(DesktopCaptureCounters counter) { | |
42 UMA_HISTOGRAM_ENUMERATION("WebRTC.DesktopCaptureCounters", | |
43 counter, | |
44 DESKTOP_CAPTURE_COUNTER_BOUNDARY); | |
45 } | |
46 | |
30 // Maximum CPU time percentage of a single core that can be consumed for desktop | 47 // Maximum CPU time percentage of a single core that can be consumed for desktop |
31 // capturing. This means that on systems where screen scraping is slow we may | 48 // capturing. This means that on systems where screen scraping is slow we may |
32 // need to capture at frame rate lower than requested. This is necessary to keep | 49 // need to capture at frame rate lower than requested. This is necessary to keep |
33 // UI responsive. | 50 // UI responsive. |
34 const int kMaximumCpuConsumptionPercentage = 50; | 51 const int kMaximumCpuConsumptionPercentage = 50; |
35 | 52 |
36 webrtc::DesktopRect ComputeLetterboxRect( | 53 webrtc::DesktopRect ComputeLetterboxRect( |
37 const webrtc::DesktopSize& max_size, | 54 const webrtc::DesktopSize& max_size, |
38 const webrtc::DesktopSize& source_size) { | 55 const webrtc::DesktopSize& source_size) { |
39 gfx::Rect result = media::ComputeLetterboxRegion( | 56 gfx::Rect result = media::ComputeLetterboxRegion( |
40 gfx::Rect(0, 0, max_size.width(), max_size.height()), | 57 gfx::Rect(0, 0, max_size.width(), max_size.height()), |
41 gfx::Size(source_size.width(), source_size.height())); | 58 gfx::Size(source_size.width(), source_size.height())); |
42 return webrtc::DesktopRect::MakeLTRB( | 59 return webrtc::DesktopRect::MakeLTRB( |
43 result.x(), result.y(), result.right(), result.bottom()); | 60 result.x(), result.y(), result.right(), result.bottom()); |
44 } | 61 } |
45 | 62 |
46 } // namespace | 63 } // namespace |
47 | 64 |
48 class DesktopCaptureDevice::Core | 65 class DesktopCaptureDevice::Core |
49 : public base::RefCountedThreadSafe<Core>, | 66 : public base::RefCountedThreadSafe<Core>, |
50 public webrtc::DesktopCapturer::Callback { | 67 public webrtc::DesktopCapturer::Callback { |
51 public: | 68 public: |
52 Core(scoped_refptr<base::SequencedTaskRunner> task_runner, | 69 Core(scoped_refptr<base::SequencedTaskRunner> task_runner, |
53 scoped_ptr<webrtc::DesktopCapturer> capturer); | 70 scoped_ptr<webrtc::DesktopCapturer> capturer, |
71 DesktopMediaID::Type type); | |
54 | 72 |
55 // Implementation of VideoCaptureDevice methods. | 73 // Implementation of VideoCaptureDevice methods. |
56 void AllocateAndStart(const media::VideoCaptureParams& params, | 74 void AllocateAndStart(const media::VideoCaptureParams& params, |
57 scoped_ptr<Client> client); | 75 scoped_ptr<Client> client); |
58 void StopAndDeAllocate(); | 76 void StopAndDeAllocate(); |
59 | 77 |
60 void SetNotificationWindowId(gfx::NativeViewId window_id); | 78 void SetNotificationWindowId(gfx::NativeViewId window_id); |
61 | 79 |
62 private: | 80 private: |
63 friend class base::RefCountedThreadSafe<Core>; | 81 friend class base::RefCountedThreadSafe<Core>; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 // and/or letterboxed. | 136 // and/or letterboxed. |
119 webrtc::DesktopRect output_rect_; | 137 webrtc::DesktopRect output_rect_; |
120 | 138 |
121 // True when we have delayed OnCaptureTimer() task posted on | 139 // True when we have delayed OnCaptureTimer() task posted on |
122 // |task_runner_|. | 140 // |task_runner_|. |
123 bool capture_task_posted_; | 141 bool capture_task_posted_; |
124 | 142 |
125 // True when waiting for |desktop_capturer_| to capture current frame. | 143 // True when waiting for |desktop_capturer_| to capture current frame. |
126 bool capture_in_progress_; | 144 bool capture_in_progress_; |
127 | 145 |
146 // The type of the capturer. | |
147 DesktopMediaID::Type capturer_type_; | |
148 | |
128 DISALLOW_COPY_AND_ASSIGN(Core); | 149 DISALLOW_COPY_AND_ASSIGN(Core); |
129 }; | 150 }; |
130 | 151 |
131 DesktopCaptureDevice::Core::Core( | 152 DesktopCaptureDevice::Core::Core( |
132 scoped_refptr<base::SequencedTaskRunner> task_runner, | 153 scoped_refptr<base::SequencedTaskRunner> task_runner, |
133 scoped_ptr<webrtc::DesktopCapturer> capturer) | 154 scoped_ptr<webrtc::DesktopCapturer> capturer, |
155 DesktopMediaID::Type type) | |
134 : task_runner_(task_runner), | 156 : task_runner_(task_runner), |
135 desktop_capturer_(capturer.Pass()), | 157 desktop_capturer_(capturer.Pass()), |
136 capture_task_posted_(false), | 158 capture_task_posted_(false), |
137 capture_in_progress_(false) {} | 159 capture_in_progress_(false), |
160 capturer_type_(type) {} | |
138 | 161 |
139 DesktopCaptureDevice::Core::~Core() { | 162 DesktopCaptureDevice::Core::~Core() { |
140 } | 163 } |
141 | 164 |
142 void DesktopCaptureDevice::Core::AllocateAndStart( | 165 void DesktopCaptureDevice::Core::AllocateAndStart( |
143 const media::VideoCaptureParams& params, | 166 const media::VideoCaptureParams& params, |
144 scoped_ptr<Client> client) { | 167 scoped_ptr<Client> client) { |
145 DCHECK_GT(params.requested_format.frame_size.GetArea(), 0); | 168 DCHECK_GT(params.requested_format.frame_size.GetArea(), 0); |
146 DCHECK_GT(params.requested_format.frame_rate, 0); | 169 DCHECK_GT(params.requested_format.frame_rate, 0); |
147 | 170 |
(...skipping 17 matching lines...) Expand all Loading... | |
165 webrtc::SharedMemory* | 188 webrtc::SharedMemory* |
166 DesktopCaptureDevice::Core::CreateSharedMemory(size_t size) { | 189 DesktopCaptureDevice::Core::CreateSharedMemory(size_t size) { |
167 return NULL; | 190 return NULL; |
168 } | 191 } |
169 | 192 |
170 void DesktopCaptureDevice::Core::OnCaptureCompleted( | 193 void DesktopCaptureDevice::Core::OnCaptureCompleted( |
171 webrtc::DesktopFrame* frame) { | 194 webrtc::DesktopFrame* frame) { |
172 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 195 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
173 DCHECK(capture_in_progress_); | 196 DCHECK(capture_in_progress_); |
174 | 197 |
198 static bool first_call = true; | |
199 if (first_call) { | |
200 first_call = false; | |
201 if (frame) { | |
202 if (capturer_type_ == DesktopMediaID::TYPE_SCREEN) | |
Sergey Ulanov
2014/04/24 02:21:20
maybe use :? to make this code shorter:
if (captu
| |
203 IncrementCounter(FIRST_SCREEN_CAPTURE_SUCCEEDED); | |
Sergey Ulanov
2014/04/24 02:21:20
add {} please
| |
204 else | |
205 IncrementCounter(FIRST_WINDOW_CAPTURE_SUCCEEDED); | |
206 } else { | |
207 if (capturer_type_ == DesktopMediaID::TYPE_SCREEN) | |
208 IncrementCounter(FIRST_SCREEN_CAPTURE_FAILED); | |
209 else | |
210 IncrementCounter(FIRST_WINDOW_CAPTURE_FAILED); | |
211 } | |
212 } | |
213 | |
175 capture_in_progress_ = false; | 214 capture_in_progress_ = false; |
176 | 215 |
177 if (!frame) { | 216 if (!frame) { |
178 std::string log("Failed to capture a frame."); | 217 std::string log("Failed to capture a frame."); |
179 LOG(ERROR) << log; | 218 LOG(ERROR) << log; |
180 client_->OnError(log); | 219 client_->OnError(log); |
181 return; | 220 return; |
182 } | 221 } |
183 | 222 |
184 if (!client_) | 223 if (!client_) |
185 return; | 224 return; |
186 | 225 |
226 base::TimeDelta capture_time( | |
227 base::TimeDelta::FromMilliseconds(frame->capture_time_ms())); | |
228 if (capturer_type_ == DesktopMediaID::TYPE_SCREEN) | |
229 HISTOGRAM_TIMES("WebRTC.ScreenCaptureTime", capture_time); | |
Sergey Ulanov
2014/04/24 02:21:20
add {} please
| |
230 else | |
231 HISTOGRAM_TIMES("WebRTC.WindowCaptureTime", capture_time); | |
Ilya Sherman
2014/04/24 01:57:43
These should both be UMA_HISTOGRAM_TIMES rather th
| |
232 | |
187 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame); | 233 scoped_ptr<webrtc::DesktopFrame> owned_frame(frame); |
188 | 234 |
189 // Handle initial frame size and size changes. | 235 // Handle initial frame size and size changes. |
190 RefreshCaptureFormat(frame->size()); | 236 RefreshCaptureFormat(frame->size()); |
191 | 237 |
192 webrtc::DesktopSize output_size(capture_format_.frame_size.width(), | 238 webrtc::DesktopSize output_size(capture_format_.frame_size.width(), |
193 capture_format_.frame_size.height()); | 239 capture_format_.frame_size.height()); |
194 size_t output_bytes = output_size.width() * output_size.height() * | 240 size_t output_bytes = output_size.width() * output_size.height() * |
195 webrtc::DesktopFrame::kBytesPerPixel; | 241 webrtc::DesktopFrame::kBytesPerPixel; |
196 const uint8_t* output_data = NULL; | 242 const uint8_t* output_data = NULL; |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
382 scoped_ptr<webrtc::DesktopCapturer> capturer; | 428 scoped_ptr<webrtc::DesktopCapturer> capturer; |
383 | 429 |
384 switch (source.type) { | 430 switch (source.type) { |
385 case DesktopMediaID::TYPE_SCREEN: { | 431 case DesktopMediaID::TYPE_SCREEN: { |
386 scoped_ptr<webrtc::ScreenCapturer> screen_capturer; | 432 scoped_ptr<webrtc::ScreenCapturer> screen_capturer; |
387 screen_capturer.reset(webrtc::ScreenCapturer::Create(options)); | 433 screen_capturer.reset(webrtc::ScreenCapturer::Create(options)); |
388 if (screen_capturer && screen_capturer->SelectScreen(source.id)) { | 434 if (screen_capturer && screen_capturer->SelectScreen(source.id)) { |
389 capturer.reset(new webrtc::DesktopAndCursorComposer( | 435 capturer.reset(new webrtc::DesktopAndCursorComposer( |
390 screen_capturer.release(), | 436 screen_capturer.release(), |
391 webrtc::MouseCursorMonitor::CreateForScreen(options, source.id))); | 437 webrtc::MouseCursorMonitor::CreateForScreen(options, source.id))); |
438 IncrementCounter(SCREEN_CAPTURER_CREATED); | |
392 } | 439 } |
393 break; | 440 break; |
394 } | 441 } |
395 | 442 |
396 case DesktopMediaID::TYPE_WINDOW: { | 443 case DesktopMediaID::TYPE_WINDOW: { |
397 scoped_ptr<webrtc::WindowCapturer> window_capturer( | 444 scoped_ptr<webrtc::WindowCapturer> window_capturer( |
398 webrtc::WindowCapturer::Create(options)); | 445 webrtc::WindowCapturer::Create(options)); |
399 if (window_capturer && window_capturer->SelectWindow(source.id)) { | 446 if (window_capturer && window_capturer->SelectWindow(source.id)) { |
400 window_capturer->BringSelectedWindowToFront(); | 447 window_capturer->BringSelectedWindowToFront(); |
401 capturer.reset(new webrtc::DesktopAndCursorComposer( | 448 capturer.reset(new webrtc::DesktopAndCursorComposer( |
402 window_capturer.release(), | 449 window_capturer.release(), |
403 webrtc::MouseCursorMonitor::CreateForWindow(options, source.id))); | 450 webrtc::MouseCursorMonitor::CreateForWindow(options, source.id))); |
451 IncrementCounter(WINDOW_CATPTURER_CREATED); | |
404 } | 452 } |
405 break; | 453 break; |
406 } | 454 } |
407 | 455 |
408 default: { | 456 default: { |
409 NOTREACHED(); | 457 NOTREACHED(); |
410 } | 458 } |
411 } | 459 } |
412 | 460 |
413 scoped_ptr<media::VideoCaptureDevice> result; | 461 scoped_ptr<media::VideoCaptureDevice> result; |
414 if (capturer) | 462 if (capturer) { |
415 result.reset(new DesktopCaptureDevice(task_runner, capturer.Pass())); | 463 result.reset( |
464 new DesktopCaptureDevice(task_runner, capturer.Pass(), source.type)); | |
465 } | |
416 | 466 |
417 return result.Pass(); | 467 return result.Pass(); |
418 } | 468 } |
419 | 469 |
420 DesktopCaptureDevice::DesktopCaptureDevice( | 470 DesktopCaptureDevice::DesktopCaptureDevice( |
421 scoped_refptr<base::SequencedTaskRunner> task_runner, | 471 scoped_refptr<base::SequencedTaskRunner> task_runner, |
422 scoped_ptr<webrtc::DesktopCapturer> capturer) | 472 scoped_ptr<webrtc::DesktopCapturer> capturer, |
423 : core_(new Core(task_runner, capturer.Pass())) {} | 473 DesktopMediaID::Type type) |
474 : core_(new Core(task_runner, capturer.Pass(), type)) {} | |
424 | 475 |
425 DesktopCaptureDevice::~DesktopCaptureDevice() { | 476 DesktopCaptureDevice::~DesktopCaptureDevice() { |
426 StopAndDeAllocate(); | 477 StopAndDeAllocate(); |
427 } | 478 } |
428 | 479 |
429 void DesktopCaptureDevice::AllocateAndStart( | 480 void DesktopCaptureDevice::AllocateAndStart( |
430 const media::VideoCaptureParams& params, | 481 const media::VideoCaptureParams& params, |
431 scoped_ptr<Client> client) { | 482 scoped_ptr<Client> client) { |
432 core_->AllocateAndStart(params, client.Pass()); | 483 core_->AllocateAndStart(params, client.Pass()); |
433 } | 484 } |
434 | 485 |
435 void DesktopCaptureDevice::StopAndDeAllocate() { | 486 void DesktopCaptureDevice::StopAndDeAllocate() { |
436 core_->StopAndDeAllocate(); | 487 core_->StopAndDeAllocate(); |
437 } | 488 } |
438 | 489 |
439 void DesktopCaptureDevice::SetNotificationWindowId( | 490 void DesktopCaptureDevice::SetNotificationWindowId( |
440 gfx::NativeViewId window_id) { | 491 gfx::NativeViewId window_id) { |
441 core_->SetNotificationWindowId(window_id); | 492 core_->SetNotificationWindowId(window_id); |
442 } | 493 } |
443 | 494 |
444 } // namespace content | 495 } // namespace content |
OLD | NEW |