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

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

Issue 2530303002: Use RotateDesktopFrame in DirectX capturer (Closed)
Patch Set: 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 DXGI_MODE_ROTATIONToRotation(DXGI_MODE_ROTATION rotation) {
Sergey Ulanov 2016/11/28 23:12:35 Call it DxgiRotationToRotation()?
Hzj_jie 2016/11/29 01:21:39 Done.
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());
Sergey Ulanov 2016/11/28 23:12:35 nit: This could be expressed Translate(DesktopVect
Hzj_jie 2016/11/29 01:21:39 Acknowledged.
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(), reverse_rotation_);
64 if (desc_.DesktopImageInSystemMemory) { 90 if (desc_.DesktopImageInSystemMemory) {
65 texture_.reset(new DxgiTextureMapping(desktop_rect_, duplication_.Get())); 91 texture_.reset(new DxgiTextureMapping(
92 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_ = DXGI_MODE_ROTATIONToRotation(desc_.Rotation);
135 reverse_rotation_ = ReverseRotation(rotation_);
136 unrotated_size_ = RotateSize(desktop_rect_.size(), reverse_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(), reverse_rotation_);
198 RotateDesktopFrame(source,
199 source_rect,
Sergey Ulanov 2016/11/28 23:12:35 "git cl format" please. It will put multiple args
Hzj_jie 2016/11/29 01:21:39 Done.
200 rotation_,
201 offset,
202 target);
203 }
204 } else {
205 for (DesktopRegion::Iterator it(updated_region); !it.IsAtEnd();
206 it.Advance()) {
207 target->CopyPixelsFrom(
208 source, ReverseTranslate(it.rect(), offset).top_left(), it.rect());
209 }
168 } 210 }
169 last_frame_ = target->Share(); 211 last_frame_ = target->Share();
170 last_frame_offset_ = offset; 212 last_frame_offset_ = offset;
171 target->mutable_updated_region()->AddRegion(updated_region); 213 target->mutable_updated_region()->AddRegion(updated_region);
172 return texture_->Release() && ReleaseFrame(); 214 return texture_->Release() && ReleaseFrame();
173 } 215 }
174 216
175 if (last_frame_) { 217 if (last_frame_) {
176 // No change since last frame or AcquireNextFrame() timed out, we will 218 // No change since last frame or AcquireNextFrame() timed out, we will
177 // export last frame to the target. 219 // export last frame to the target.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 DesktopRegion* updated_region) { 253 DesktopRegion* updated_region) {
212 RTC_DCHECK(updated_region); 254 RTC_DCHECK(updated_region);
213 updated_region->Clear(); 255 updated_region->Clear();
214 if (frame_info.TotalMetadataBufferSize == 0) { 256 if (frame_info.TotalMetadataBufferSize == 0) {
215 // This should not happen, since frame_info.AccumulatedFrames > 0. 257 // This should not happen, since frame_info.AccumulatedFrames > 0.
216 LOG(LS_ERROR) << "frame_info.AccumulatedFrames > 0, " 258 LOG(LS_ERROR) << "frame_info.AccumulatedFrames > 0, "
217 "but TotalMetadataBufferSize == 0"; 259 "but TotalMetadataBufferSize == 0";
218 return false; 260 return false;
219 } 261 }
220 262
221 if (metadata.capacity() < frame_info.TotalMetadataBufferSize) { 263 if (metadata_.capacity() < frame_info.TotalMetadataBufferSize) {
222 metadata.clear(); // Avoid data copy 264 metadata_.clear(); // Avoid data copy
223 metadata.reserve(frame_info.TotalMetadataBufferSize); 265 metadata_.reserve(frame_info.TotalMetadataBufferSize);
224 } 266 }
225 267
226 UINT buff_size = 0; 268 UINT buff_size = 0;
227 DXGI_OUTDUPL_MOVE_RECT* move_rects = 269 DXGI_OUTDUPL_MOVE_RECT* move_rects =
228 reinterpret_cast<DXGI_OUTDUPL_MOVE_RECT*>(metadata.data()); 270 reinterpret_cast<DXGI_OUTDUPL_MOVE_RECT*>(metadata_.data());
229 size_t move_rects_count = 0; 271 size_t move_rects_count = 0;
230 _com_error error = duplication_->GetFrameMoveRects( 272 _com_error error = duplication_->GetFrameMoveRects(
231 static_cast<UINT>(metadata.capacity()), move_rects, &buff_size); 273 static_cast<UINT>(metadata_.capacity()), move_rects, &buff_size);
232 if (error.Error() != S_OK) { 274 if (error.Error() != S_OK) {
233 LOG(LS_ERROR) << "Failed to get move rectangles, error " 275 LOG(LS_ERROR) << "Failed to get move rectangles, error "
234 << error.ErrorMessage() << ", code " << error.Error(); 276 << error.ErrorMessage() << ", code " << error.Error();
235 return false; 277 return false;
236 } 278 }
237 move_rects_count = buff_size / sizeof(DXGI_OUTDUPL_MOVE_RECT); 279 move_rects_count = buff_size / sizeof(DXGI_OUTDUPL_MOVE_RECT);
238 280
239 RECT* dirty_rects = reinterpret_cast<RECT*>(metadata.data() + buff_size); 281 RECT* dirty_rects = reinterpret_cast<RECT*>(metadata_.data() + buff_size);
240 size_t dirty_rects_count = 0; 282 size_t dirty_rects_count = 0;
241 error = duplication_->GetFrameDirtyRects( 283 error = duplication_->GetFrameDirtyRects(
242 static_cast<UINT>(metadata.capacity()) - buff_size, dirty_rects, 284 static_cast<UINT>(metadata_.capacity()) - buff_size, dirty_rects,
243 &buff_size); 285 &buff_size);
244 if (error.Error() != S_OK) { 286 if (error.Error() != S_OK) {
245 LOG(LS_ERROR) << "Failed to get dirty rectangles, error " 287 LOG(LS_ERROR) << "Failed to get dirty rectangles, error "
246 << error.ErrorMessage() << ", code " << error.Error(); 288 << error.ErrorMessage() << ", code " << error.Error();
247 return false; 289 return false;
248 } 290 }
249 dirty_rects_count = buff_size / sizeof(RECT); 291 dirty_rects_count = buff_size / sizeof(RECT);
250 292
251 while (move_rects_count > 0) { 293 while (move_rects_count > 0) {
252 updated_region->AddRect(DesktopRect::MakeXYWH( 294 updated_region->AddRect(RotateRect(DesktopRect::MakeXYWH(
253 move_rects->SourcePoint.x, move_rects->SourcePoint.y, 295 move_rects->SourcePoint.x, move_rects->SourcePoint.y,
254 move_rects->DestinationRect.right - move_rects->DestinationRect.left, 296 move_rects->DestinationRect.right - move_rects->DestinationRect.left,
255 move_rects->DestinationRect.bottom - move_rects->DestinationRect.top)); 297 move_rects->DestinationRect.bottom - move_rects->DestinationRect.top),
256 updated_region->AddRect(DesktopRect::MakeLTRB( 298 unrotated_size_, rotation_));
299 updated_region->AddRect(RotateRect(DesktopRect::MakeLTRB(
257 move_rects->DestinationRect.left, move_rects->DestinationRect.top, 300 move_rects->DestinationRect.left, move_rects->DestinationRect.top,
258 move_rects->DestinationRect.right, move_rects->DestinationRect.bottom)); 301 move_rects->DestinationRect.right, move_rects->DestinationRect.bottom),
302 unrotated_size_, rotation_));
259 move_rects++; 303 move_rects++;
260 move_rects_count--; 304 move_rects_count--;
261 } 305 }
262 306
263 while (dirty_rects_count > 0) { 307 while (dirty_rects_count > 0) {
264 updated_region->AddRect( 308 updated_region->AddRect(RotateRect(
265 DesktopRect::MakeLTRB(dirty_rects->left, dirty_rects->top, 309 DesktopRect::MakeLTRB(dirty_rects->left, dirty_rects->top,
266 dirty_rects->right, dirty_rects->bottom)); 310 dirty_rects->right, dirty_rects->bottom),
311 unrotated_size_, rotation_));
267 dirty_rects++; 312 dirty_rects++;
268 dirty_rects_count--; 313 dirty_rects_count--;
269 } 314 }
270 315
271 return true; 316 return true;
272 } 317 }
273 318
274 void DxgiOutputDuplicator::Setup(Context* context) { 319 void DxgiOutputDuplicator::Setup(Context* context) {
275 RTC_DCHECK(context->updated_region.is_empty()); 320 RTC_DCHECK(context->updated_region.is_empty());
276 // Always copy entire monitor during the first Duplicate() function call. 321 // Always copy entire monitor during the first Duplicate() function call.
(...skipping 11 matching lines...) Expand all
288 333
289 void DxgiOutputDuplicator::SpreadContextChange(const Context* const source) { 334 void DxgiOutputDuplicator::SpreadContextChange(const Context* const source) {
290 for (Context* dest : contexts_) { 335 for (Context* dest : contexts_) {
291 RTC_DCHECK(dest); 336 RTC_DCHECK(dest);
292 if (dest != source) { 337 if (dest != source) {
293 dest->updated_region.AddRegion(source->updated_region); 338 dest->updated_region.AddRegion(source->updated_region);
294 } 339 }
295 } 340 }
296 } 341 }
297 342
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 343 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698