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

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

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

Powered by Google App Engine
This is Rietveld 408576698