Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(105)

Side by Side Diff: webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.cc

Issue 2703123002: Skips the first frame in DxgiDuplicatorController (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698