SimpleCapture.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // D3D
  2. #include <d3d11_4.h>
  3. #include <dxgi1_6.h>
  4. #include <d2d1_3.h>
  5. #include <wincodec.h>
  6. #include "pch.h"
  7. #include "SimpleCapture.h"
  8. #include "basic/basic.h"
  9. #include <QDebug>
  10. using namespace winrt;
  11. using namespace Windows;
  12. using namespace Windows::Foundation;
  13. using namespace Windows::System;
  14. using namespace Windows::Graphics;
  15. using namespace Windows::Graphics::Capture;
  16. using namespace Windows::Graphics::DirectX;
  17. using namespace Windows::Graphics::DirectX::Direct3D11;
  18. using namespace Windows::Foundation::Numerics;
  19. using namespace Windows::UI;
  20. using namespace Windows::UI::Composition;
  21. #undef min
  22. #undef max
  23. template<typename T>
  24. auto GetDXGIInterfaceFromObjectEx(winrt::Windows::Foundation::IInspectable const& object)
  25. {
  26. auto access = object.try_as<IDirect3DDxgiInterfaceAccess>();
  27. if (!access) {
  28. qDebug() << "Failed to cast to IDirect3DDxgiInterfaceAccess!";
  29. throw std::runtime_error("Failed to cast to IDirect3DDxgiInterfaceAccess");
  30. }
  31. winrt::com_ptr<T> result;
  32. winrt::check_hresult(access->GetInterface(winrt::guid_of<T>(), result.put_void()));
  33. return result;
  34. }
  35. SimpleCapture::SimpleCapture(
  36. IDirect3DDevice const& device,
  37. GraphicsCaptureItem const& item,
  38. int width, int height)
  39. {
  40. m_item = item;
  41. m_device = device;
  42. if (!m_device) {
  43. qDebug() << "m_device is nullptr!";
  44. // 这里可以 return 或抛异常
  45. }
  46. // Set up
  47. auto d3dDevice = GetDXGIInterfaceFromObjectEx<ID3D11Device>(m_device);
  48. d3dDevice->GetImmediateContext(m_d3dContext.put());
  49. auto size = m_item.Size();
  50. m_swapChain = CreateDXGISwapChain(
  51. d3dDevice,
  52. static_cast<uint32_t>(size.Width),
  53. static_cast<uint32_t>(size.Height),
  54. static_cast<DXGI_FORMAT>(DirectXPixelFormat::B8G8R8A8UIntNormalized),
  55. 2);
  56. // Create framepool, define pixel format (DXGI_FORMAT_B8G8R8A8_UNORM), and frame size.
  57. m_framePool = Direct3D11CaptureFramePool::Create(
  58. m_device,
  59. DirectXPixelFormat::B8G8R8A8UIntNormalized,
  60. 2,
  61. size);
  62. m_session = m_framePool.CreateCaptureSession(m_item);
  63. m_lastSize = size;
  64. m_frameArrived = m_framePool.FrameArrived(auto_revoke, {this, &SimpleCapture::OnFrameArrived});
  65. // Set ColorSpace
  66. D3D11_VIDEO_PROCESSOR_COLOR_SPACE inputColorSpace;
  67. inputColorSpace.Usage = 1;
  68. inputColorSpace.RGB_Range = 0;
  69. inputColorSpace.YCbCr_Matrix = 1;
  70. inputColorSpace.YCbCr_xvYCC = 0;
  71. inputColorSpace.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_0_255;
  72. D3D11_VIDEO_PROCESSOR_COLOR_SPACE outputColorSpace;
  73. outputColorSpace.Usage = 0;
  74. outputColorSpace.RGB_Range = 0;
  75. outputColorSpace.YCbCr_Matrix = 1;
  76. outputColorSpace.YCbCr_xvYCC = 0;
  77. outputColorSpace.Nominal_Range = D3D11_VIDEO_PROCESSOR_NOMINAL_RANGE_16_235;
  78. m_rgbToNv12.Open(d3dDevice.get(), m_d3dContext.get(), inputColorSpace, outputColorSpace);
  79. m_nv12Frame = Frame<MediaType::VIDEO>::Alloc(AV_PIX_FMT_NV12, width, height);
  80. m_xrgbFrame = Frame<MediaType::VIDEO>::Alloc(AV_PIX_FMT_BGR0, width, height);
  81. if (!m_nv12Frame) {
  82. qDebug() << "Alloc NV12 frame failed";
  83. m_isCapture = false;
  84. return;
  85. }
  86. if (!m_xrgbFrame) {
  87. qDebug() << "Alloc XRGB frame failed";
  88. m_isCapture = false;
  89. return;
  90. }
  91. m_isCapture = true;
  92. m_cnt = 5;
  93. }
  94. // Start sending capture frames
  95. void SimpleCapture::StartCapture()
  96. {
  97. CheckClosed();
  98. m_session.StartCapture();
  99. }
  100. ICompositionSurface SimpleCapture::CreateSurface(
  101. Compositor const& compositor)
  102. {
  103. CheckClosed();
  104. return CreateCompositionSurfaceForSwapChain(compositor, m_swapChain.get());
  105. }
  106. // Process captured frames
  107. void SimpleCapture::Close()
  108. {
  109. auto expected = false;
  110. if (m_closed.compare_exchange_strong(expected, true)) {
  111. m_frameArrived.revoke();
  112. m_framePool.Close();
  113. m_session.Close();
  114. m_swapChain = nullptr;
  115. m_framePool = nullptr;
  116. m_session = nullptr;
  117. m_item = nullptr;
  118. }
  119. m_nv12Buffers.Clear();
  120. m_xrgbBuffers.Clear();
  121. m_rgbToNv12.Close();
  122. Free(m_nv12Frame, [this] { av_frame_free(&m_nv12Frame); });
  123. Free(m_xrgbFrame, [this] { av_frame_free(&m_xrgbFrame); });
  124. }
  125. void SimpleCapture::OnFrameArrived(
  126. Direct3D11CaptureFramePool const& sender,
  127. winrt::Windows::Foundation::IInspectable const&)
  128. {
  129. auto newSize = false;
  130. auto frame = sender.TryGetNextFrame();
  131. auto frameContentSize = frame.ContentSize();
  132. if (frameContentSize.Width != m_lastSize.Width || frameContentSize.Height != m_lastSize.Height) {
  133. // The thing we have been capturing has changed size.
  134. // We need to resize our swap chain first, then blit the pixels.
  135. // After we do that, retire the frame and then recreate our frame pool.
  136. newSize = true;
  137. m_lastSize = frameContentSize;
  138. m_swapChain->ResizeBuffers(
  139. 2,
  140. static_cast<uint32_t>(m_lastSize.Width),
  141. static_cast<uint32_t>(m_lastSize.Height),
  142. static_cast<DXGI_FORMAT>(DirectXPixelFormat::B8G8R8A8UIntNormalized),
  143. 0);
  144. m_nv12Buffers.Clear();
  145. m_xrgbBuffers.Clear();
  146. }
  147. if (m_cnt > 0) {
  148. --m_cnt;
  149. }
  150. m_isCapture = (m_isCapture && !newSize) || m_cnt > 0;
  151. if (m_isCapture) {
  152. auto frameSurface = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
  153. D3D11_TEXTURE2D_DESC desc;
  154. frameSurface->GetDesc(&desc);
  155. auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(m_device);
  156. // 首先尝试创建 NV12 纹理
  157. auto tmpFormat = desc.Format;
  158. desc.Format = DXGI_FORMAT_NV12;
  159. if (GenNv12Frame(d3dDevice.get(), m_d3dContext.get(), desc, frameSurface.get(),
  160. m_nv12Buffers, m_nv12Frame, m_rgbToNv12)) {
  161. m_pixType = _PixType::NV12;
  162. } else {
  163. desc.Format = tmpFormat;
  164. GenRgbFrame(d3dDevice.get(), m_d3dContext.get(), desc, frameSurface.get(),
  165. m_xrgbBuffers, m_xrgbFrame);
  166. m_pixType = _PixType::RGB;
  167. }
  168. }
  169. // com_ptr<ID3D11Texture2D> backBuffer;
  170. // check_hresult(m_swapChain->GetBuffer(0, guid_of<ID3D11Texture2D>(), backBuffer.put_void()));
  171. // m_d3dContext->CopyResource(backBuffer.get(), m_bufferFiller.GetMap());
  172. // DXGI_PRESENT_PARAMETERS presentParameters = {0};
  173. // auto hr = m_swapChain->Present1(1, 0, &presentParameters);
  174. if (newSize) {
  175. m_framePool.Recreate(
  176. m_device,
  177. DirectXPixelFormat::B8G8R8A8UIntNormalized,
  178. 2,
  179. m_lastSize);
  180. }
  181. }