Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h" | 11 #include "webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h" |
| 12 | 12 |
| 13 #include <windows.h> | 13 #include <windows.h> |
| 14 | 14 |
| 15 #include <algorithm> | 15 #include <algorithm> |
| 16 #include <string> | 16 #include <string> |
| 17 | 17 |
| 18 #include "webrtc/base/checks.h" | 18 #include "webrtc/base/checks.h" |
| 19 #include "webrtc/base/timeutils.h" | |
| 19 #include "webrtc/modules/desktop_capture/desktop_capture_types.h" | 20 #include "webrtc/modules/desktop_capture/desktop_capture_types.h" |
| 20 #include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" | 21 #include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" |
| 22 #include "webrtc/system_wrappers/include/sleep.h" | |
| 21 | 23 |
| 22 namespace webrtc { | 24 namespace webrtc { |
| 23 | 25 |
| 26 namespace { | |
| 27 | |
| 28 void SleepMoreThanMs(int milliseconds) { | |
|
Sergey Ulanov
2017/02/23 19:07:30
Do you really need this function? webrtc::SleepMs(
Hzj_jie
2017/02/23 20:52:11
According to MSDN, the Sleep() function may still
Sergey Ulanov
2017/02/23 21:06:43
Where does it say that? I was reading these page:
Hzj_jie
2017/02/23 21:48:58
It states,
If dwMilliseconds is less than the reso
Sergey Ulanov
2017/02/24 00:40:40
Ah, I see. Sorry I missed it. Still, I don't think
Hzj_jie
2017/02/24 01:28:52
Done.
| |
| 29 if (milliseconds <= 0) { | |
| 30 return; | |
| 31 } | |
| 32 int64_t end_ms = rtc::TimeMillis() + milliseconds; | |
| 33 int64_t current_ms = rtc::TimeMillis(); | |
| 34 while (current_ms < end_ms) { | |
| 35 webrtc::SleepMs(end_ms - current_ms); | |
| 36 current_ms = rtc::TimeMillis(); | |
| 37 } | |
| 38 } | |
| 39 | |
| 40 } // namespace | |
| 41 | |
| 24 DxgiDuplicatorController::Context::Context() = default; | 42 DxgiDuplicatorController::Context::Context() = default; |
| 25 | 43 |
| 26 DxgiDuplicatorController::Context::~Context() { | 44 DxgiDuplicatorController::Context::~Context() { |
| 27 DxgiDuplicatorController::Instance()->Unregister(this); | 45 DxgiDuplicatorController::Instance()->Unregister(this); |
| 28 } | 46 } |
| 29 | 47 |
| 30 void DxgiDuplicatorController::Context::Reset() { | 48 void DxgiDuplicatorController::Context::Reset() { |
| 31 identity_ = 0; | 49 identity_ = 0; |
| 32 } | 50 } |
| 33 | 51 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 97 id -= duplicators_[i].screen_count(); | 115 id -= duplicators_[i].screen_count(); |
| 98 } else { | 116 } else { |
| 99 return duplicators_[i].ScreenRect(id); | 117 return duplicators_[i].ScreenRect(id); |
| 100 } | 118 } |
| 101 } | 119 } |
| 102 return DesktopRect(); | 120 return DesktopRect(); |
| 103 } | 121 } |
| 104 | 122 |
| 105 int DxgiDuplicatorController::ScreenCount() { | 123 int DxgiDuplicatorController::ScreenCount() { |
| 106 rtc::CritScope lock(&lock_); | 124 rtc::CritScope lock(&lock_); |
| 107 if (!Initialize()) { | 125 return ScreenCountUnlocked(); |
| 108 return 0; | |
| 109 } | |
| 110 int result = 0; | |
| 111 for (auto& duplicator : duplicators_) { | |
| 112 result += duplicator.screen_count(); | |
| 113 } | |
| 114 return result; | |
| 115 } | 126 } |
| 116 | 127 |
| 117 void DxgiDuplicatorController::Unregister(const Context* const context) { | 128 void DxgiDuplicatorController::Unregister(const Context* const context) { |
| 118 rtc::CritScope lock(&lock_); | 129 rtc::CritScope lock(&lock_); |
| 119 if (ContextExpired(context)) { | 130 if (ContextExpired(context)) { |
| 120 // The Context has not been setup after a recent initialization, so it | 131 // The Context has not been setup after a recent initialization, so it |
| 121 // should not been registered in duplicators. | 132 // should not been registered in duplicators. |
| 122 return; | 133 return; |
| 123 } | 134 } |
| 124 for (size_t i = 0; i < duplicators_.size(); i++) { | 135 for (size_t i = 0; i < duplicators_.size(); i++) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 228 | 239 |
| 229 bool DxgiDuplicatorController::DoDuplicate(Context* context, | 240 bool DxgiDuplicatorController::DoDuplicate(Context* context, |
| 230 int monitor_id, | 241 int monitor_id, |
| 231 SharedDesktopFrame* target) { | 242 SharedDesktopFrame* target) { |
| 232 RTC_DCHECK(target); | 243 RTC_DCHECK(target); |
| 233 target->mutable_updated_region()->Clear(); | 244 target->mutable_updated_region()->Clear(); |
| 234 rtc::CritScope lock(&lock_); | 245 rtc::CritScope lock(&lock_); |
| 235 if (DoDuplicateUnlocked(context, monitor_id, target)) { | 246 if (DoDuplicateUnlocked(context, monitor_id, target)) { |
| 236 return true; | 247 return true; |
| 237 } | 248 } |
| 238 Deinitialize(); | 249 if (monitor_id < ScreenCountUnlocked()) { |
| 250 // It's a user error to provide a |monitor_id| larger than screen count. We | |
| 251 // do not need to deinitialize. | |
| 252 Deinitialize(); | |
| 253 } | |
| 239 return false; | 254 return false; |
| 240 } | 255 } |
| 241 | 256 |
| 242 bool DxgiDuplicatorController::DoDuplicateUnlocked(Context* context, | 257 bool DxgiDuplicatorController::DoDuplicateUnlocked(Context* context, |
| 243 int monitor_id, | 258 int monitor_id, |
| 244 SharedDesktopFrame* target) { | 259 SharedDesktopFrame* target) { |
| 245 if (!Initialize()) { | 260 if (!Initialize()) { |
| 246 // Cannot initialize COM components now, display mode may be changing. | 261 // Cannot initialize COM components now, display mode may be changing. |
| 247 return false; | 262 return false; |
| 248 } | 263 } |
| 249 | 264 |
| 250 if (resolution_change_detector_.IsChanged( | 265 if (resolution_change_detector_.IsChanged( |
| 251 GetScreenRect(kFullDesktopScreenId, std::wstring()).size())) { | 266 GetScreenRect(kFullDesktopScreenId, std::wstring()).size())) { |
| 252 // Resolution of entire screen has been changed, which usually means a new | 267 // Resolution of entire screen has been changed, which usually means a new |
| 253 // monitor has been attached or one has been removed. The simplest way is to | 268 // monitor has been attached or one has been removed. The simplest way is to |
| 254 // Deinitialize() and returns false to indicate downstream components. | 269 // Deinitialize() and returns false to indicate downstream components. |
| 255 return false; | 270 return false; |
| 256 } | 271 } |
| 257 | 272 |
| 258 Setup(context); | 273 Setup(context); |
| 274 | |
| 275 if (!EnsureFrameCaptured(context, target)) { | |
| 276 return false; | |
| 277 } | |
| 278 | |
| 279 bool result = false; | |
| 259 if (monitor_id < 0) { | 280 if (monitor_id < 0) { |
| 260 // Capture entire screen. | 281 // Capture entire screen. |
| 261 for (size_t i = 0; i < duplicators_.size(); i++) { | 282 result = DoDuplicateAll(context, target); |
| 262 if (!duplicators_[i].Duplicate(&context->contexts_[i], target)) { | 283 } else { |
| 263 return false; | 284 result = DoDuplicateOne(context, monitor_id, target); |
| 264 } | 285 } |
| 265 } | 286 |
| 287 if (result) { | |
| 266 target->set_dpi(dpi()); | 288 target->set_dpi(dpi()); |
| 267 return true; | 289 return true; |
| 268 } | 290 } |
| 269 | 291 |
| 270 // Capture one monitor. | 292 return false; |
| 293 } | |
| 294 | |
| 295 bool DxgiDuplicatorController::DoDuplicateAll(Context* context, | |
| 296 SharedDesktopFrame* target) { | |
| 297 for (size_t i = 0; i < duplicators_.size(); i++) { | |
| 298 if (!duplicators_[i].Duplicate(&context->contexts_[i], target)) { | |
| 299 return false; | |
| 300 } | |
| 301 } | |
| 302 return true; | |
| 303 } | |
| 304 | |
| 305 bool DxgiDuplicatorController::DoDuplicateOne(Context* context, | |
| 306 int monitor_id, | |
| 307 SharedDesktopFrame* target) { | |
| 308 RTC_DCHECK(monitor_id >= 0); | |
| 271 for (size_t i = 0; i < duplicators_.size() && i < context->contexts_.size(); | 309 for (size_t i = 0; i < duplicators_.size() && i < context->contexts_.size(); |
| 272 i++) { | 310 i++) { |
| 273 if (monitor_id >= duplicators_[i].screen_count()) { | 311 if (monitor_id >= duplicators_[i].screen_count()) { |
| 274 monitor_id -= duplicators_[i].screen_count(); | 312 monitor_id -= duplicators_[i].screen_count(); |
| 275 } else { | 313 } else { |
| 276 if (duplicators_[i].DuplicateMonitor(&context->contexts_[i], monitor_id, | 314 if (duplicators_[i].DuplicateMonitor(&context->contexts_[i], monitor_id, |
| 277 target)) { | 315 target)) { |
| 278 target->set_dpi(dpi()); | |
| 279 return true; | 316 return true; |
| 280 } | 317 } |
| 281 return false; | 318 return false; |
| 282 } | 319 } |
| 283 } | 320 } |
| 284 // id >= ScreenCount(). This is a user error, so we do not need to | |
| 285 // deinitialize. | |
| 286 return false; | 321 return false; |
| 287 } | 322 } |
| 288 | 323 |
| 324 int64_t DxgiDuplicatorController::num_frames_captured() const { | |
|
Sergey Ulanov
2017/02/23 19:07:30
GetNumFramesCaptured()
Hzj_jie
2017/02/23 20:52:11
Done.
| |
| 325 int64_t min = INT64_MAX; | |
| 326 for (size_t i = 0; i < duplicators_.size(); i++) { | |
| 327 if (duplicators_[i].num_frames_captured() < min) { | |
| 328 min = duplicators_[i].num_frames_captured(); | |
| 329 } | |
| 330 } | |
| 331 | |
| 332 return min; | |
| 333 } | |
| 334 | |
| 335 int DxgiDuplicatorController::ScreenCountUnlocked() { | |
| 336 if (!Initialize()) { | |
| 337 return 0; | |
| 338 } | |
| 339 int result = 0; | |
| 340 for (auto& duplicator : duplicators_) { | |
| 341 result += duplicator.screen_count(); | |
| 342 } | |
| 343 return result; | |
| 344 } | |
| 345 | |
| 346 bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context, | |
| 347 SharedDesktopFrame* target) { | |
| 348 // On a modern system, the FPS / monitor refresh rate is usually larger than | |
| 349 // or equal to 60. So 17 milliseconds is enough to capture at least one frame. | |
| 350 const int64_t ms_per_frame = 17; | |
| 351 const int64_t skip_frames = 2; | |
|
Sergey Ulanov
2017/02/23 19:07:30
Where does 2 come from? why 1 is not enough?
Sergey Ulanov
2017/02/23 19:07:30
maybe call it frames_to_skip?
Hzj_jie
2017/02/23 20:52:11
Done.
Hzj_jie
2017/02/23 20:52:11
By using 2, we can ensure we always wait for 17 mi
Sergey Ulanov
2017/02/23 21:06:43
But why do we need to ensure that at all? I think
Hzj_jie
2017/02/23 21:48:58
Here the real issue is, we need to ensure two succ
| |
| 352 if (num_frames_captured() >= skip_frames) { | |
| 353 return true; | |
| 354 } | |
| 355 | |
| 356 std::unique_ptr<SharedDesktopFrame> fallback_frame; | |
| 357 SharedDesktopFrame* shared_frame = nullptr; | |
| 358 if (target->size().width() >= desktop_size().width() && | |
| 359 target->size().height() >= desktop_size().height()) { | |
|
Sergey Ulanov
2017/02/23 19:07:30
Why is this necessary? Shouldn't the capturer make
Hzj_jie
2017/02/23 20:52:11
A ScreenCapturerWinDirectx may capture only one of
| |
| 360 // |target| is large enough to cover entire screen, we do not need to use | |
| 361 // |fallback_frame|. | |
| 362 shared_frame = target; | |
| 363 } else { | |
| 364 fallback_frame = SharedDesktopFrame::Wrap(std::unique_ptr<DesktopFrame>( | |
| 365 new BasicDesktopFrame(desktop_size()))); | |
| 366 shared_frame = fallback_frame.get(); | |
| 367 } | |
| 368 | |
| 369 int64_t start_ms = rtc::TimeMillis(); | |
| 370 int64_t last_frame_start_ms = 0; | |
| 371 while (num_frames_captured() < skip_frames) { | |
| 372 if (num_frames_captured() > 0) { | |
| 373 // Sleep |ms_per_frame| before capturing next frame to ensure the screen | |
| 374 // has been updated by the video adapter. | |
| 375 SleepMoreThanMs( | |
| 376 ms_per_frame - (rtc::TimeMillis() - last_frame_start_ms)); | |
| 377 } | |
| 378 last_frame_start_ms = rtc::TimeMillis(); | |
| 379 if (!DoDuplicateAll(context, shared_frame)) { | |
| 380 return false; | |
| 381 } | |
| 382 if (rtc::TimeMillis() - start_ms > (ms_per_frame * skip_frames * 4)) { | |
|
Sergey Ulanov
2017/02/23 19:07:30
Where does 4 come from? I suggest adding a separat
Hzj_jie
2017/02/23 20:52:11
It's a very random number. :)
Updated.
| |
| 383 return false; | |
| 384 } | |
| 385 } | |
| 386 return true; | |
| 387 } | |
| 388 | |
| 289 } // namespace webrtc | 389 } // namespace webrtc |
| OLD | NEW |