dxgi_capturer.cpp 8.7 KB

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