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

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

Issue 2703123002: Skips the first frame in DxgiDuplicatorController (Closed)
Patch Set: Resolve review comments 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
24 DxgiDuplicatorController::Context::Context() = default; 26 DxgiDuplicatorController::Context::Context() = default;
25 27
26 DxgiDuplicatorController::Context::~Context() { 28 DxgiDuplicatorController::Context::~Context() {
27 DxgiDuplicatorController::Instance()->Unregister(this); 29 DxgiDuplicatorController::Instance()->Unregister(this);
28 } 30 }
29 31
30 void DxgiDuplicatorController::Context::Reset() { 32 void DxgiDuplicatorController::Context::Reset() {
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 id -= duplicators_[i].screen_count(); 99 id -= duplicators_[i].screen_count();
98 } else { 100 } else {
99 return duplicators_[i].ScreenRect(id); 101 return duplicators_[i].ScreenRect(id);
100 } 102 }
101 } 103 }
102 return DesktopRect(); 104 return DesktopRect();
103 } 105 }
104 106
105 int DxgiDuplicatorController::ScreenCount() { 107 int DxgiDuplicatorController::ScreenCount() {
106 rtc::CritScope lock(&lock_); 108 rtc::CritScope lock(&lock_);
107 if (!Initialize()) { 109 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 } 110 }
116 111
117 void DxgiDuplicatorController::Unregister(const Context* const context) { 112 void DxgiDuplicatorController::Unregister(const Context* const context) {
118 rtc::CritScope lock(&lock_); 113 rtc::CritScope lock(&lock_);
119 if (ContextExpired(context)) { 114 if (ContextExpired(context)) {
120 // The Context has not been setup after a recent initialization, so it 115 // The Context has not been setup after a recent initialization, so it
121 // should not been registered in duplicators. 116 // should not been registered in duplicators.
122 return; 117 return;
123 } 118 }
124 for (size_t i = 0; i < duplicators_.size(); i++) { 119 for (size_t i = 0; i < duplicators_.size(); i++) {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
228 223
229 bool DxgiDuplicatorController::DoDuplicate(Context* context, 224 bool DxgiDuplicatorController::DoDuplicate(Context* context,
230 int monitor_id, 225 int monitor_id,
231 SharedDesktopFrame* target) { 226 SharedDesktopFrame* target) {
232 RTC_DCHECK(target); 227 RTC_DCHECK(target);
233 target->mutable_updated_region()->Clear(); 228 target->mutable_updated_region()->Clear();
234 rtc::CritScope lock(&lock_); 229 rtc::CritScope lock(&lock_);
235 if (DoDuplicateUnlocked(context, monitor_id, target)) { 230 if (DoDuplicateUnlocked(context, monitor_id, target)) {
236 return true; 231 return true;
237 } 232 }
238 Deinitialize(); 233 if (monitor_id < ScreenCountUnlocked()) {
234 // It's a user error to provide a |monitor_id| larger than screen count. We
235 // do not need to deinitialize.
236 Deinitialize();
237 }
239 return false; 238 return false;
240 } 239 }
241 240
242 bool DxgiDuplicatorController::DoDuplicateUnlocked(Context* context, 241 bool DxgiDuplicatorController::DoDuplicateUnlocked(Context* context,
243 int monitor_id, 242 int monitor_id,
244 SharedDesktopFrame* target) { 243 SharedDesktopFrame* target) {
245 if (!Initialize()) { 244 if (!Initialize()) {
246 // Cannot initialize COM components now, display mode may be changing. 245 // Cannot initialize COM components now, display mode may be changing.
247 return false; 246 return false;
248 } 247 }
249 248
250 if (resolution_change_detector_.IsChanged( 249 if (resolution_change_detector_.IsChanged(
251 GetScreenRect(kFullDesktopScreenId, std::wstring()).size())) { 250 GetScreenRect(kFullDesktopScreenId, std::wstring()).size())) {
252 // Resolution of entire screen has been changed, which usually means a new 251 // 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 252 // monitor has been attached or one has been removed. The simplest way is to
254 // Deinitialize() and returns false to indicate downstream components. 253 // Deinitialize() and returns false to indicate downstream components.
255 return false; 254 return false;
256 } 255 }
257 256
258 Setup(context); 257 Setup(context);
258
259 if (!EnsureFrameCaptured(context, target)) {
260 return false;
261 }
262
263 bool result = false;
259 if (monitor_id < 0) { 264 if (monitor_id < 0) {
260 // Capture entire screen. 265 // Capture entire screen.
261 for (size_t i = 0; i < duplicators_.size(); i++) { 266 result = DoDuplicateAll(context, target);
262 if (!duplicators_[i].Duplicate(&context->contexts_[i], target)) { 267 } else {
263 return false; 268 result = DoDuplicateOne(context, monitor_id, target);
264 } 269 }
265 } 270
271 if (result) {
266 target->set_dpi(dpi()); 272 target->set_dpi(dpi());
267 return true; 273 return true;
268 } 274 }
269 275
270 // Capture one monitor. 276 return false;
277 }
278
279 bool DxgiDuplicatorController::DoDuplicateAll(Context* context,
280 SharedDesktopFrame* target) {
281 for (size_t i = 0; i < duplicators_.size(); i++) {
282 if (!duplicators_[i].Duplicate(&context->contexts_[i], target)) {
283 return false;
284 }
285 }
286 return true;
287 }
288
289 bool DxgiDuplicatorController::DoDuplicateOne(Context* context,
290 int monitor_id,
291 SharedDesktopFrame* target) {
292 RTC_DCHECK(monitor_id >= 0);
271 for (size_t i = 0; i < duplicators_.size() && i < context->contexts_.size(); 293 for (size_t i = 0; i < duplicators_.size() && i < context->contexts_.size();
272 i++) { 294 i++) {
273 if (monitor_id >= duplicators_[i].screen_count()) { 295 if (monitor_id >= duplicators_[i].screen_count()) {
274 monitor_id -= duplicators_[i].screen_count(); 296 monitor_id -= duplicators_[i].screen_count();
275 } else { 297 } else {
276 if (duplicators_[i].DuplicateMonitor(&context->contexts_[i], monitor_id, 298 if (duplicators_[i].DuplicateMonitor(&context->contexts_[i], monitor_id,
277 target)) { 299 target)) {
278 target->set_dpi(dpi());
279 return true; 300 return true;
280 } 301 }
281 return false; 302 return false;
282 } 303 }
283 } 304 }
284 // id >= ScreenCount(). This is a user error, so we do not need to
285 // deinitialize.
286 return false; 305 return false;
287 } 306 }
288 307
308 int64_t DxgiDuplicatorController::GetNumFramesCaptured() const {
309 int64_t min = INT64_MAX;
310 for (const auto& duplicator : duplicators_) {
311 min = std::min(min, duplicator.GetNumFramesCaptured());
312 }
313
314 return min;
315 }
316
317 int DxgiDuplicatorController::ScreenCountUnlocked() {
318 if (!Initialize()) {
319 return 0;
320 }
321 int result = 0;
322 for (auto& duplicator : duplicators_) {
323 result += duplicator.screen_count();
324 }
325 return result;
326 }
327
328 bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context,
329 SharedDesktopFrame* target) {
330 // On a modern system, the FPS / monitor refresh rate is usually larger than
331 // or equal to 60. So 17 milliseconds is enough to capture at least one frame.
332 const int64_t ms_per_frame = 17;
333 // Skips the first frame to ensure a full frame refresh has happened before
334 // this function returns.
335 const int64_t frames_to_skip = 1;
336 // The total time out milliseconds for this function. If we cannot get enough
337 // frames during this time interval, this function returns false, and cause
338 // the DXGI components to be reinitialized. This usually should not happen
339 // unless the system is switching display mode when this function is being
340 // called. 500 milliseconds should be enough for ~30 frames.
341 const int64_t timeout_ms = 500;
342 if (GetNumFramesCaptured() >= frames_to_skip) {
343 return true;
344 }
345
346 std::unique_ptr<SharedDesktopFrame> fallback_frame;
347 SharedDesktopFrame* shared_frame = nullptr;
348 if (target->size().width() >= desktop_size().width() &&
349 target->size().height() >= desktop_size().height()) {
350 // |target| is large enough to cover entire screen, we do not need to use
351 // |fallback_frame|.
352 shared_frame = target;
353 } else {
354 fallback_frame = SharedDesktopFrame::Wrap(std::unique_ptr<DesktopFrame>(
355 new BasicDesktopFrame(desktop_size())));
356 shared_frame = fallback_frame.get();
357 }
358
359 const int64_t start_ms = rtc::TimeMillis();
360 int64_t last_frame_start_ms = 0;
361 while (GetNumFramesCaptured() < frames_to_skip) {
362 if (GetNumFramesCaptured() > 0) {
363 // Sleep |ms_per_frame| before capturing next frame to ensure the screen
364 // has been updated by the video adapter.
365 webrtc::SleepMs(
366 ms_per_frame - (rtc::TimeMillis() - last_frame_start_ms));
367 }
368 last_frame_start_ms = rtc::TimeMillis();
369 if (!DoDuplicateAll(context, shared_frame)) {
370 return false;
371 }
372 if (rtc::TimeMillis() - start_ms > timeout_ms) {
373 return false;
374 }
375 }
376 return true;
377 }
378
289 } // namespace webrtc 379 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698