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" |
| 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 |