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/logging.h" | |
19 #include "webrtc/base/timeutils.h" | 20 #include "webrtc/base/timeutils.h" |
21 #include "webrtc/base/win32.h" | |
20 #include "webrtc/modules/desktop_capture/desktop_capture_types.h" | 22 #include "webrtc/modules/desktop_capture/desktop_capture_types.h" |
21 #include "webrtc/modules/desktop_capture/win/dxgi_frame.h" | 23 #include "webrtc/modules/desktop_capture/win/dxgi_frame.h" |
22 #include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" | 24 #include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" |
23 #include "webrtc/system_wrappers/include/sleep.h" | 25 #include "webrtc/system_wrappers/include/sleep.h" |
24 | 26 |
25 namespace webrtc { | 27 namespace webrtc { |
26 | 28 |
29 namespace { | |
30 | |
31 bool IsRunningInSession0() { | |
32 DWORD session_id = 0; | |
33 if (!::ProcessIdToSessionId(::GetCurrentProcessId(), &session_id)) { | |
34 LOG(LS_WARNING) << "Failed to retrieve current session Id, no priviledge?"; | |
35 return true; | |
36 } | |
37 return session_id == 0; | |
38 } | |
39 | |
40 } // namespace | |
41 | |
27 // static | 42 // static |
28 DxgiDuplicatorController* DxgiDuplicatorController::Instance() { | 43 DxgiDuplicatorController* DxgiDuplicatorController::Instance() { |
29 // The static instance won't be deleted to ensure it can be used by other | 44 // The static instance won't be deleted to ensure it can be used by other |
30 // threads even during program exiting. | 45 // threads even during program exiting. |
31 static DxgiDuplicatorController* instance = new DxgiDuplicatorController(); | 46 static DxgiDuplicatorController* instance = new DxgiDuplicatorController(); |
32 return instance; | 47 return instance; |
33 } | 48 } |
34 | 49 |
35 DxgiDuplicatorController::DxgiDuplicatorController() = default; | 50 DxgiDuplicatorController::DxgiDuplicatorController() = default; |
36 | 51 |
37 DxgiDuplicatorController::~DxgiDuplicatorController() { | 52 DxgiDuplicatorController::~DxgiDuplicatorController() { |
38 rtc::CritScope lock(&lock_); | 53 rtc::CritScope lock(&lock_); |
39 Deinitialize(); | 54 Deinitialize(); |
40 } | 55 } |
41 | 56 |
42 bool DxgiDuplicatorController::IsSupported() { | 57 bool DxgiDuplicatorController::IsSupported() { |
43 rtc::CritScope lock(&lock_); | 58 bool result = false; |
44 return Initialize(); | 59 { |
60 rtc::CritScope lock(&lock_); | |
61 result = Initialize(); | |
62 } | |
63 | |
64 if (result) { | |
65 return true; | |
66 } | |
67 | |
68 if (IsRunningInSession0()) { | |
69 LOG(LS_WARNING) << "Current binary is running in session 0. DXGI " | |
70 "components cannot be initialized. Fallback to use " | |
71 "Windows version to decide the support of DirectX " | |
72 "capturer. It may be inaccurate."; | |
73 return rtc::IsWindows8OrLater(); | |
Sergey Ulanov
2017/06/26 23:41:41
In this case DX capturer is effectively unsupporte
Hzj_jie
2017/06/27 04:37:33
A very good point, I have moved this logic into ht
| |
74 } | |
75 | |
76 return false; | |
45 } | 77 } |
46 | 78 |
47 bool DxgiDuplicatorController::RetrieveD3dInfo(D3dInfo* info) { | 79 bool DxgiDuplicatorController::RetrieveD3dInfo(D3dInfo* info) { |
48 rtc::CritScope lock(&lock_); | 80 bool result = false; |
49 if (!Initialize()) { | 81 { |
50 return false; | 82 rtc::CritScope lock(&lock_); |
83 result = Initialize(); | |
51 } | 84 } |
52 *info = d3d_info_; | 85 |
53 return true; | 86 if (result) { |
87 *info = d3d_info_; | |
88 return true; | |
89 } | |
90 | |
91 if (IsRunningInSession0()) { | |
92 LOG(LS_WARNING) << "Current binary is running in session 0. Initialization " | |
93 "of DXGI components are expected to fail. But " | |
94 "retrieving feature level is still supported."; | |
95 *info = d3d_info_; | |
96 return true; | |
97 } | |
98 | |
99 return false; | |
54 } | 100 } |
55 | 101 |
56 DxgiDuplicatorController::Result | 102 DxgiDuplicatorController::Result |
57 DxgiDuplicatorController::Duplicate(DxgiFrame* frame) { | 103 DxgiDuplicatorController::Duplicate(DxgiFrame* frame) { |
58 return DoDuplicate(frame, -1); | 104 return DoDuplicate(frame, -1); |
59 } | 105 } |
60 | 106 |
61 DxgiDuplicatorController::Result | 107 DxgiDuplicatorController::Result |
62 DxgiDuplicatorController::DuplicateMonitor(DxgiFrame* frame, int monitor_id) { | 108 DxgiDuplicatorController::DuplicateMonitor(DxgiFrame* frame, int monitor_id) { |
63 RTC_DCHECK_GE(monitor_id, 0); | 109 RTC_DCHECK_GE(monitor_id, 0); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 // size. | 143 // size. |
98 // TODO(zijiehe): Confirm whether IDXGIOutput::GetDesc() and | 144 // TODO(zijiehe): Confirm whether IDXGIOutput::GetDesc() and |
99 // IDXGIOutputDuplication::GetDesc() can detect the resolution change without | 145 // IDXGIOutputDuplication::GetDesc() can detect the resolution change without |
100 // reinitialization. | 146 // reinitialization. |
101 if (resolution_change_detector_.IsChanged( | 147 if (resolution_change_detector_.IsChanged( |
102 GetScreenRect(kFullDesktopScreenId, std::wstring()).size())) { | 148 GetScreenRect(kFullDesktopScreenId, std::wstring()).size())) { |
103 Deinitialize(); | 149 Deinitialize(); |
104 } | 150 } |
105 | 151 |
106 if (!Initialize()) { | 152 if (!Initialize()) { |
153 if (succeeded_duplications_ == 0 && IsRunningInSession0()) { | |
154 LOG(LS_WARNING) << "Current binary is running in session 0. DXGI " | |
155 "components cannot be initialized."; | |
156 return Result::UNSUPPORTED_SESSION; | |
157 } | |
158 | |
107 // Cannot initialize COM components now, display mode may be changing. | 159 // Cannot initialize COM components now, display mode may be changing. |
108 return Result::INITIALIZATION_FAILED; | 160 return Result::INITIALIZATION_FAILED; |
109 } | 161 } |
110 | 162 |
111 if (!frame->Prepare(SelectedDesktopSize(monitor_id), monitor_id)) { | 163 if (!frame->Prepare(SelectedDesktopSize(monitor_id), monitor_id)) { |
112 return Result::FRAME_PREPARE_FAILED; | 164 return Result::FRAME_PREPARE_FAILED; |
113 } | 165 } |
114 | 166 |
115 frame->frame()->mutable_updated_region()->Clear(); | 167 frame->frame()->mutable_updated_region()->Clear(); |
116 | 168 |
117 if (DoDuplicateUnlocked(frame->context(), monitor_id, frame->frame())) { | 169 if (DoDuplicateUnlocked(frame->context(), monitor_id, frame->frame())) { |
170 succeeded_duplications_++; | |
118 return Result::SUCCEEDED; | 171 return Result::SUCCEEDED; |
119 } | 172 } |
120 if (monitor_id >= ScreenCountUnlocked()) { | 173 if (monitor_id >= ScreenCountUnlocked()) { |
121 // It's a user error to provide a |monitor_id| larger than screen count. We | 174 // It's a user error to provide a |monitor_id| larger than screen count. We |
122 // do not need to deinitialize. | 175 // do not need to deinitialize. |
123 return Result::INVALID_MONITOR_ID; | 176 return Result::INVALID_MONITOR_ID; |
124 } | 177 } |
125 | 178 |
126 // If the |monitor_id| is valid, but DoDuplicateUnlocked() failed, something | 179 // If the |monitor_id| is valid, but DoDuplicateUnlocked() failed, something |
127 // must be wrong from capturer APIs. We should Deinitialize(). | 180 // must be wrong from capturer APIs. We should Deinitialize(). |
(...skipping 27 matching lines...) Expand all Loading... | |
155 | 208 |
156 bool DxgiDuplicatorController::DoInitialize() { | 209 bool DxgiDuplicatorController::DoInitialize() { |
157 RTC_DCHECK(desktop_rect_.is_empty()); | 210 RTC_DCHECK(desktop_rect_.is_empty()); |
158 RTC_DCHECK(duplicators_.empty()); | 211 RTC_DCHECK(duplicators_.empty()); |
159 | 212 |
160 d3d_info_.min_feature_level = static_cast<D3D_FEATURE_LEVEL>(0); | 213 d3d_info_.min_feature_level = static_cast<D3D_FEATURE_LEVEL>(0); |
161 d3d_info_.max_feature_level = static_cast<D3D_FEATURE_LEVEL>(0); | 214 d3d_info_.max_feature_level = static_cast<D3D_FEATURE_LEVEL>(0); |
162 | 215 |
163 std::vector<D3dDevice> devices = D3dDevice::EnumDevices(); | 216 std::vector<D3dDevice> devices = D3dDevice::EnumDevices(); |
164 if (devices.empty()) { | 217 if (devices.empty()) { |
218 LOG(LS_WARNING) << "No D3dDevice found."; | |
165 return false; | 219 return false; |
166 } | 220 } |
167 | 221 |
168 for (size_t i = 0; i < devices.size(); i++) { | 222 for (size_t i = 0; i < devices.size(); i++) { |
169 duplicators_.emplace_back(devices[i]); | |
170 if (!duplicators_.back().Initialize()) { | |
171 return false; | |
172 } | |
173 | |
174 D3D_FEATURE_LEVEL feature_level = | 223 D3D_FEATURE_LEVEL feature_level = |
175 devices[i].d3d_device()->GetFeatureLevel(); | 224 devices[i].d3d_device()->GetFeatureLevel(); |
176 if (d3d_info_.max_feature_level == 0 || | 225 if (d3d_info_.max_feature_level == 0 || |
177 feature_level > d3d_info_.max_feature_level) { | 226 feature_level > d3d_info_.max_feature_level) { |
178 d3d_info_.max_feature_level = feature_level; | 227 d3d_info_.max_feature_level = feature_level; |
179 } | 228 } |
180 if (d3d_info_.min_feature_level == 0 || | 229 if (d3d_info_.min_feature_level == 0 || |
181 feature_level < d3d_info_.min_feature_level) { | 230 feature_level < d3d_info_.min_feature_level) { |
182 d3d_info_.min_feature_level = feature_level; | 231 d3d_info_.min_feature_level = feature_level; |
183 } | 232 } |
184 | 233 |
234 DxgiAdapterDuplicator duplicator(devices[i]); | |
235 if (!duplicator.Initialize()) { | |
236 LOG(LS_WARNING) << "Failed to initialize DxgiAdapterDuplicator on " | |
237 "adapter " | |
238 << i; | |
239 continue; | |
Sergey Ulanov
2017/06/26 23:41:41
Why do we need to keep trying initialization after
Hzj_jie
2017/06/27 04:37:33
This issue happens when a virtual adapter is insta
| |
240 } | |
241 RTC_DCHECK(!duplicator.desktop_rect().is_empty()); | |
242 duplicators_.push_back(std::move(duplicator)); | |
243 | |
185 desktop_rect_.UnionWith(duplicators_.back().desktop_rect()); | 244 desktop_rect_.UnionWith(duplicators_.back().desktop_rect()); |
186 } | 245 } |
187 TranslateRect(); | 246 TranslateRect(); |
188 | 247 |
189 HDC hdc = GetDC(nullptr); | 248 HDC hdc = GetDC(nullptr); |
190 // Use old DPI value if failed. | 249 // Use old DPI value if failed. |
191 if (hdc) { | 250 if (hdc) { |
192 dpi_.set(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY)); | 251 dpi_.set(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY)); |
193 ReleaseDC(nullptr, hdc); | 252 ReleaseDC(nullptr, hdc); |
194 } | 253 } |
195 | 254 |
196 identity_++; | 255 identity_++; |
197 return true; | 256 |
257 if (duplicators_.empty()) { | |
258 LOG(LS_WARNING) << "Cannot initialize any DxgiAdapterDuplicator instance."; | |
259 } | |
260 | |
261 return !duplicators_.empty(); | |
198 } | 262 } |
199 | 263 |
200 void DxgiDuplicatorController::Deinitialize() { | 264 void DxgiDuplicatorController::Deinitialize() { |
201 desktop_rect_ = DesktopRect(); | 265 desktop_rect_ = DesktopRect(); |
202 duplicators_.clear(); | 266 duplicators_.clear(); |
203 resolution_change_detector_.Reset(); | 267 resolution_change_detector_.Reset(); |
204 } | 268 } |
205 | 269 |
206 bool DxgiDuplicatorController::ContextExpired( | 270 bool DxgiDuplicatorController::ContextExpired( |
207 const Context* const context) const { | 271 const Context* const context) const { |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
372 void DxgiDuplicatorController::TranslateRect() { | 436 void DxgiDuplicatorController::TranslateRect() { |
373 const DesktopVector position = | 437 const DesktopVector position = |
374 DesktopVector().subtract(desktop_rect_.top_left()); | 438 DesktopVector().subtract(desktop_rect_.top_left()); |
375 desktop_rect_.Translate(position); | 439 desktop_rect_.Translate(position); |
376 for (auto& duplicator : duplicators_) { | 440 for (auto& duplicator : duplicators_) { |
377 duplicator.TranslateRect(position); | 441 duplicator.TranslateRect(position); |
378 } | 442 } |
379 } | 443 } |
380 | 444 |
381 } // namespace webrtc | 445 } // namespace webrtc |
OLD | NEW |