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

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

Issue 1845113002: DirectX based screen capturer logic (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Lint errors Created 4 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
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698