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 "modules/desktop_capture/win/dxgi_adapter_duplicator.h"
12
13 #include <comdef.h>
14 #include <dxgi.h>
15
16 #include <algorithm>
17
18 #include "modules/desktop_capture/win/desktop_capture_utils.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21
22 namespace webrtc {
23
24 using Microsoft::WRL::ComPtr;
25
26 namespace {
27
IsValidRect(const RECT & rect)28 bool IsValidRect(const RECT& rect) {
29 return rect.right > rect.left && rect.bottom > rect.top;
30 }
31
32 } // namespace
33
DxgiAdapterDuplicator(const D3dDevice & device)34 DxgiAdapterDuplicator::DxgiAdapterDuplicator(const D3dDevice& device)
35 : device_(device) {}
36 DxgiAdapterDuplicator::DxgiAdapterDuplicator(DxgiAdapterDuplicator&&) = default;
37 DxgiAdapterDuplicator::~DxgiAdapterDuplicator() = default;
38
Initialize()39 bool DxgiAdapterDuplicator::Initialize() {
40 if (DoInitialize()) {
41 return true;
42 }
43 duplicators_.clear();
44 return false;
45 }
46
DoInitialize()47 bool DxgiAdapterDuplicator::DoInitialize() {
48 for (int i = 0;; i++) {
49 ComPtr<IDXGIOutput> output;
50 _com_error error =
51 device_.dxgi_adapter()->EnumOutputs(i, output.GetAddressOf());
52 if (error.Error() == DXGI_ERROR_NOT_FOUND) {
53 break;
54 }
55
56 if (error.Error() == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
57 RTC_LOG(LS_WARNING) << "IDXGIAdapter::EnumOutputs returned "
58 << "NOT_CURRENTLY_AVAILABLE. This may happen when "
59 << "running in session 0.";
60 break;
61 }
62
63 if (error.Error() != S_OK || !output) {
64 RTC_LOG(LS_WARNING) << "IDXGIAdapter::EnumOutputs returned an unexpected "
65 << "result: "
66 << desktop_capture::utils::ComErrorToString(error);
67 continue;
68 }
69
70 DXGI_OUTPUT_DESC desc;
71 error = output->GetDesc(&desc);
72 if (error.Error() == S_OK) {
73 if (desc.AttachedToDesktop && IsValidRect(desc.DesktopCoordinates)) {
74 ComPtr<IDXGIOutput1> output1;
75 error = output.As(&output1);
76 if (error.Error() != S_OK || !output1) {
77 RTC_LOG(LS_WARNING)
78 << "Failed to convert IDXGIOutput to IDXGIOutput1, this usually "
79 << "means the system does not support DirectX 11";
80 continue;
81 }
82 DxgiOutputDuplicator duplicator(device_, output1, desc);
83 if (!duplicator.Initialize()) {
84 RTC_LOG(LS_WARNING) << "Failed to initialize DxgiOutputDuplicator on "
85 << "output " << i;
86 continue;
87 }
88
89 duplicators_.push_back(std::move(duplicator));
90 desktop_rect_.UnionWith(duplicators_.back().desktop_rect());
91 } else {
92 RTC_LOG(LS_ERROR) << (desc.AttachedToDesktop ? "Attached" : "Detached")
93 << " output " << i << " ("
94 << desc.DesktopCoordinates.top << ", "
95 << desc.DesktopCoordinates.left << ") - ("
96 << desc.DesktopCoordinates.bottom << ", "
97 << desc.DesktopCoordinates.right << ") is ignored.";
98 }
99 } else {
100 RTC_LOG(LS_WARNING) << "Failed to get output description of device " << i
101 << ", ignore.";
102 }
103 }
104
105 if (duplicators_.empty()) {
106 RTC_LOG(LS_WARNING)
107 << "Cannot initialize any DxgiOutputDuplicator instance.";
108 }
109
110 return !duplicators_.empty();
111 }
112
Setup(Context * context)113 void DxgiAdapterDuplicator::Setup(Context* context) {
114 RTC_DCHECK(context->contexts.empty());
115 context->contexts.resize(duplicators_.size());
116 for (size_t i = 0; i < duplicators_.size(); i++) {
117 duplicators_[i].Setup(&context->contexts[i]);
118 }
119 }
120
Unregister(const Context * const context)121 void DxgiAdapterDuplicator::Unregister(const Context* const context) {
122 RTC_DCHECK_EQ(context->contexts.size(), duplicators_.size());
123 for (size_t i = 0; i < duplicators_.size(); i++) {
124 duplicators_[i].Unregister(&context->contexts[i]);
125 }
126 }
127
Duplicate(Context * context,SharedDesktopFrame * target)128 bool DxgiAdapterDuplicator::Duplicate(Context* context,
129 SharedDesktopFrame* target) {
130 RTC_DCHECK_EQ(context->contexts.size(), duplicators_.size());
131 for (size_t i = 0; i < duplicators_.size(); i++) {
132 if (!duplicators_[i].Duplicate(&context->contexts[i],
133 duplicators_[i].desktop_rect().top_left(),
134 target)) {
135 return false;
136 }
137 }
138 return true;
139 }
140
DuplicateMonitor(Context * context,int monitor_id,SharedDesktopFrame * target)141 bool DxgiAdapterDuplicator::DuplicateMonitor(Context* context,
142 int monitor_id,
143 SharedDesktopFrame* target) {
144 RTC_DCHECK_GE(monitor_id, 0);
145 RTC_DCHECK_LT(monitor_id, duplicators_.size());
146 RTC_DCHECK_EQ(context->contexts.size(), duplicators_.size());
147 return duplicators_[monitor_id].Duplicate(&context->contexts[monitor_id],
148 DesktopVector(), target);
149 }
150
ScreenRect(int id) const151 DesktopRect DxgiAdapterDuplicator::ScreenRect(int id) const {
152 RTC_DCHECK_GE(id, 0);
153 RTC_DCHECK_LT(id, duplicators_.size());
154 return duplicators_[id].desktop_rect();
155 }
156
GetDeviceName(int id) const157 const std::string& DxgiAdapterDuplicator::GetDeviceName(int id) const {
158 RTC_DCHECK_GE(id, 0);
159 RTC_DCHECK_LT(id, duplicators_.size());
160 return duplicators_[id].device_name();
161 }
162
screen_count() const163 int DxgiAdapterDuplicator::screen_count() const {
164 return static_cast<int>(duplicators_.size());
165 }
166
GetNumFramesCaptured() const167 int64_t DxgiAdapterDuplicator::GetNumFramesCaptured() const {
168 int64_t min = INT64_MAX;
169 for (const auto& duplicator : duplicators_) {
170 min = std::min(min, duplicator.num_frames_captured());
171 }
172
173 return min;
174 }
175
TranslateRect(const DesktopVector & position)176 void DxgiAdapterDuplicator::TranslateRect(const DesktopVector& position) {
177 desktop_rect_.Translate(position);
178 RTC_DCHECK_GE(desktop_rect_.left(), 0);
179 RTC_DCHECK_GE(desktop_rect_.top(), 0);
180 for (auto& duplicator : duplicators_) {
181 duplicator.TranslateRect(position);
182 }
183 }
184
185 } // namespace webrtc
186