Chromium Code Reviews| 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/screen_capturer_win_directx.h" | |
| 12 | |
| 13 #include <assert.h> | |
| 14 #include <string.h> | |
| 15 | |
| 16 #include <comdef.h> | |
| 17 #include <wincodec.h> | |
| 18 #include <DXGI.h> | |
| 19 | |
| 20 #include "webrtc/modules/desktop_capture/desktop_frame_win.h" | |
| 21 #include "webrtc/modules/desktop_capture/win/screen_capture_utils.h" | |
| 22 #include "webrtc/system_wrappers/include/logging.h" | |
| 23 #include "webrtc/system_wrappers/include/tick_util.h" | |
| 24 | |
| 25 namespace webrtc { | |
| 26 | |
| 27 using Microsoft::WRL::ComPtr; | |
| 28 using rtc::scoped_ptr; | |
|
Sergey Ulanov
2016/03/31 18:41:16
scoped_ptr<> is used in only one place, so you can
Hzj_jie
2016/04/05 23:15:17
Done.
| |
| 29 using std::unique_ptr; | |
|
Sergey Ulanov
2016/03/31 18:41:17
unique_ptr is not used anywhere in this file.
Hzj_jie
2016/04/05 23:15:17
Done.
| |
| 30 | |
| 31 bool ScreenCapturerWinDirectX::kInitialized { false }; | |
|
Sergey Ulanov
2016/03/31 18:41:16
All of these are not really constants, so you shou
Sergey Ulanov
2016/03/31 18:41:16
= false.
C++11 style initialization syntax is not
Hzj_jie
2016/04/05 23:15:17
Done.
Hzj_jie
2016/04/05 23:15:18
Yes, I have also had the same feeling, but logical
| |
| 32 bool ScreenCapturerWinDirectX::kInitializeResult { false }; | |
| 33 ID3D11Device* ScreenCapturerWinDirectX::kD3D11Device { nullptr }; | |
| 34 ID3D11DeviceContext* ScreenCapturerWinDirectX::kD3D11Context { nullptr }; | |
| 35 IDXGIOutput1* ScreenCapturerWinDirectX::kDXGIOutput1 { nullptr }; | |
| 36 ComPtr<IDXGIOutputDuplication> | |
|
Sergey Ulanov
2016/03/31 18:41:16
Static variables are allowed only for POD types. S
Hzj_jie
2016/04/05 23:15:18
According to MSDN http://shortn/_geEQFIizM3, one a
Sergey Ulanov
2016/04/08 21:22:26
All global variables _must_ be POD. It doesn't mat
| |
| 37 ScreenCapturerWinDirectX::kDXGIOutputDuplication {}; | |
| 38 DesktopSize ScreenCapturerWinDirectX::kDesktopSize {}; | |
| 39 ComPtr<ID3D11Texture2D> ScreenCapturerWinDirectX::kStage {}; | |
| 40 ComPtr<IDXGISurface> ScreenCapturerWinDirectX::kSurface {}; | |
| 41 std::vector<BYTE> ScreenCapturerWinDirectX::kMetaDataBuffer {}; | |
| 42 CriticalSectionWrapper ScreenCapturerWinDirectX::kInitializeLock {}; | |
| 43 CriticalSectionWrapper ScreenCapturerWinDirectX::kDuplicationLock {}; | |
| 44 CriticalSectionWrapper ScreenCapturerWinDirectX::kAcquireLock {}; | |
| 45 | |
| 46 bool ScreenCapturerWinDirectX::Initialize() { | |
| 47 if (!kInitialized) { | |
| 48 CriticalSectionScoped lock(&kInitializeLock); | |
| 49 if (!kInitialized) { | |
| 50 kInitializeResult = DoInitialize(); | |
| 51 kInitialized = true; | |
| 52 if (kInitializeResult) { | |
| 53 return true; | |
| 54 } | |
| 55 | |
| 56 // Clean up if DirectX cannot work on the system. | |
| 57 if (kDXGIOutputDuplication) { | |
| 58 kDXGIOutputDuplication.Reset(); | |
| 59 } | |
| 60 | |
| 61 if (kDXGIOutput1 != nullptr) { | |
| 62 kDXGIOutput1->Release(); | |
|
Sergey Ulanov
2016/03/31 18:41:15
Why do you need this? Doesn't ComPtr<> release the
Hzj_jie
2016/04/05 23:15:18
Yes, ComPtr does, but this instance is a pure poin
| |
| 63 kDXGIOutput1 = nullptr; | |
| 64 } | |
| 65 | |
| 66 if (kD3D11Context != nullptr) { | |
| 67 kD3D11Context->Release(); | |
| 68 kD3D11Context = nullptr; | |
| 69 } | |
| 70 | |
| 71 if (kD3D11Device != nullptr) { | |
| 72 kD3D11Device->Release(); | |
| 73 kD3D11Device = nullptr; | |
| 74 } | |
| 75 | |
| 76 return false; | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 return kInitializeResult; | |
| 81 } | |
| 82 | |
| 83 bool ScreenCapturerWinDirectX::DoInitialize() { | |
| 84 D3D_FEATURE_LEVEL feature_level; | |
| 85 _com_error err(D3D11CreateDevice(nullptr, | |
| 86 D3D_DRIVER_TYPE_HARDWARE, | |
| 87 nullptr, | |
| 88 D3D11_CREATE_DEVICE_SINGLETHREADED, | |
|
Sergey Ulanov
2016/03/31 18:41:17
DirectX may be used from other threads in chrome,
Hzj_jie
2016/04/05 23:15:17
We always have only one thread to access an ID3D11
| |
| 89 nullptr, | |
| 90 0, | |
| 91 D3D11_SDK_VERSION, | |
| 92 &kD3D11Device, | |
| 93 &feature_level, | |
| 94 &kD3D11Context)); | |
| 95 if (err.Error() != S_OK || | |
| 96 kD3D11Device == nullptr || | |
| 97 kD3D11Context == nullptr) { | |
| 98 LOG(LS_WARNING) << "D3D11CreateDeivce returns error " << err.ErrorMessage() | |
| 99 << " with code " << err.Error(); | |
| 100 return false; | |
| 101 } | |
| 102 | |
| 103 if (feature_level < D3D_FEATURE_LEVEL_11_0) { | |
| 104 LOG(LS_WARNING) << "D3D11CreateDevice returns an instance without DirectX " | |
| 105 "11 support, level " << feature_level; | |
| 106 return false; | |
| 107 } | |
| 108 | |
| 109 ComPtr<IDXGIDevice> device; | |
| 110 err = _com_error(kD3D11Device->QueryInterface( | |
| 111 __uuidof(IDXGIDevice), | |
| 112 reinterpret_cast<void**>(device.GetAddressOf()))); | |
| 113 if (err.Error() != S_OK || !device) { | |
| 114 LOG(LS_WARNING) << "ID3D11Device is not an implementation of IDXGIDevice, " | |
| 115 "this usually means the system does not support DirectX " | |
| 116 "11"; | |
| 117 return false; | |
| 118 } | |
| 119 | |
| 120 ComPtr<IDXGIAdapter> adapter; | |
| 121 err = _com_error(device->GetAdapter(adapter.GetAddressOf())); | |
| 122 if (err.Error() != S_OK || !adapter) { | |
| 123 LOG(LS_WARNING) << "Failed to get an IDXGIAdapter implementation from " | |
| 124 "IDXGIDevice."; | |
| 125 return false; | |
| 126 } | |
| 127 | |
| 128 ComPtr<IDXGIOutput> output; | |
| 129 for (int i = 0;; i++) { | |
|
Sergey Ulanov
2016/03/31 18:41:16
while() loop would be more readable here. E.g. see
Hzj_jie
2016/04/05 23:15:17
The scenario is a little bit different, we are loo
| |
| 130 err = _com_error(adapter->EnumOutputs(i, output.GetAddressOf())); | |
| 131 if (err.Error() == DXGI_ERROR_NOT_FOUND) { | |
| 132 LOG(LS_WARNING) << "No output detected."; | |
| 133 return false; | |
| 134 } else if (err.Error() == S_OK && output) { | |
|
Sergey Ulanov
2016/03/31 18:41:15
what if err.Error() is any error other than DXGI_
Sergey Ulanov
2016/03/31 18:41:16
no else after return please: https://www.chromium.
Hzj_jie
2016/04/05 23:15:18
I do not see a statement in MSDN to say this funct
| |
| 135 DXGI_OUTPUT_DESC desc; | |
| 136 err = _com_error(output->GetDesc(&desc)); | |
| 137 if (err.Error() == S_OK) { | |
| 138 if (desc.AttachedToDesktop) { | |
| 139 // Current output instance is the device attached to desktop. | |
| 140 break; | |
| 141 } | |
| 142 } else { | |
| 143 LOG(LS_WARNING) << "Failed to get output description of device " << i | |
| 144 << ", ignore."; | |
| 145 } | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 assert(output); | |
| 150 err = _com_error(output.CopyTo(__uuidof(IDXGIOutput1), | |
| 151 reinterpret_cast<void**>(&kDXGIOutput1))); | |
| 152 if (err.Error() != S_OK || kDXGIOutput1 == nullptr) { | |
| 153 LOG(LS_WARNING) << "Failed to convert IDXGIOutput to IDXGIOutput1, this " | |
| 154 "usually means the system does not support DirectX 11"; | |
| 155 return false; | |
| 156 } | |
| 157 | |
| 158 return DuplicateOutput(); | |
| 159 } | |
| 160 | |
| 161 bool ScreenCapturerWinDirectX::DuplicateOutput() { | |
| 162 assert(kDXGIOutput1 != nullptr); | |
| 163 // We are updating the instance. | |
| 164 CriticalSectionScoped lock(&kDuplicationLock); | |
| 165 // Make sure nobody is using current instance. | |
| 166 CriticalSectionScoped lock2(&kAcquireLock); | |
| 167 if (kDXGIOutputDuplication) { | |
| 168 kDXGIOutputDuplication.Reset(); | |
| 169 } | |
| 170 _com_error err(kDXGIOutput1->DuplicateOutput( | |
| 171 static_cast<IUnknown*>(kD3D11Device), | |
| 172 kDXGIOutputDuplication.GetAddressOf())); | |
| 173 if (err.Error() != S_OK || !kDXGIOutputDuplication) { | |
| 174 LOG(LS_WARNING) << "Failed to duplicate output from IDXGIOutput1, error " | |
| 175 << err.ErrorMessage() << ", with code " << err.Error(); | |
| 176 return false; | |
| 177 } | |
| 178 | |
| 179 DXGI_OUTDUPL_DESC desc; | |
| 180 kDXGIOutputDuplication->GetDesc(&desc); | |
| 181 kDesktopSize.set(desc.ModeDesc.Width, desc.ModeDesc.Height); | |
| 182 kStage.Reset(); | |
| 183 kSurface.Reset(); | |
| 184 return true; | |
| 185 } | |
| 186 | |
| 187 ScreenCapturerWinDirectX::ScreenCapturerWinDirectX( | |
| 188 const DesktopCaptureOptions& options) : | |
| 189 callback_(nullptr), | |
| 190 set_thread_execution_state_failed_(false) { | |
| 191 assert(kInitialized && kInitializeResult); | |
| 192 } | |
| 193 | |
| 194 ScreenCapturerWinDirectX::~ScreenCapturerWinDirectX() {} | |
| 195 | |
| 196 void ScreenCapturerWinDirectX::Start(Callback* callback) { | |
| 197 assert(callback_ == nullptr); | |
|
Sergey Ulanov
2016/03/31 18:41:16
Here and everywhere else please use RTC_DCHECK() i
Hzj_jie
2016/04/05 23:15:18
Done.
| |
| 198 assert(callback != nullptr); | |
| 199 | |
| 200 callback_ = callback; | |
| 201 } | |
| 202 | |
| 203 // We do not need to allocate memory in this class. | |
| 204 void ScreenCapturerWinDirectX::SetSharedMemoryFactory( | |
| 205 rtc::scoped_ptr<SharedMemoryFactory> shared_memory_factory) {} | |
|
Sergey Ulanov
2016/03/31 18:41:16
We actually don't want to ignore this call. On win
Hzj_jie
2016/04/05 23:15:18
Yes, done.
| |
| 206 | |
| 207 bool ScreenCapturerWinDirectX::CreateTexture(ID3D11Texture2D* texture) { | |
| 208 assert(texture != nullptr); | |
| 209 D3D11_TEXTURE2D_DESC desc; | |
| 210 texture->GetDesc(&desc); | |
| 211 desc.Usage = D3D11_USAGE_STAGING; | |
| 212 desc.BindFlags = 0; | |
| 213 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; | |
| 214 desc.MiscFlags = 0; | |
| 215 if (kStage) { | |
| 216 { | |
| 217 ComPtr<IUnknown> left; | |
| 218 ComPtr<IUnknown> right; | |
| 219 assert(SUCCEEDED(kStage.CopyTo( | |
|
Sergey Ulanov
2016/03/31 18:41:16
Don't put any statements with side-effects inside
Hzj_jie
2016/04/05 23:15:18
Done.
| |
| 220 __uuidof(IUnknown), | |
| 221 reinterpret_cast<void**>(left.GetAddressOf())))); | |
| 222 assert(SUCCEEDED(kSurface.CopyTo( | |
| 223 __uuidof(IUnknown), | |
| 224 reinterpret_cast<void**>(right.GetAddressOf())))); | |
| 225 assert(left.Get() == right.Get()); | |
| 226 } | |
| 227 _com_error err(kSurface->Unmap()); // This buffer should be used already. | |
| 228 if (err.Error() == S_OK) { | |
| 229 D3D11_TEXTURE2D_DESC orgi_desc; | |
| 230 kStage->GetDesc(&orgi_desc); | |
| 231 if (memcmp(&desc, &orgi_desc, sizeof(D3D11_TEXTURE2D_DESC)) == 0) { | |
|
Sergey Ulanov
2016/03/31 18:41:16
You don't need this check. memcmp() is not expecte
Hzj_jie
2016/04/05 23:15:18
This logic is to check whether current buffer (sta
| |
| 232 return true; | |
| 233 } | |
| 234 } else { | |
| 235 // Let's recreate kSurface later. | |
| 236 LOG(LS_ERROR) << "Failed to unmap surface, error " << err.ErrorMessage() | |
| 237 << ", code " << err.Error(); | |
| 238 } | |
| 239 kStage.Reset(); | |
| 240 kSurface.Reset(); | |
| 241 } | |
| 242 | |
| 243 _com_error err = _com_error(kD3D11Device->CreateTexture2D( | |
| 244 &desc, | |
| 245 nullptr, | |
| 246 kStage.GetAddressOf())); | |
| 247 if (err.Error() != S_OK || !kStage) { | |
| 248 LOG(LS_ERROR) << "Failed to create a new ID3D11Texture2D as stage, " | |
| 249 "error " << err.ErrorMessage() | |
| 250 << ", code " << err.Error(); | |
| 251 return false; | |
| 252 } | |
| 253 | |
| 254 err = _com_error(kStage.CopyTo( | |
| 255 __uuidof(IDXGISurface), | |
| 256 reinterpret_cast<void**>(kSurface.GetAddressOf()))); | |
| 257 if (err.Error() != S_OK || !kSurface) { | |
| 258 LOG(LS_ERROR) << "Failed to convert ID3D11Texture2D to IDXGISurface, " | |
| 259 "error " << err.ErrorMessage() | |
| 260 << ", code " << err.Error(); | |
| 261 return false; | |
| 262 } | |
| 263 | |
| 264 return true; | |
| 265 } | |
| 266 | |
| 267 bool ScreenCapturerWinDirectX::DetectUpdatedRegion( | |
| 268 const DXGI_OUTDUPL_FRAME_INFO& frame_info, | |
|
Sergey Ulanov
2016/03/31 18:41:16
incorrect indentation. Please use clang-format: ht
Hzj_jie
2016/04/05 23:15:17
Done.
| |
| 269 DesktopFrame* frame) { | |
| 270 assert(kDXGIOutputDuplication); | |
| 271 assert(frame != nullptr); | |
| 272 DesktopRegion& updated_region = *frame->mutable_updated_region(); | |
| 273 updated_region.Clear(); | |
| 274 if (frame_info.TotalMetadataBufferSize == 0) { | |
| 275 // This should not happen, since frame_info.AccumulatedFrames > 0. | |
| 276 LOG(LS_ERROR) << "frame_info.AccumulatedFrames > 0, " | |
| 277 "but TotalMetadataBufferSize == 0"; | |
| 278 return false; | |
| 279 } | |
| 280 | |
| 281 if (kMetaDataBuffer.size() < frame_info.TotalMetadataBufferSize) { | |
| 282 kMetaDataBuffer.clear(); // Avoid data copy | |
| 283 kMetaDataBuffer.reserve(frame_info.TotalMetadataBufferSize); | |
| 284 } | |
| 285 | |
| 286 UINT buff_size = 0; | |
| 287 DXGI_OUTDUPL_MOVE_RECT* move_rects = nullptr; | |
| 288 size_t move_rects_count = 0; | |
| 289 RECT* dirty_rects = nullptr; | |
| 290 size_t dirty_rects_count = 0; | |
| 291 for (int i = 0; i < 2; i++) { | |
|
Sergey Ulanov
2016/03/31 18:41:16
This looks strange. You have a loop that iterates
Hzj_jie
2016/04/05 23:15:17
To share most of the logic below. I agree it looks
| |
| 292 _com_error err(S_OK); | |
| 293 if (i == 0) { | |
| 294 move_rects = | |
| 295 reinterpret_cast<DXGI_OUTDUPL_MOVE_RECT*>(kMetaDataBuffer.data()); | |
| 296 err = _com_error(kDXGIOutputDuplication->GetFrameMoveRects( | |
| 297 kMetaDataBuffer.capacity(), | |
| 298 move_rects, | |
| 299 &buff_size)); | |
| 300 } else { | |
| 301 dirty_rects = | |
| 302 reinterpret_cast<RECT*>(kMetaDataBuffer.data() + buff_size); | |
| 303 err = _com_error(kDXGIOutputDuplication->GetFrameDirtyRects( | |
| 304 kMetaDataBuffer.capacity() - buff_size, | |
| 305 dirty_rects, | |
| 306 &buff_size)); | |
| 307 } | |
| 308 if (err.Error() != S_OK) { | |
| 309 if (err.Error() == DXGI_ERROR_ACCESS_LOST) { | |
| 310 if (!DuplicateOutput()) { | |
| 311 LOG(LS_ERROR) << "Failed to regenerate an IDXGIOutputDuplication."; | |
| 312 } | |
| 313 } else { | |
| 314 LOG(LS_ERROR) << "Failed to get " << (i == 0 ? "move" : "dirty") | |
| 315 << " rectangles, error " << err.ErrorMessage() | |
| 316 << ", code " << err.Error(); | |
| 317 } | |
| 318 // Send whole desktop as we cannot get dirty or move rectangles. | |
| 319 return false; | |
| 320 } | |
| 321 if (i == 0) { | |
| 322 move_rects_count = buff_size / sizeof(DXGI_OUTDUPL_MOVE_RECT); | |
| 323 } else { | |
| 324 dirty_rects_count = buff_size / sizeof(RECT); | |
| 325 } | |
| 326 } | |
| 327 | |
| 328 while (move_rects_count > 0) { | |
| 329 updated_region.AddRect(DesktopRect::MakeXYWH( | |
| 330 move_rects->SourcePoint.x, | |
| 331 move_rects->SourcePoint.y, | |
| 332 move_rects->DestinationRect.right - move_rects->DestinationRect.left, | |
| 333 move_rects->DestinationRect.bottom - move_rects->DestinationRect.top)); | |
| 334 updated_region.AddRect(DesktopRect::MakeLTRB( | |
| 335 move_rects->DestinationRect.left, | |
| 336 move_rects->DestinationRect.top, | |
| 337 move_rects->DestinationRect.right, | |
| 338 move_rects->DestinationRect.bottom)); | |
| 339 move_rects++; | |
| 340 move_rects_count--; | |
| 341 } | |
| 342 | |
| 343 while (dirty_rects_count > 0) { | |
| 344 updated_region.AddRect(DesktopRect::MakeLTRB( | |
| 345 dirty_rects->left, | |
| 346 dirty_rects->top, | |
| 347 dirty_rects->right, | |
| 348 dirty_rects->bottom)); | |
| 349 dirty_rects++; | |
| 350 dirty_rects_count--; | |
| 351 } | |
| 352 | |
| 353 return true; | |
| 354 } | |
| 355 | |
| 356 bool ScreenCapturerWinDirectX::ProcessFrame( | |
| 357 const DXGI_OUTDUPL_FRAME_INFO& frame_info, | |
| 358 IDXGIResource* resource, | |
| 359 DesktopFrame** frame) { | |
| 360 assert(resource != nullptr); | |
| 361 assert(frame != nullptr); | |
| 362 assert(frame_info.AccumulatedFrames > 0); | |
| 363 | |
| 364 ComPtr<ID3D11Texture2D> texture; | |
| 365 _com_error err = _com_error(resource->QueryInterface( | |
| 366 __uuidof(ID3D11Texture2D), | |
| 367 reinterpret_cast<void**>(texture.GetAddressOf()))); | |
| 368 if (err.Error() != S_OK || !texture) { | |
| 369 LOG(LS_ERROR) << "Failed to convert IDXGIResource to ID3D11Texture2D, " | |
| 370 "error " << err.ErrorMessage() << ", code " | |
| 371 << err.Error(); | |
| 372 return false; | |
| 373 } | |
| 374 | |
| 375 // AcquireNextFrame returns a CPU inaccessible IDXGIResource, so we need to | |
| 376 // make a copy. | |
| 377 if (!CreateTexture(texture.Get())) { | |
| 378 return false; | |
| 379 } | |
| 380 | |
| 381 kD3D11Context->CopyResource(static_cast<ID3D11Resource*>(kStage.Get()), | |
| 382 static_cast<ID3D11Resource*>(texture.Get())); | |
| 383 | |
| 384 DXGI_MAPPED_RECT rect; | |
| 385 err = _com_error(kSurface->Map(&rect, DXGI_MAP_READ)); | |
| 386 if (err.Error() != S_OK) { | |
| 387 LOG(LS_ERROR) << "Failed to map the IDXGISurface to a bitmap, error " | |
| 388 << err.ErrorMessage() << ", code " << err.Error(); | |
| 389 return false; | |
| 390 } | |
| 391 | |
| 392 *frame = new DesktopFrameWinDXGI(kDesktopSize, kSurface, rect); | |
| 393 // kSurface->Unmap will be called next time we capture an image to avoid | |
| 394 // memory copy. | |
| 395 if (!DetectUpdatedRegion(frame_info, *frame)) { | |
| 396 (*frame)->mutable_updated_region()->Clear(); | |
| 397 (*frame)->mutable_updated_region()->AddRect( | |
| 398 DesktopRect::MakeSize(kDesktopSize)); | |
| 399 } | |
| 400 return true; | |
| 401 } | |
| 402 | |
| 403 void ScreenCapturerWinDirectX::Capture(const DesktopRegion& region) { | |
| 404 if (!kDXGIOutputDuplication) { | |
| 405 // Receive a capture request when application is shutting down. | |
| 406 CallbackError(); | |
| 407 return; | |
| 408 } | |
| 409 | |
| 410 assert(callback_ != nullptr); | |
| 411 TickTime capture_start_time = TickTime::Now(); | |
| 412 | |
| 413 if (!SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED)) { | |
| 414 if (!set_thread_execution_state_failed_) { | |
| 415 set_thread_execution_state_failed_ = true; | |
| 416 LOG(LS_WARNING) << "Failed to make system & display power assertion: " | |
| 417 << GetLastError(); | |
| 418 } | |
| 419 } | |
| 420 | |
| 421 DXGI_OUTDUPL_FRAME_INFO frame_info = { 0 }; | |
| 422 ComPtr<IDXGIResource> resource = nullptr; | |
| 423 CriticalSectionScoped lock(&kAcquireLock); | |
| 424 _com_error err(kDXGIOutputDuplication->AcquireNextFrame( | |
| 425 kAcquireTimeout, | |
| 426 &frame_info, | |
| 427 resource.GetAddressOf())); | |
| 428 if (err.Error() == DXGI_ERROR_ACCESS_LOST) { | |
| 429 if (DuplicateOutput()) { | |
| 430 CallbackUnchanged(); | |
| 431 } else { | |
| 432 LOG(LS_ERROR) << "Failed to regenerate an IDXGIOutputDuplication"; | |
| 433 CallbackError(); | |
| 434 } | |
| 435 return; | |
| 436 } else if (err.Error() == DXGI_ERROR_WAIT_TIMEOUT) { | |
|
Sergey Ulanov
2016/03/31 18:41:17
here and below: no else after return please
Hzj_jie
2016/04/05 23:15:18
Done.
| |
| 437 // Nothing changed. | |
| 438 CallbackUnchanged(); | |
| 439 return; | |
| 440 } else if (err.Error() != S_OK) { | |
| 441 CallbackError(); | |
| 442 return; | |
| 443 } else { | |
| 444 if (frame_info.AccumulatedFrames > 0) { | |
| 445 // Everything looks good so far, build CaptureFrame. | |
| 446 DesktopFrame* frame = nullptr; | |
| 447 bool result = ProcessFrame(frame_info, resource.Get(), &frame); | |
| 448 kDXGIOutputDuplication->ReleaseFrame(); | |
| 449 if (result) { | |
| 450 assert(frame != nullptr); | |
| 451 frame->set_capture_time_ms( | |
| 452 (TickTime::Now() - capture_start_time).Milliseconds()); | |
| 453 callback_->OnCaptureCompleted(frame); | |
| 454 } else { | |
| 455 assert(frame == nullptr); | |
| 456 CallbackError(); | |
| 457 } | |
| 458 } else { | |
| 459 // Only mouse cursor moved, ignore. | |
| 460 CallbackUnchanged(); | |
| 461 kDXGIOutputDuplication->ReleaseFrame(); | |
| 462 } | |
| 463 } | |
| 464 } | |
| 465 | |
| 466 bool ScreenCapturerWinDirectX::GetScreenList(ScreenList* screens) { | |
| 467 assert(screens != nullptr); | |
| 468 assert(screens->size() == 0); | |
| 469 screens->push_back(Screen { 0 }); | |
| 470 return true; | |
| 471 } | |
| 472 | |
| 473 bool ScreenCapturerWinDirectX::SelectScreen(ScreenId id) { | |
| 474 return id == 0 || id == kFullDesktopScreenId; | |
| 475 } | |
| 476 | |
| 477 void ScreenCapturerWinDirectX::CallbackUnchanged() { | |
| 478 callback_->OnCaptureCompleted(new DesktopFrameWinDXGI(kDesktopSize)); | |
|
Sergey Ulanov
2016/03/31 18:41:16
When nothing is changed we want to emit a frame th
Hzj_jie
2016/04/05 23:15:18
Done.
| |
| 479 } | |
| 480 | |
| 481 void ScreenCapturerWinDirectX::CallbackError() { | |
| 482 callback_->OnCaptureCompleted(nullptr); | |
| 483 } | |
| 484 | |
| 485 } // namespace webrtc | |
| OLD | NEW |