Chromium Code Reviews| 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 |