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