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

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

Issue 2788863006: Merge ScreenCapturerWinDirectx::frames_ and contexts_ (Closed)
Patch Set: Created 3 years, 8 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/base/timeutils.h"
20 #include "webrtc/modules/desktop_capture/desktop_capture_types.h" 20 #include "webrtc/modules/desktop_capture/desktop_capture_types.h"
21 #include "webrtc/modules/desktop_capture/win/dxgi_frame.h"
21 #include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" 22 #include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
22 #include "webrtc/system_wrappers/include/sleep.h" 23 #include "webrtc/system_wrappers/include/sleep.h"
23 24
24 namespace webrtc { 25 namespace webrtc {
25 26
26 DxgiDuplicatorController::Context::Context() = default; 27 DxgiDuplicatorController::Context::Context() = default;
27 28
28 DxgiDuplicatorController::Context::~Context() { 29 DxgiDuplicatorController::Context::~Context() {
29 DxgiDuplicatorController::Instance()->Unregister(this); 30 DxgiDuplicatorController::Instance()->Unregister(this);
30 } 31 }
(...skipping 15 matching lines...) Expand all
46 DxgiDuplicatorController::~DxgiDuplicatorController() { 47 DxgiDuplicatorController::~DxgiDuplicatorController() {
47 rtc::CritScope lock(&lock_); 48 rtc::CritScope lock(&lock_);
48 Deinitialize(); 49 Deinitialize();
49 } 50 }
50 51
51 bool DxgiDuplicatorController::IsSupported() { 52 bool DxgiDuplicatorController::IsSupported() {
52 rtc::CritScope lock(&lock_); 53 rtc::CritScope lock(&lock_);
53 return Initialize(); 54 return Initialize();
54 } 55 }
55 56
56 void DxgiDuplicatorController::Reset() {
57 rtc::CritScope lock(&lock_);
58 Deinitialize();
59 }
60
61 bool DxgiDuplicatorController::RetrieveD3dInfo(D3dInfo* info) { 57 bool DxgiDuplicatorController::RetrieveD3dInfo(D3dInfo* info) {
62 rtc::CritScope lock(&lock_); 58 rtc::CritScope lock(&lock_);
63 if (!Initialize()) { 59 if (!Initialize()) {
64 return false; 60 return false;
65 } 61 }
66 *info = d3d_info_; 62 *info = d3d_info_;
67 return true; 63 return true;
68 } 64 }
69 65
66 DxgiDuplicatorController::Result
67 DxgiDuplicatorController::Duplicate(DxgiFrame* frame) {
68 return DoDuplicate(frame, -1);
69 }
70
71 DxgiDuplicatorController::Result
72 DxgiDuplicatorController::DuplicateMonitor(DxgiFrame* frame, int monitor_id) {
73 RTC_DCHECK_GE(monitor_id, 0);
74 return DoDuplicate(frame, monitor_id);
75 }
76
70 DesktopVector DxgiDuplicatorController::dpi() { 77 DesktopVector DxgiDuplicatorController::dpi() {
71 rtc::CritScope lock(&lock_); 78 rtc::CritScope lock(&lock_);
72 if (Initialize()) { 79 if (Initialize()) {
73 return dpi_; 80 return dpi_;
74 } 81 }
75 return DesktopVector(); 82 return DesktopVector();
76 } 83 }
77 84
78 DesktopRect DxgiDuplicatorController::desktop_rect() {
79 rtc::CritScope lock(&lock_);
80 if (Initialize()) {
81 return desktop_rect_;
82 }
83 return DesktopRect();
84 }
85
86 DesktopSize DxgiDuplicatorController::desktop_size() {
87 DesktopRect rect = desktop_rect();
88 return DesktopSize(rect.right(), rect.bottom());
89 }
90
91 DesktopRect DxgiDuplicatorController::ScreenRect(int id) {
92 RTC_DCHECK(id >= 0);
93 rtc::CritScope lock(&lock_);
94 if (!Initialize()) {
95 return DesktopRect();
96 }
97 for (size_t i = 0; i < duplicators_.size(); i++) {
98 if (id >= duplicators_[i].screen_count()) {
99 id -= duplicators_[i].screen_count();
100 } else {
101 return duplicators_[i].ScreenRect(id);
102 }
103 }
104 return DesktopRect();
105 }
106
107 int DxgiDuplicatorController::ScreenCount() { 85 int DxgiDuplicatorController::ScreenCount() {
108 rtc::CritScope lock(&lock_); 86 rtc::CritScope lock(&lock_);
109 return ScreenCountUnlocked(); 87 if (Initialize()) {
88 return ScreenCountUnlocked();
89 }
90 return 0;
91 }
92
93 DxgiDuplicatorController::Result
94 DxgiDuplicatorController::DoDuplicate(DxgiFrame* frame, int monitor_id) {
95 RTC_DCHECK(frame);
96 rtc::CritScope lock(&lock_);
97
98 // The dxgi components and APIs do not update the screen resolution without
99 // a reinitialization. So we use the GetDC() function to retrieve the screen
100 // resolution to decide whether dxgi components need to be reinitialized.
101 // If the screen resolution changed, it's very likely the next Duplicate()
102 // function call will fail because of a missing monitor or the frame size is
103 // not enough to store the output. So we reinitialize dxgi components in-place
104 // to avoid a capture failure.
105 // But there is no guarantee GetDC() function returns the same resolution as
106 // dxgi APIs, we still rely on dxgi components to return the output frame
107 // size.
108 // TODO(zijiehe): Confirm whether IDXGIOutput::GetDesc() and
109 // IDXGIOutputDuplication::GetDesc() can detect the resolution change without
110 // reinitialization.
111 if (resolution_change_detector_.IsChanged(
112 GetScreenRect(kFullDesktopScreenId, std::wstring()).size())) {
113 Deinitialize();
114 }
115
116 if (!Initialize()) {
117 // Cannot initialize COM components now, display mode may be changing.
118 return Result::INITIALIZATION_FAILED;
119 }
120
121 if (!frame->Prepare(SelectedDesktopSize(monitor_id), monitor_id)) {
122 return Result::FRAME_PREPARE_FAILED;
123 }
124
125 frame->frame()->mutable_updated_region()->Clear();
126
127 if (DoDuplicateUnlocked(frame->context(), monitor_id, frame->frame())) {
128 return Result::SUCCEEDED;
129 }
130 if (monitor_id >= ScreenCountUnlocked()) {
131 // It's a user error to provide a |monitor_id| larger than screen count. We
132 // do not need to deinitialize.
133 return Result::INVALID_MONITOR_ID;
134 }
135
136 // If the |monitor_id| is valid, but DoDuplicateUnlocked() failed, something
137 // must be wrong from capturer APIs. We should Deinitialize().
138 Deinitialize();
139 return Result::DUPLICATION_FAILED;
110 } 140 }
111 141
112 void DxgiDuplicatorController::Unregister(const Context* const context) { 142 void DxgiDuplicatorController::Unregister(const Context* const context) {
113 rtc::CritScope lock(&lock_); 143 rtc::CritScope lock(&lock_);
114 if (ContextExpired(context)) { 144 if (ContextExpired(context)) {
115 // The Context has not been setup after a recent initialization, so it 145 // The Context has not been setup after a recent initialization, so it
116 // should not been registered in duplicators. 146 // should not been registered in duplicators.
117 return; 147 return;
118 } 148 }
119 for (size_t i = 0; i < duplicators_.size(); i++) { 149 for (size_t i = 0; i < duplicators_.size(); i++) {
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 } 217 }
188 218
189 void DxgiDuplicatorController::Deinitialize() { 219 void DxgiDuplicatorController::Deinitialize() {
190 desktop_rect_ = DesktopRect(); 220 desktop_rect_ = DesktopRect();
191 duplicators_.clear(); 221 duplicators_.clear();
192 resolution_change_detector_.Reset(); 222 resolution_change_detector_.Reset();
193 } 223 }
194 224
195 bool DxgiDuplicatorController::ContextExpired( 225 bool DxgiDuplicatorController::ContextExpired(
196 const Context* const context) const { 226 const Context* const context) const {
227 RTC_DCHECK(context);
197 return context->identity_ != identity_ || 228 return context->identity_ != identity_ ||
198 context->contexts_.size() != duplicators_.size(); 229 context->contexts_.size() != duplicators_.size();
199 } 230 }
200 231
201 void DxgiDuplicatorController::Setup(Context* context) { 232 void DxgiDuplicatorController::Setup(Context* context) {
202 if (ContextExpired(context)) { 233 if (ContextExpired(context)) {
234 RTC_DCHECK(context);
203 context->contexts_.clear(); 235 context->contexts_.clear();
204 context->contexts_.resize(duplicators_.size()); 236 context->contexts_.resize(duplicators_.size());
205 for (size_t i = 0; i < duplicators_.size(); i++) { 237 for (size_t i = 0; i < duplicators_.size(); i++) {
206 duplicators_[i].Setup(&context->contexts_[i]); 238 duplicators_[i].Setup(&context->contexts_[i]);
207 } 239 }
208 context->identity_ = identity_; 240 context->identity_ = identity_;
209 } 241 }
210 } 242 }
211 243
212 bool DxgiDuplicatorController::Duplicate(Context* context,
213 SharedDesktopFrame* target) {
214 return DoDuplicate(context, -1, target);
215 }
216
217 bool DxgiDuplicatorController::DuplicateMonitor(Context* context,
218 int monitor_id,
219 SharedDesktopFrame* target) {
220 RTC_DCHECK_GE(monitor_id, 0);
221 return DoDuplicate(context, monitor_id, target);
222 }
223
224 bool DxgiDuplicatorController::DoDuplicate(Context* context,
225 int monitor_id,
226 SharedDesktopFrame* target) {
227 RTC_DCHECK(target);
228 target->mutable_updated_region()->Clear();
229 rtc::CritScope lock(&lock_);
230 if (DoDuplicateUnlocked(context, monitor_id, target)) {
231 return true;
232 }
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 }
238 return false;
239 }
240
241 bool DxgiDuplicatorController::DoDuplicateUnlocked(Context* context, 244 bool DxgiDuplicatorController::DoDuplicateUnlocked(Context* context,
242 int monitor_id, 245 int monitor_id,
243 SharedDesktopFrame* target) { 246 SharedDesktopFrame* target) {
244 if (!Initialize()) {
245 // Cannot initialize COM components now, display mode may be changing.
246 return false;
247 }
248
249 if (resolution_change_detector_.IsChanged(
250 GetScreenRect(kFullDesktopScreenId, std::wstring()).size())) {
251 // Resolution of entire screen has been changed, which usually means a new
252 // monitor has been attached or one has been removed. The simplest way is to
253 // Deinitialize() and returns false to indicate downstream components.
254 return false;
255 }
256
257 Setup(context); 247 Setup(context);
258 248
259 if (!EnsureFrameCaptured(context, target)) { 249 if (!EnsureFrameCaptured(context, target)) {
260 return false; 250 return false;
261 } 251 }
262 252
263 bool result = false; 253 bool result = false;
264 if (monitor_id < 0) { 254 if (monitor_id < 0) {
265 // Capture entire screen. 255 // Capture entire screen.
266 result = DoDuplicateAll(context, target); 256 result = DoDuplicateAll(context, target);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 297
308 int64_t DxgiDuplicatorController::GetNumFramesCaptured() const { 298 int64_t DxgiDuplicatorController::GetNumFramesCaptured() const {
309 int64_t min = INT64_MAX; 299 int64_t min = INT64_MAX;
310 for (const auto& duplicator : duplicators_) { 300 for (const auto& duplicator : duplicators_) {
311 min = std::min(min, duplicator.GetNumFramesCaptured()); 301 min = std::min(min, duplicator.GetNumFramesCaptured());
312 } 302 }
313 303
314 return min; 304 return min;
315 } 305 }
316 306
317 int DxgiDuplicatorController::ScreenCountUnlocked() { 307 DesktopSize DxgiDuplicatorController::desktop_size() const {
318 if (!Initialize()) { 308 return DesktopSize(desktop_rect_.right(), desktop_rect_.bottom());
319 return 0; 309 }
310
311 DesktopRect DxgiDuplicatorController::ScreenRect(int id) const {
312 RTC_DCHECK(id >= 0);
313 for (size_t i = 0; i < duplicators_.size(); i++) {
314 if (id >= duplicators_[i].screen_count()) {
315 id -= duplicators_[i].screen_count();
316 } else {
317 return duplicators_[i].ScreenRect(id);
318 }
320 } 319 }
320 return DesktopRect();
321 }
322
323 int DxgiDuplicatorController::ScreenCountUnlocked() const {
321 int result = 0; 324 int result = 0;
322 for (auto& duplicator : duplicators_) { 325 for (auto& duplicator : duplicators_) {
323 result += duplicator.screen_count(); 326 result += duplicator.screen_count();
324 } 327 }
325 return result; 328 return result;
326 } 329 }
327 330
331 DesktopSize DxgiDuplicatorController::SelectedDesktopSize(
332 int monitor_id) const {
333 if (monitor_id < 0) {
334 return desktop_size();
335 }
336
337 return ScreenRect(monitor_id).size();
338 }
339
328 bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context, 340 bool DxgiDuplicatorController::EnsureFrameCaptured(Context* context,
329 SharedDesktopFrame* target) { 341 SharedDesktopFrame* target) {
330 // On a modern system, the FPS / monitor refresh rate is usually larger than 342 // 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. 343 // or equal to 60. So 17 milliseconds is enough to capture at least one frame.
332 const int64_t ms_per_frame = 17; 344 const int64_t ms_per_frame = 17;
333 // Skips the first frame to ensure a full frame refresh has happened before 345 // Skips the first frame to ensure a full frame refresh has happened before
334 // this function returns. 346 // this function returns.
335 const int64_t frames_to_skip = 1; 347 const int64_t frames_to_skip = 1;
336 // The total time out milliseconds for this function. If we cannot get enough 348 // 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 349 // frames during this time interval, this function returns false, and cause
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
370 return false; 382 return false;
371 } 383 }
372 if (rtc::TimeMillis() - start_ms > timeout_ms) { 384 if (rtc::TimeMillis() - start_ms > timeout_ms) {
373 return false; 385 return false;
374 } 386 }
375 } 387 }
376 return true; 388 return true;
377 } 389 }
378 390
379 } // namespace webrtc 391 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698