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

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

Issue 2530303002: Use RotateDesktopFrame in DirectX capturer (Closed)
Patch Set: Sync latest changes Created 4 years 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
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_output_duplicator.h" 11 #include "webrtc/modules/desktop_capture/win/dxgi_output_duplicator.h"
12 12
13 #include <string.h> 13 #include <string.h>
14 14
15 #include <unknwn.h> 15 #include <unknwn.h>
16 #include <DXGI.h>
16 #include <DXGIFormat.h> 17 #include <DXGIFormat.h>
17 #include <Windows.h> 18 #include <Windows.h>
18 19
19 #include <algorithm> 20 #include <algorithm>
20 21
21 #include "webrtc/base/checks.h" 22 #include "webrtc/base/checks.h"
22 #include "webrtc/base/logging.h" 23 #include "webrtc/base/logging.h"
23 #include "webrtc/modules/desktop_capture/win/dxgi_texture_mapping.h" 24 #include "webrtc/modules/desktop_capture/win/dxgi_texture_mapping.h"
24 #include "webrtc/modules/desktop_capture/win/dxgi_texture_staging.h" 25 #include "webrtc/modules/desktop_capture/win/dxgi_texture_staging.h"
25 26
26 namespace webrtc { 27 namespace webrtc {
27 28
28 using Microsoft::WRL::ComPtr; 29 using Microsoft::WRL::ComPtr;
29 30
30 namespace { 31 namespace {
31 32
32 // Timeout for AcquireNextFrame() call. 33 // Timeout for AcquireNextFrame() call.
33 const int kAcquireTimeoutMs = 10; 34 const int kAcquireTimeoutMs = 10;
34 35
35 DesktopRect RECTToDesktopRect(const RECT& rect) { 36 DesktopRect RECTToDesktopRect(const RECT& rect) {
36 return DesktopRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom); 37 return DesktopRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
37 } 38 }
38 39
40 Rotation DxgiRotationToRotation(DXGI_MODE_ROTATION rotation) {
41 switch (rotation) {
42 case DXGI_MODE_ROTATION_IDENTITY:
43 case DXGI_MODE_ROTATION_UNSPECIFIED:
44 return Rotation::CLOCK_WISE_0;
45 case DXGI_MODE_ROTATION_ROTATE90:
46 return Rotation::CLOCK_WISE_90;
47 case DXGI_MODE_ROTATION_ROTATE180:
48 return Rotation::CLOCK_WISE_180;
49 case DXGI_MODE_ROTATION_ROTATE270:
50 return Rotation::CLOCK_WISE_270;
51 }
52
53 RTC_NOTREACHED();
54 return Rotation::CLOCK_WISE_0;
55 }
56
57 // Translates |rect| with the reverse of |offset|
58 DesktopRect ReverseTranslate(DesktopRect rect, DesktopVector offset) {
59 rect.Translate(-offset.x(), -offset.y());
60 return rect;
61 }
62
39 } // namespace 63 } // namespace
40 64
41 DxgiOutputDuplicator::DxgiOutputDuplicator(const D3dDevice& device, 65 DxgiOutputDuplicator::DxgiOutputDuplicator(const D3dDevice& device,
42 const ComPtr<IDXGIOutput1>& output, 66 const ComPtr<IDXGIOutput1>& output,
43 const DXGI_OUTPUT_DESC& desc) 67 const DXGI_OUTPUT_DESC& desc)
44 : device_(device), 68 : device_(device),
45 output_(output), 69 output_(output),
46 desktop_rect_(RECTToDesktopRect(desc.DesktopCoordinates)) { 70 desktop_rect_(RECTToDesktopRect(desc.DesktopCoordinates)) {
47 RTC_DCHECK(output_); 71 RTC_DCHECK(output_);
48 RTC_DCHECK(!desktop_rect_.is_empty()); 72 RTC_DCHECK(!desktop_rect_.is_empty());
49 RTC_DCHECK(desktop_rect_.left() >= 0 && desktop_rect_.top() >= 0); 73 RTC_DCHECK(desktop_rect_.left() >= 0 && desktop_rect_.top() >= 0);
50 } 74 }
51 75
52 DxgiOutputDuplicator::DxgiOutputDuplicator(DxgiOutputDuplicator&& other) = 76 DxgiOutputDuplicator::DxgiOutputDuplicator(DxgiOutputDuplicator&& other) =
53 default; 77 default;
54 78
55 DxgiOutputDuplicator::~DxgiOutputDuplicator() { 79 DxgiOutputDuplicator::~DxgiOutputDuplicator() {
56 if (duplication_) { 80 if (duplication_) {
57 duplication_->ReleaseFrame(); 81 duplication_->ReleaseFrame();
58 } 82 }
59 texture_.reset(); 83 texture_.reset();
60 } 84 }
61 85
62 bool DxgiOutputDuplicator::Initialize() { 86 bool DxgiOutputDuplicator::Initialize() {
63 if (DuplicateOutput()) { 87 if (DuplicateOutput()) {
88 DesktopSize unrotated_size =
89 RotateSize(desktop_rect().size(), ReverseRotation(rotation_));
64 if (desc_.DesktopImageInSystemMemory) { 90 if (desc_.DesktopImageInSystemMemory) {
65 texture_.reset(new DxgiTextureMapping(desktop_rect_, duplication_.Get())); 91 texture_.reset(
92 new DxgiTextureMapping(unrotated_size, duplication_.Get()));
66 } else { 93 } else {
67 texture_.reset(new DxgiTextureStaging(desktop_rect_, device_)); 94 texture_.reset(new DxgiTextureStaging(unrotated_size, device_));
68 } 95 }
69 return true; 96 return true;
70 } else { 97 } else {
71 duplication_.Reset(); 98 duplication_.Reset();
72 return false; 99 return false;
73 } 100 }
74 } 101 }
75 102
76 bool DxgiOutputDuplicator::DuplicateOutput() { 103 bool DxgiOutputDuplicator::DuplicateOutput() {
77 RTC_DCHECK(!duplication_); 104 RTC_DCHECK(!duplication_);
(...skipping 19 matching lines...) Expand all
97 if (static_cast<int>(desc_.ModeDesc.Width) != desktop_rect_.width() || 124 if (static_cast<int>(desc_.ModeDesc.Width) != desktop_rect_.width() ||
98 static_cast<int>(desc_.ModeDesc.Height) != desktop_rect_.height()) { 125 static_cast<int>(desc_.ModeDesc.Height) != desktop_rect_.height()) {
99 LOG(LS_ERROR) << "IDXGIDuplicateOutput does not return a same size as its " 126 LOG(LS_ERROR) << "IDXGIDuplicateOutput does not return a same size as its "
100 "IDXGIOutput1, size returned by IDXGIDuplicateOutput is " 127 "IDXGIOutput1, size returned by IDXGIDuplicateOutput is "
101 << desc_.ModeDesc.Width << " x " << desc_.ModeDesc.Height 128 << desc_.ModeDesc.Width << " x " << desc_.ModeDesc.Height
102 << ", size returned by IDXGIOutput1 is " 129 << ", size returned by IDXGIOutput1 is "
103 << desktop_rect_.width() << " x " << desktop_rect_.height(); 130 << desktop_rect_.width() << " x " << desktop_rect_.height();
104 return false; 131 return false;
105 } 132 }
106 133
134 rotation_ = DxgiRotationToRotation(desc_.Rotation);
135 unrotated_size_ =
136 RotateSize(desktop_rect_.size(), ReverseRotation(rotation_));
137
107 return true; 138 return true;
108 } 139 }
109 140
110 bool DxgiOutputDuplicator::ReleaseFrame() { 141 bool DxgiOutputDuplicator::ReleaseFrame() {
111 RTC_DCHECK(duplication_); 142 RTC_DCHECK(duplication_);
112 _com_error error = duplication_->ReleaseFrame(); 143 _com_error error = duplication_->ReleaseFrame();
113 if (error.Error() != S_OK) { 144 if (error.Error() != S_OK) {
114 LOG(LS_ERROR) << "Failed to release frame from IDXGIOutputDuplication, " 145 LOG(LS_ERROR) << "Failed to release frame from IDXGIOutputDuplication, "
115 "error" 146 "error"
116 << error.ErrorMessage() << ", code " << error.Error(); 147 << error.ErrorMessage() << ", code " << error.Error();
(...skipping 18 matching lines...) Expand all
135 memset(&frame_info, 0, sizeof(frame_info)); 166 memset(&frame_info, 0, sizeof(frame_info));
136 ComPtr<IDXGIResource> resource; 167 ComPtr<IDXGIResource> resource;
137 _com_error error = duplication_->AcquireNextFrame( 168 _com_error error = duplication_->AcquireNextFrame(
138 kAcquireTimeoutMs, &frame_info, resource.GetAddressOf()); 169 kAcquireTimeoutMs, &frame_info, resource.GetAddressOf());
139 if (error.Error() != S_OK && error.Error() != DXGI_ERROR_WAIT_TIMEOUT) { 170 if (error.Error() != S_OK && error.Error() != DXGI_ERROR_WAIT_TIMEOUT) {
140 LOG(LS_ERROR) << "Failed to capture frame, error " << error.ErrorMessage() 171 LOG(LS_ERROR) << "Failed to capture frame, error " << error.ErrorMessage()
141 << ", code " << error.Error(); 172 << ", code " << error.Error();
142 return false; 173 return false;
143 } 174 }
144 175
145 // We need to merge updated region with the one from last frame, since current 176 // We need to merge updated region with the one from context, but only spread
146 // frame contains the content one frame before. Note, this is for double 177 // updated region from current frame. So keeps a copy of updated region from
147 // buffering implementation, as what we have in ScreenCapturerWinDirectx. If 178 // context here.
148 // a consumer uses single buffering, we should clear context->updated_region
149 // after it has been merged to updated_region.
150 DesktopRegion updated_region; 179 DesktopRegion updated_region;
151 updated_region.Swap(&context->updated_region); 180 updated_region.Swap(&context->updated_region);
152 if (error.Error() == S_OK && 181 if (error.Error() == S_OK &&
153 frame_info.AccumulatedFrames > 0 && 182 frame_info.AccumulatedFrames > 0 &&
154 resource) { 183 resource) {
155 DetectUpdatedRegion(frame_info, offset, &context->updated_region); 184 DetectUpdatedRegion(frame_info, offset, &context->updated_region);
156 if (!texture_->CopyFrom(frame_info, resource.Get(), 185 if (!texture_->CopyFrom(frame_info, resource.Get())) {
157 context->updated_region)) {
158 return false; 186 return false;
159 } 187 }
160 SpreadContextChange(context); 188 SpreadContextChange(context);
161 updated_region.AddRegion(context->updated_region); 189 updated_region.AddRegion(context->updated_region);
162 190
163 const DesktopFrame& source = texture_->AsDesktopFrame(); 191 const DesktopFrame& source = texture_->AsDesktopFrame();
164 for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd(); 192 if (rotation_ != Rotation::CLOCK_WISE_0) {
165 it.Advance()) { 193 for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd();
166 target->CopyPixelsFrom( 194 it.Advance()) {
167 source, SourceRect(it.rect()).top_left(), it.rect()); 195 const DesktopRect source_rect =
196 RotateRect(ReverseTranslate(it.rect(), offset),
197 desktop_rect().size(), ReverseRotation(rotation_));
198 RotateDesktopFrame(source, source_rect, rotation_, offset, target);
199 }
200 } else {
201 for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd();
202 it.Advance()) {
203 target->CopyPixelsFrom(
204 source, ReverseTranslate(it.rect(), offset).top_left(), it.rect());
205 }
168 } 206 }
169 last_frame_ = target->Share(); 207 last_frame_ = target->Share();
170 last_frame_offset_ = offset; 208 last_frame_offset_ = offset;
171 target->mutable_updated_region()->AddRegion(updated_region); 209 target->mutable_updated_region()->AddRegion(updated_region);
172 return texture_->Release() && ReleaseFrame(); 210 return texture_->Release() && ReleaseFrame();
173 } 211 }
174 212
175 if (last_frame_) { 213 if (last_frame_) {
176 // No change since last frame or AcquireNextFrame() timed out, we will 214 // No change since last frame or AcquireNextFrame() timed out, we will
177 // export last frame to the target. 215 // export last frame to the target.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 DesktopRegion* updated_region) { 249 DesktopRegion* updated_region) {
212 RTC_DCHECK(updated_region); 250 RTC_DCHECK(updated_region);
213 updated_region->Clear(); 251 updated_region->Clear();
214 if (frame_info.TotalMetadataBufferSize == 0) { 252 if (frame_info.TotalMetadataBufferSize == 0) {
215 // This should not happen, since frame_info.AccumulatedFrames > 0. 253 // This should not happen, since frame_info.AccumulatedFrames > 0.
216 LOG(LS_ERROR) << "frame_info.AccumulatedFrames > 0, " 254 LOG(LS_ERROR) << "frame_info.AccumulatedFrames > 0, "
217 "but TotalMetadataBufferSize == 0"; 255 "but TotalMetadataBufferSize == 0";
218 return false; 256 return false;
219 } 257 }
220 258
221 if (metadata.capacity() < frame_info.TotalMetadataBufferSize) { 259 if (metadata_.capacity() < frame_info.TotalMetadataBufferSize) {
222 metadata.clear(); // Avoid data copy 260 metadata_.clear(); // Avoid data copy
223 metadata.reserve(frame_info.TotalMetadataBufferSize); 261 metadata_.reserve(frame_info.TotalMetadataBufferSize);
224 } 262 }
225 263
226 UINT buff_size = 0; 264 UINT buff_size = 0;
227 DXGI_OUTDUPL_MOVE_RECT* move_rects = 265 DXGI_OUTDUPL_MOVE_RECT* move_rects =
228 reinterpret_cast<DXGI_OUTDUPL_MOVE_RECT*>(metadata.data()); 266 reinterpret_cast<DXGI_OUTDUPL_MOVE_RECT*>(metadata_.data());
229 size_t move_rects_count = 0; 267 size_t move_rects_count = 0;
230 _com_error error = duplication_->GetFrameMoveRects( 268 _com_error error = duplication_->GetFrameMoveRects(
231 static_cast<UINT>(metadata.capacity()), move_rects, &buff_size); 269 static_cast<UINT>(metadata_.capacity()), move_rects, &buff_size);
232 if (error.Error() != S_OK) { 270 if (error.Error() != S_OK) {
233 LOG(LS_ERROR) << "Failed to get move rectangles, error " 271 LOG(LS_ERROR) << "Failed to get move rectangles, error "
234 << error.ErrorMessage() << ", code " << error.Error(); 272 << error.ErrorMessage() << ", code " << error.Error();
235 return false; 273 return false;
236 } 274 }
237 move_rects_count = buff_size / sizeof(DXGI_OUTDUPL_MOVE_RECT); 275 move_rects_count = buff_size / sizeof(DXGI_OUTDUPL_MOVE_RECT);
238 276
239 RECT* dirty_rects = reinterpret_cast<RECT*>(metadata.data() + buff_size); 277 RECT* dirty_rects = reinterpret_cast<RECT*>(metadata_.data() + buff_size);
240 size_t dirty_rects_count = 0; 278 size_t dirty_rects_count = 0;
241 error = duplication_->GetFrameDirtyRects( 279 error = duplication_->GetFrameDirtyRects(
242 static_cast<UINT>(metadata.capacity()) - buff_size, dirty_rects, 280 static_cast<UINT>(metadata_.capacity()) - buff_size, dirty_rects,
243 &buff_size); 281 &buff_size);
244 if (error.Error() != S_OK) { 282 if (error.Error() != S_OK) {
245 LOG(LS_ERROR) << "Failed to get dirty rectangles, error " 283 LOG(LS_ERROR) << "Failed to get dirty rectangles, error "
246 << error.ErrorMessage() << ", code " << error.Error(); 284 << error.ErrorMessage() << ", code " << error.Error();
247 return false; 285 return false;
248 } 286 }
249 dirty_rects_count = buff_size / sizeof(RECT); 287 dirty_rects_count = buff_size / sizeof(RECT);
250 288
251 while (move_rects_count > 0) { 289 while (move_rects_count > 0) {
252 updated_region->AddRect(DesktopRect::MakeXYWH( 290 updated_region->AddRect(
253 move_rects->SourcePoint.x, move_rects->SourcePoint.y, 291 RotateRect(DesktopRect::MakeXYWH(move_rects->SourcePoint.x,
254 move_rects->DestinationRect.right - move_rects->DestinationRect.left, 292 move_rects->SourcePoint.y,
255 move_rects->DestinationRect.bottom - move_rects->DestinationRect.top)); 293 move_rects->DestinationRect.right -
256 updated_region->AddRect(DesktopRect::MakeLTRB( 294 move_rects->DestinationRect.left,
257 move_rects->DestinationRect.left, move_rects->DestinationRect.top, 295 move_rects->DestinationRect.bottom -
258 move_rects->DestinationRect.right, move_rects->DestinationRect.bottom)); 296 move_rects->DestinationRect.top),
297 unrotated_size_, rotation_));
298 updated_region->AddRect(
299 RotateRect(DesktopRect::MakeLTRB(move_rects->DestinationRect.left,
300 move_rects->DestinationRect.top,
301 move_rects->DestinationRect.right,
302 move_rects->DestinationRect.bottom),
303 unrotated_size_, rotation_));
259 move_rects++; 304 move_rects++;
260 move_rects_count--; 305 move_rects_count--;
261 } 306 }
262 307
263 while (dirty_rects_count > 0) { 308 while (dirty_rects_count > 0) {
264 updated_region->AddRect( 309 updated_region->AddRect(RotateRect(
265 DesktopRect::MakeLTRB(dirty_rects->left, dirty_rects->top, 310 DesktopRect::MakeLTRB(dirty_rects->left, dirty_rects->top,
266 dirty_rects->right, dirty_rects->bottom)); 311 dirty_rects->right, dirty_rects->bottom),
312 unrotated_size_, rotation_));
267 dirty_rects++; 313 dirty_rects++;
268 dirty_rects_count--; 314 dirty_rects_count--;
269 } 315 }
270 316
271 return true; 317 return true;
272 } 318 }
273 319
274 void DxgiOutputDuplicator::Setup(Context* context) { 320 void DxgiOutputDuplicator::Setup(Context* context) {
275 RTC_DCHECK(context->updated_region.is_empty()); 321 RTC_DCHECK(context->updated_region.is_empty());
276 // Always copy entire monitor during the first Duplicate() function call. 322 // Always copy entire monitor during the first Duplicate() function call.
(...skipping 11 matching lines...) Expand all
288 334
289 void DxgiOutputDuplicator::SpreadContextChange(const Context* const source) { 335 void DxgiOutputDuplicator::SpreadContextChange(const Context* const source) {
290 for (Context* dest : contexts_) { 336 for (Context* dest : contexts_) {
291 RTC_DCHECK(dest); 337 RTC_DCHECK(dest);
292 if (dest != source) { 338 if (dest != source) {
293 dest->updated_region.AddRegion(source->updated_region); 339 dest->updated_region.AddRegion(source->updated_region);
294 } 340 }
295 } 341 }
296 } 342 }
297 343
298 DesktopRect DxgiOutputDuplicator::SourceRect(DesktopRect rect) {
299 // |texture_|->AsDesktopFrame() starts from (0, 0).
300 rect.Translate(-desktop_rect_.left(), -desktop_rect_.top());
301 return rect;
302 }
303
304 } // namespace webrtc 344 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/modules/desktop_capture/win/dxgi_output_duplicator.h ('k') | webrtc/modules/desktop_capture/win/dxgi_texture.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698