SimpleCapture.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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_0_255; // 修复:使用相同的颜色范围
  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. qDebug() << "SimpleCapture::Close: Starting cleanup";
  110. auto expected = false;
  111. if (m_closed.compare_exchange_strong(expected, true)) {
  112. qDebug() << "SimpleCapture::Close: Revoking frame callback and closing WGC resources";
  113. m_frameArrived.revoke();
  114. // 先停止捕获会话
  115. if (m_session) {
  116. m_session.Close();
  117. m_session = nullptr;
  118. }
  119. // 然后关闭帧池
  120. if (m_framePool) {
  121. m_framePool.Close();
  122. m_framePool = nullptr;
  123. }
  124. // 释放交换链
  125. m_swapChain = nullptr;
  126. m_item = nullptr;
  127. }
  128. // 清理缓冲区
  129. qDebug() << "SimpleCapture::Close: Clearing buffers";
  130. m_nv12Buffers.Clear();
  131. m_xrgbBuffers.Clear();
  132. // 释放D3D转换器(在释放帧之前)
  133. qDebug() << "SimpleCapture::Close: Closing D3D converter";
  134. m_rgbToNv12.Close();
  135. // 最后释放帧
  136. qDebug() << "SimpleCapture::Close: Freeing frames";
  137. Free(m_nv12Frame, [this] { av_frame_free(&m_nv12Frame); });
  138. Free(m_xrgbFrame, [this] { av_frame_free(&m_xrgbFrame); });
  139. qDebug() << "SimpleCapture::Close: Cleanup completed";
  140. }
  141. void SimpleCapture::OnFrameArrived(
  142. Direct3D11CaptureFramePool const& sender,
  143. winrt::Windows::Foundation::IInspectable const&)
  144. {
  145. auto newSize = false;
  146. auto frame = sender.TryGetNextFrame();
  147. auto frameContentSize = frame.ContentSize();
  148. if (frameContentSize.Width != m_lastSize.Width || frameContentSize.Height != m_lastSize.Height) {
  149. // The thing we have been capturing has changed size.
  150. // We need to resize our swap chain first, then blit the pixels.
  151. // After we do that, retire the frame and then recreate our frame pool.
  152. newSize = true;
  153. m_lastSize = frameContentSize;
  154. m_swapChain->ResizeBuffers(
  155. 2,
  156. static_cast<uint32_t>(m_lastSize.Width),
  157. static_cast<uint32_t>(m_lastSize.Height),
  158. static_cast<DXGI_FORMAT>(DirectXPixelFormat::B8G8R8A8UIntNormalized),
  159. 0);
  160. m_nv12Buffers.Clear();
  161. m_xrgbBuffers.Clear();
  162. }
  163. if (m_cnt > 0) {
  164. --m_cnt;
  165. }
  166. m_isCapture = (m_isCapture && !newSize) || m_cnt > 0;
  167. if (m_isCapture) {
  168. auto frameSurface = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
  169. D3D11_TEXTURE2D_DESC desc;
  170. frameSurface->GetDesc(&desc);
  171. auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(m_device);
  172. // 首先尝试创建 NV12 纹理
  173. auto tmpFormat = desc.Format;
  174. desc.Format = DXGI_FORMAT_NV12;
  175. if (GenNv12Frame(d3dDevice.get(), m_d3dContext.get(), desc, frameSurface.get(),
  176. m_nv12Buffers, m_nv12Frame, m_rgbToNv12)) {
  177. m_pixType = _PixType::NV12;
  178. } else {
  179. desc.Format = tmpFormat;
  180. GenRgbFrame(d3dDevice.get(), m_d3dContext.get(), desc, frameSurface.get(),
  181. m_xrgbBuffers, m_xrgbFrame);
  182. m_pixType = _PixType::RGB;
  183. }
  184. }
  185. // com_ptr<ID3D11Texture2D> backBuffer;
  186. // check_hresult(m_swapChain->GetBuffer(0, guid_of<ID3D11Texture2D>(), backBuffer.put_void()));
  187. // m_d3dContext->CopyResource(backBuffer.get(), m_bufferFiller.GetMap());
  188. // DXGI_PRESENT_PARAMETERS presentParameters = {0};
  189. // auto hr = m_swapChain->Present1(1, 0, &presentParameters);
  190. if (newSize) {
  191. m_framePool.Recreate(
  192. m_device,
  193. DirectXPixelFormat::B8G8R8A8UIntNormalized,
  194. 2,
  195. m_lastSize);
  196. }
  197. }