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/desktop_frame_win_dxgi.h" | |
12 | |
13 #include <string.h> | |
14 | |
15 #include <comdef.h> | |
16 #include <D3D11.h> | |
17 | |
18 #include "webrtc/base/checks.h" | |
19 #include "webrtc/base/scoped_ptr.h" | |
20 #include "webrtc/system_wrappers/include/logging.h" | |
21 | |
22 namespace webrtc { | |
23 | |
24 using std::unique_ptr; | |
25 using Microsoft::WRL::ComPtr; | |
26 | |
27 namespace { | |
28 | |
29 ID3D11Device* device = nullptr; | |
30 ID3D11DeviceContext* context = nullptr; | |
31 | |
32 } // namespace | |
33 | |
34 void DesktopFrameWinDxgi::Initialize(ID3D11Device* dev, | |
35 ID3D11DeviceContext* ctx) { | |
36 RTC_DCHECK(dev != nullptr); | |
37 RTC_DCHECK(ctx != nullptr); | |
38 RTC_DCHECK(device == nullptr); | |
39 RTC_DCHECK(context == nullptr); | |
40 | |
41 device = dev; | |
42 context = ctx; | |
43 } | |
44 | |
45 DesktopFrameWinDxgi::DesktopFrameWinDxgi(DesktopSize size, | |
46 int stride, | |
47 SharedMemory* shared_memory) | |
48 : DesktopFrame(size, | |
49 stride, | |
50 nullptr, // Data will always be returned from rect_.pBits. | |
51 shared_memory) { | |
52 RTC_DCHECK(device != nullptr); | |
53 RTC_DCHECK(context != nullptr); | |
54 } | |
55 | |
56 DesktopFrameWinDxgi::~DesktopFrameWinDxgi() {} | |
57 | |
58 unique_ptr<DesktopFrameWinDxgi> DesktopFrameWinDxgi::Create( | |
59 DesktopSize size, | |
60 SharedMemoryFactory* shared_memory_factory) { | |
61 int stride = size.width() * DesktopFrame::kBytesPerPixel; | |
62 int buffer_size = stride * size.height(); | |
63 rtc::scoped_ptr<SharedMemory> shared_memory; | |
64 if (shared_memory_factory != nullptr) { | |
65 shared_memory = shared_memory_factory->CreateSharedMemory(buffer_size); | |
66 if (!shared_memory) { | |
67 LOG(LS_ERROR) << "Failed to create shared memory with size " | |
68 << buffer_size; | |
69 // Well, we are still able to work without shared_memory. | |
70 } | |
71 } else { | |
72 LOG(LS_WARNING) << "No SharedMemoryFactory provided"; | |
73 } | |
74 | |
75 return unique_ptr<DesktopFrameWinDxgi>( | |
76 new DesktopFrameWinDxgi(size, stride, shared_memory.release())); | |
77 } | |
78 | |
79 bool DesktopFrameWinDxgi::Capture(const DXGI_OUTDUPL_FRAME_INFO& frame_info, | |
80 IDXGIResource* resource) { | |
81 if (resource == nullptr || frame_info.AccumulatedFrames == 0) { | |
82 // Nothing updated, but current data is still valid. | |
83 return false; | |
84 } | |
85 | |
86 ComPtr<ID3D11Texture2D> texture; | |
87 _com_error err(resource->QueryInterface( | |
88 __uuidof(ID3D11Texture2D), | |
89 reinterpret_cast<void**>(texture.GetAddressOf()))); | |
90 if (err.Error() != S_OK || !texture) { | |
91 LOG(LS_ERROR) << "Failed to convert IDXGIResource to ID3D11Texture2D, " | |
92 "error " | |
93 << err.ErrorMessage() << ", code " << err.Error(); | |
94 return false; | |
95 } | |
96 | |
97 // AcquireNextFrame returns a CPU inaccessible IDXGIResource, so we need to | |
98 // make a copy. | |
99 if (!CreateTexture(texture.Get())) { | |
100 return false; | |
101 } | |
102 | |
103 context->CopyResource(static_cast<ID3D11Resource*>(stage_.Get()), | |
104 static_cast<ID3D11Resource*>(texture.Get())); | |
105 | |
106 rect_ = {0}; | |
107 err = _com_error(surface_->Map(&rect_, DXGI_MAP_READ)); | |
108 if (err.Error() != S_OK) { | |
109 LOG(LS_ERROR) << "Failed to map the IDXGISurface to a bitmap, error " | |
110 << err.ErrorMessage() << ", code " << err.Error(); | |
111 return false; | |
112 } | |
113 | |
114 if (rect_.Pitch != stride()) { | |
115 // Unfortunately we cannot check whether the buffer size is also consistent. | |
116 LOG(LS_ERROR) << "System returns a different size of bitmap, with pitch " | |
117 << rect_.Pitch; | |
118 return false; | |
119 } | |
120 | |
121 if (shared_memory() != nullptr) { | |
Sergey Ulanov
2016/04/08 21:22:26
There are two cases:
1. SharedMemoryFactory is se
Hzj_jie
2016/04/11 22:19:16
There are two reasons I used current solution.
1.
Sergey Ulanov
2016/04/12 03:00:46
ScreenCaptureFrameQueue is not the only place wher
Hzj_jie
2016/04/12 17:40:40
For the reason we make a copy to stage_, it's a Wi
| |
122 // If there is a shared_memory, we need to copy the data to it, so other | |
123 // processes can use it. | |
124 memcpy(shared_memory()->data(), rect_.pBits, shared_memory()->size()); | |
Sergey Ulanov
2016/04/08 21:22:26
This copies the whole frame every time. It should
Hzj_jie
2016/04/11 22:19:16
What's my initial plan is to move all variables fr
Sergey Ulanov
2016/04/12 03:00:47
IMO ScreenCapturerFrameQueue would a better place
| |
125 } | |
126 // surface_->Unmap will be called next time we capture an image to avoid | |
127 // memory copy without shared_memory. | |
128 return true; | |
129 } | |
130 | |
131 bool DesktopFrameWinDxgi::CreateTexture(ID3D11Texture2D* texture) { | |
132 RTC_DCHECK(texture != nullptr); | |
133 D3D11_TEXTURE2D_DESC desc; | |
Sergey Ulanov
2016/04/08 21:22:26
memset the struct to 0?
Hzj_jie
2016/04/11 22:19:16
Done.
| |
134 texture->GetDesc(&desc); | |
135 // TODO(zijiehe): Debug | |
136 // desc.ArraySize = 1; // Capture only one frame. | |
137 desc.BindFlags = 0; | |
138 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; | |
139 // desc.MipLevels = 1; | |
140 desc.MiscFlags = 0; | |
141 // desc.SampleDesc.Count = 1; | |
142 // desc.SampleDesc.Quality = 0; | |
Sergey Ulanov
2016/04/08 21:22:26
remove commented code?
Hzj_jie
2016/04/11 22:19:16
Yes, should be, sorry.
| |
143 desc.Usage = D3D11_USAGE_STAGING; | |
144 if (stage_) { | |
145 // Make sure stage_ and surface_ are always pointing to a same object. | |
146 // We need an ID3D11Texture2D instance for | |
147 // ID3D11DeviceContext::CopySubresourceRegion, but an IDXGISurface for | |
148 // IDXGISurface::Map. | |
149 { | |
150 ComPtr<IUnknown> left; | |
151 ComPtr<IUnknown> right; | |
152 bool left_result = SUCCEEDED(stage_.As(&left)); | |
153 bool right_result = SUCCEEDED(surface_.As(&right)); | |
154 RTC_DCHECK(left_result); | |
155 RTC_DCHECK(right_result); | |
156 RTC_DCHECK(left.Get() == right.Get()); | |
157 } | |
158 | |
159 // This buffer should be used already. | |
160 _com_error err = _com_error(surface_->Unmap()); | |
161 if (err.Error() == S_OK) { | |
162 D3D11_TEXTURE2D_DESC orgi_desc; | |
163 stage_->GetDesc(&orgi_desc); | |
164 if (memcmp(&desc, &orgi_desc, sizeof(D3D11_TEXTURE2D_DESC)) == 0) { | |
165 return true; | |
166 } | |
167 } else { | |
168 // Let's recreate stage_ and surface_ later. | |
169 LOG(LS_ERROR) << "Failed to unmap surface, error " << err.ErrorMessage() | |
170 << ", code " << err.Error(); | |
171 } | |
172 | |
173 stage_.Reset(); | |
174 surface_.Reset(); | |
175 } else { | |
176 RTC_DCHECK(!surface_); | |
177 } | |
178 | |
179 _com_error err = _com_error( | |
180 device->CreateTexture2D(&desc, nullptr, stage_.GetAddressOf())); | |
181 if (err.Error() != S_OK || !stage_) { | |
182 LOG(LS_ERROR) << "Failed to create a new ID3D11Texture2D as stage, " | |
183 "error " | |
184 << err.ErrorMessage() << ", code " << err.Error(); | |
185 return false; | |
186 } | |
187 | |
188 err = _com_error(stage_.As(&surface_)); | |
189 if (err.Error() != S_OK || !surface_) { | |
190 LOG(LS_ERROR) << "Failed to convert ID3D11Texture2D to IDXGISurface, " | |
191 "error " | |
192 << err.ErrorMessage() << ", code " << err.Error(); | |
193 return false; | |
194 } | |
195 | |
196 return true; | |
197 } | |
198 | |
199 } // namespace webrtc | |
OLD | NEW |