OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | |
3 * | |
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 | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/modules/desktop_capture/win/dxgi_duplicator_controller.h" | |
12 | |
13 #include <windows.h> | |
14 | |
15 #include <algorithm> | |
16 | |
17 #include "webrtc/base/checks.h" | |
18 | |
19 namespace webrtc { | |
20 | |
21 DxgiDuplicatorController::Context::~Context() { | |
22 DxgiDuplicatorController::Instance()->Unregister(this); | |
23 } | |
24 | |
25 // static | |
26 DxgiDuplicatorController* DxgiDuplicatorController::Instance() { | |
27 // The static instance won't be deleted to ensure it can be used by other | |
28 // threads even during program exiting. | |
29 static DxgiDuplicatorController* instance = new DxgiDuplicatorController(); | |
30 return instance; | |
31 } | |
32 | |
33 DxgiDuplicatorController::DxgiDuplicatorController() = default; | |
34 | |
35 DxgiDuplicatorController::~DxgiDuplicatorController() { | |
36 rtc::CritScope lock(&lock_); | |
37 Deinitialize(); | |
38 } | |
39 | |
40 bool DxgiDuplicatorController::IsSupported() { | |
41 rtc::CritScope lock(&lock_); | |
42 return Initialize(); | |
43 } | |
44 | |
45 DesktopVector DxgiDuplicatorController::dpi() { | |
46 rtc::CritScope lock(&lock_); | |
47 if (Initialize()) { | |
48 return dpi_; | |
49 } | |
50 return DesktopVector(); | |
51 } | |
52 | |
53 DesktopRect DxgiDuplicatorController::desktop_rect() { | |
54 rtc::CritScope lock(&lock_); | |
55 if (Initialize()) { | |
56 return desktop_rect_; | |
57 } | |
58 return DesktopRect(); | |
59 } | |
60 | |
61 DesktopSize DxgiDuplicatorController::desktop_size() { | |
62 DesktopRect rect = desktop_rect(); | |
63 return DesktopSize(rect.right(), rect.bottom()); | |
64 } | |
65 | |
66 DesktopRect DxgiDuplicatorController::ScreenRect(int id) { | |
67 RTC_DCHECK(id >= 0); | |
68 rtc::CritScope lock(&lock_); | |
69 if (!Initialize()) { | |
70 return DesktopRect(); | |
71 } | |
72 for (size_t i = 0; i < duplicators_.size(); i++) { | |
73 if (id >= duplicators_[i].screen_count()) { | |
74 id -= duplicators_[i].screen_count(); | |
75 } else { | |
76 return duplicators_[i].ScreenRect(id); | |
77 } | |
78 } | |
79 return DesktopRect(); | |
80 } | |
81 | |
82 int DxgiDuplicatorController::ScreenCount() { | |
83 rtc::CritScope lock(&lock_); | |
84 if (!Initialize()) { | |
85 return 0; | |
86 } | |
87 int result = 0; | |
88 for (auto& duplicator : duplicators_) { | |
89 result += duplicator.screen_count(); | |
90 } | |
91 return result; | |
92 } | |
93 | |
94 void DxgiDuplicatorController::Unregister(const Context* const context) { | |
95 rtc::CritScope lock(&lock_); | |
96 if (ContextExpired(context)) { | |
97 // The Context has not been setup after a recent initialization, so it | |
98 // should not been registered in duplicators. | |
99 return; | |
100 } | |
101 for (size_t i = 0; i < duplicators_.size(); i++) { | |
102 duplicators_[i].Unregister(&context->contexts_[i]); | |
103 } | |
104 } | |
105 | |
106 bool DxgiDuplicatorController::Initialize() { | |
107 if (!duplicators_.empty()) { | |
108 return true; | |
109 } | |
110 | |
111 if (DoInitialize()) { | |
112 return true; | |
113 } | |
114 Deinitialize(); | |
115 return false; | |
116 } | |
117 | |
118 bool DxgiDuplicatorController::DoInitialize() { | |
119 RTC_DCHECK(desktop_rect_.is_empty()); | |
120 RTC_DCHECK(duplicators_.empty()); | |
121 | |
122 std::vector<D3dDevice> devices = D3dDevice::EnumDevices(); | |
123 if (devices.empty()) { | |
124 return false; | |
125 } | |
126 | |
127 for (size_t i = 0; i < devices.size(); i++) { | |
128 duplicators_.emplace_back(devices[i]); | |
129 if (!duplicators_.back().Initialize()) { | |
130 return false; | |
131 } | |
132 if (desktop_rect_.is_empty()) { | |
133 desktop_rect_ = duplicators_.back().desktop_rect(); | |
134 } else { | |
135 const DesktopRect& left = desktop_rect_; | |
136 const DesktopRect& right = duplicators_.back().desktop_rect(); | |
137 desktop_rect_ = | |
138 DesktopRect::MakeLTRB(std::min(left.left(), right.left()), | |
139 std::min(left.top(), right.top()), | |
140 std::max(left.right(), right.right()), | |
141 std::max(left.bottom(), right.bottom())); | |
142 } | |
143 } | |
144 | |
145 HDC hdc = GetDC(nullptr); | |
146 // Use old DPI value if failed. | |
147 if (hdc) { | |
148 dpi_.set(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY)); | |
149 ReleaseDC(nullptr, hdc); | |
150 } | |
151 | |
152 identity_++; | |
153 return true; | |
154 } | |
155 | |
156 void DxgiDuplicatorController::Deinitialize() { | |
157 desktop_rect_ = DesktopRect(); | |
158 duplicators_.clear(); | |
159 } | |
160 | |
161 bool DxgiDuplicatorController::ContextExpired( | |
162 const Context* const context) const { | |
163 return context->identity_ != identity_ || | |
164 context->contexts_.size() != duplicators_.size(); | |
165 } | |
166 | |
167 void DxgiDuplicatorController::Setup(Context* context) { | |
168 if (ContextExpired(context)) { | |
169 context->contexts_.clear(); | |
170 context->contexts_.resize(duplicators_.size()); | |
171 for (size_t i = 0; i < duplicators_.size(); i++) { | |
172 duplicators_[i].Setup(&context->contexts_[i]); | |
173 } | |
174 context->identity_ = identity_; | |
175 } | |
176 } | |
177 | |
178 bool DxgiDuplicatorController::Duplicate(Context* context, | |
179 const DesktopFrame* last_frame, | |
180 DesktopFrame* target) { | |
181 return DoDuplicate(context, -1, last_frame, target); | |
182 } | |
183 | |
184 bool DxgiDuplicatorController::DuplicateMonitor(Context* context, | |
185 int monitor_id, | |
186 const DesktopFrame* last_frame, | |
187 DesktopFrame* target) { | |
188 RTC_DCHECK(monitor_id >= 0); | |
Sergey Ulanov
2016/08/06 01:27:57
RTC_DCHECK_GE
Hzj_jie
2016/08/08 00:16:08
Done.
| |
189 return DoDuplicate(context, monitor_id, last_frame, target); | |
190 } | |
191 | |
192 bool DxgiDuplicatorController::DoDuplicate(Context* context, | |
193 int monitor_id, | |
194 const DesktopFrame* last_frame, | |
195 DesktopFrame* target) { | |
196 RTC_DCHECK(target); | |
197 if (last_frame && !target->size().equals(last_frame->size())) { | |
198 return false; | |
199 } | |
200 target->mutable_updated_region()->Clear(); | |
201 rtc::CritScope lock(&lock_); | |
202 if (!Initialize()) { | |
203 // Cannot initialize COM components now, display mode may be changing. | |
204 return false; | |
205 } | |
206 Setup(context); | |
207 if (monitor_id < 0) { | |
208 // Capture entire screen. | |
209 for (size_t i = 0; i < duplicators_.size(); i++) { | |
210 if (!duplicators_[i].Duplicate(&context->contexts_[i], last_frame, | |
211 target)) { | |
212 Deinitialize(); | |
213 return false; | |
214 } | |
215 } | |
216 target->set_dpi(dpi()); | |
217 return true; | |
218 } | |
219 | |
220 // Capture one monitor. | |
221 for (size_t i = 0; i < duplicators_.size() && i < context->contexts_.size(); | |
222 i++) { | |
223 if (monitor_id >= duplicators_[i].screen_count()) { | |
224 monitor_id -= duplicators_[i].screen_count(); | |
225 } else { | |
226 if (duplicators_[i].DuplicateMonitor(&context->contexts_[i], monitor_id, | |
227 last_frame, target)) { | |
228 target->set_dpi(dpi()); | |
229 return true; | |
230 } | |
231 Deinitialize(); | |
232 return false; | |
233 } | |
234 } | |
235 // id >= ScreenCount(). This is a user error, so we do not need to | |
Sergey Ulanov
2016/08/06 01:27:57
this may not a "user error". It could be that a sc
Hzj_jie
2016/08/08 00:16:08
Done. Updated in ScreenCapturerWinDirectx. We can
| |
236 // deinitialize. | |
237 return false; | |
238 } | |
239 | |
240 } // namespace webrtc | |
OLD | NEW |