dxgi_capturer.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #include "dxgi_capturer.h"
  2. #include <windows.h>
  3. DxgiCapturer::DxgiCapturer()
  4. {
  5. ZeroMemory(&_desc, sizeof(_desc));
  6. }
  7. DxgiCapturer::~DxgiCapturer()
  8. {
  9. Close();
  10. }
  11. bool DxgiCapturer::Open(int left, int top, int width, int height)
  12. {
  13. Close();
  14. HRESULT hr = S_OK;
  15. _isAttached = false;
  16. if (_bInit) {
  17. return false;
  18. }
  19. // Driver types supported
  20. D3D_DRIVER_TYPE DriverTypes[] = {
  21. D3D_DRIVER_TYPE_HARDWARE,
  22. D3D_DRIVER_TYPE_WARP,
  23. D3D_DRIVER_TYPE_REFERENCE,
  24. };
  25. UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
  26. // Feature levels supported
  27. D3D_FEATURE_LEVEL FeatureLevels[] = {
  28. D3D_FEATURE_LEVEL_11_0,
  29. D3D_FEATURE_LEVEL_10_1,
  30. D3D_FEATURE_LEVEL_10_0,
  31. D3D_FEATURE_LEVEL_9_1};
  32. UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
  33. D3D_FEATURE_LEVEL FeatureLevel;
  34. // Create D3D device
  35. for (UINT DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex) {
  36. hr = D3D11CreateDevice(nullptr, DriverTypes[DriverTypeIndex], nullptr, 0, FeatureLevels,
  37. NumFeatureLevels, D3D11_SDK_VERSION, &_hDevice, &FeatureLevel, &_hContext);
  38. if (SUCCEEDED(hr)) {
  39. break;
  40. }
  41. }
  42. __CheckBool(SUCCEEDED(hr));
  43. // Get DXGI device
  44. IDXGIDevice* hDxgiDevice = nullptr;
  45. __CheckBool(SUCCEEDED(_hDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&hDxgiDevice))));
  46. // Get DXGI adapter
  47. IDXGIAdapter* hDxgiAdapter = nullptr;
  48. hr = hDxgiDevice->GetParent(__uuidof(IDXGIAdapter), reinterpret_cast<void**>(&hDxgiAdapter));
  49. Free(hDxgiDevice, [=] { hDxgiDevice->Release(); });
  50. __CheckBool(SUCCEEDED(hr));
  51. // Get output
  52. INT nOutput = 0;
  53. IDXGIOutput* hDxgiOutput = nullptr;
  54. DXGI_OUTPUT_DESC dxgiOutDesc;
  55. ZeroMemory(&dxgiOutDesc, sizeof(dxgiOutDesc));
  56. for (int idx = 0; SUCCEEDED(hr = hDxgiAdapter->EnumOutputs(idx, &hDxgiOutput)); ++idx) {
  57. // get output description struct
  58. hDxgiOutput->GetDesc(&dxgiOutDesc);
  59. if (dxgiOutDesc.DesktopCoordinates.left == left
  60. && dxgiOutDesc.DesktopCoordinates.top == top) { // 寻找显示器
  61. break;
  62. }
  63. }
  64. Free(hDxgiAdapter, [=] { hDxgiAdapter->Release(); });
  65. __CheckBool(SUCCEEDED(hr));
  66. // QI for Output 1
  67. IDXGIOutput1* hDxgiOutput1 = nullptr;
  68. hr = hDxgiOutput->QueryInterface(__uuidof(hDxgiOutput1), reinterpret_cast<void**>(&hDxgiOutput1));
  69. Free(hDxgiOutput, [=] { hDxgiOutput->Release(); });
  70. __CheckBool(SUCCEEDED(hr));
  71. // Create desktop duplication
  72. hr = hDxgiOutput1->DuplicateOutput(_hDevice, &_hDeskDupl);
  73. Free(hDxgiOutput1, [=] { hDxgiOutput1->Release(); });
  74. __CheckBool(SUCCEEDED(hr));
  75. // Set ColorSpace
  76. D3D11_VIDEO_PROCESSOR_COLOR_SPACE inputColorSpace;
  77. inputColorSpace.Usage = 1;
  78. inputColorSpace.RGB_Range = 0;
  79. inputColorSpace.YCbCr_Matrix = 1;
  80. inputColorSpace.YCbCr_xvYCC = 0;
  81. inputColorSpace.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_0_255;
  82. D3D11_VIDEO_PROCESSOR_COLOR_SPACE outputColorSpace;
  83. outputColorSpace.Usage = 0;
  84. outputColorSpace.RGB_Range = 0;
  85. outputColorSpace.YCbCr_Matrix = 1;
  86. outputColorSpace.YCbCr_xvYCC = 0;
  87. outputColorSpace.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_16_235;
  88. _rgbToNv12.Open(_hDevice, _hContext, inputColorSpace, outputColorSpace);
  89. _nv12Frame = Frame<MediaType::VIDEO>::Alloc(AV_PIX_FMT_NV12, width, height);
  90. _xrgbFrame = Frame<MediaType::VIDEO>::Alloc(AV_PIX_FMT_BGR0, width, height);
  91. __CheckBool(_nv12Frame);
  92. __CheckBool(_xrgbFrame);
  93. // 初始化成功
  94. _bInit = true;
  95. return true;
  96. }
  97. void DxgiCapturer::Close()
  98. {
  99. if (!_bInit) {
  100. return;
  101. }
  102. _bInit = false;
  103. _nv12Buffers.Clear();
  104. _xrgbBuffers.Clear();
  105. _rgbToNv12.Close();
  106. Free(_nv12Frame, [this] { av_frame_free(&_nv12Frame); });
  107. Free(_xrgbFrame, [this] { av_frame_free(&_xrgbFrame); });
  108. Free(_hDeskDupl, [this] { _hDeskDupl->Release(); });
  109. Free(_hDevice, [this] { _hDevice->Release(); });
  110. Free(_hContext, [this] { _hContext->Release(); });
  111. }
  112. HDC DxgiCapturer::GetHdc()
  113. {
  114. _isCaptureSuccess = false;
  115. if (!_bInit) {
  116. return nullptr;
  117. }
  118. IDXGIResource* hDesktopResource = nullptr;
  119. DXGI_OUTDUPL_FRAME_INFO FrameInfo;
  120. HRESULT hr = _hDeskDupl->AcquireNextFrame(0, &FrameInfo, &hDesktopResource);
  121. if (FAILED(hr)) {
  122. if (hr == DXGI_ERROR_WAIT_TIMEOUT) { // 这里是因为当桌面没有动画更新时就会有一个错误值,不进行错误打印
  123. return nullptr;
  124. }
  125. return nullptr;
  126. }
  127. // query next frame staging buffer
  128. ID3D11Texture2D* srcImage = nullptr;
  129. hr = hDesktopResource->QueryInterface(__uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&srcImage));
  130. Free(hDesktopResource, [=] { hDesktopResource->Release(); });
  131. __CheckNullptr(SUCCEEDED(hr));
  132. srcImage->GetDesc(&_desc);
  133. // create a new staging buffer for fill frame image
  134. auto desc = _desc;
  135. desc.ArraySize = 1;
  136. desc.BindFlags = D3D11_BIND_FLAG::D3D11_BIND_RENDER_TARGET;
  137. desc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
  138. desc.SampleDesc.Count = 1;
  139. desc.SampleDesc.Quality = 0;
  140. desc.MipLevels = 1;
  141. desc.CPUAccessFlags = 0;
  142. desc.Usage = D3D11_USAGE_DEFAULT;
  143. hr = _hDevice->CreateTexture2D(&desc, nullptr, &_gdiImage);
  144. if (FAILED(hr)) {
  145. __DebugPrint("Create _gdiImage failed");
  146. Free(srcImage, [=] { srcImage->Release(); });
  147. Free(_hDeskDupl, [this] { _hDeskDupl->ReleaseFrame(); });
  148. return nullptr;
  149. }
  150. // copy next staging buffer to new staging buffer
  151. _hContext->CopyResource(_gdiImage, srcImage);
  152. Free(srcImage, [=] { srcImage->Release(); });
  153. _hDeskDupl->ReleaseFrame();
  154. // create staging buffer for map bits
  155. _hStagingSurf = nullptr;
  156. hr = _gdiImage->QueryInterface(__uuidof(IDXGISurface), (void**)(&_hStagingSurf));
  157. if (FAILED(hr)) {
  158. __DebugPrint("_gdiImage->QueryInterface failed");
  159. Free(_gdiImage, [this] { _gdiImage->Release(); });
  160. return nullptr;
  161. }
  162. _isCaptureSuccess = true;
  163. HDC hdc = nullptr;
  164. // if GetDc is failed, the hdc is nullptr
  165. _hStagingSurf->GetDC(FALSE, &hdc);
  166. return hdc;
  167. }
  168. AVFrame* DxgiCapturer::GetFrame()
  169. {
  170. if (!_isCaptureSuccess) {
  171. return nullptr;
  172. }
  173. _isCaptureSuccess = false;
  174. _hStagingSurf->ReleaseDC(nullptr);
  175. // 创建一个临时的纹理
  176. ID3D11Texture2D* tmpImage = nullptr;
  177. _desc.MiscFlags = 2050;
  178. __CheckNullptr(SUCCEEDED(_hDevice->CreateTexture2D(&_desc, nullptr, &tmpImage)));
  179. _hContext->CopyResource(tmpImage, _gdiImage);
  180. // 首先尝试创建 NV12 纹理
  181. AVFrame* frame = nullptr;
  182. auto tmpFormat = _desc.Format;
  183. _desc.Format = DXGI_FORMAT_NV12;
  184. if (GenNv12Frame(_hDevice, _hContext, _desc, tmpImage,
  185. _nv12Buffers, _nv12Frame, _rgbToNv12)) {
  186. frame = _nv12Frame;
  187. } else {
  188. _desc.Format = tmpFormat;
  189. GenRgbFrame(_hDevice, _hContext, _desc, _gdiImage,
  190. _xrgbBuffers, _xrgbFrame);
  191. frame = _xrgbFrame;
  192. }
  193. Free(_hStagingSurf, [this] { _hStagingSurf->Release(); });
  194. Free(tmpImage, [&tmpImage] { tmpImage->Release(); });
  195. Free(_gdiImage, [this] { _gdiImage->Release(); });
  196. return frame;
  197. }