SimpleCapture.cpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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. __CheckNo(m_nv12Frame);
  82. __CheckNo(m_xrgbFrame);
  83. m_isCapture = true;
  84. m_cnt = 5;
  85. }
  86. // Start sending capture frames
  87. void SimpleCapture::StartCapture()
  88. {
  89. CheckClosed();
  90. m_session.StartCapture();
  91. }
  92. ICompositionSurface SimpleCapture::CreateSurface(
  93. Compositor const& compositor)
  94. {
  95. CheckClosed();
  96. return CreateCompositionSurfaceForSwapChain(compositor, m_swapChain.get());
  97. }
  98. // Process captured frames
  99. void SimpleCapture::Close()
  100. {
  101. auto expected = false;
  102. if (m_closed.compare_exchange_strong(expected, true)) {
  103. m_frameArrived.revoke();
  104. m_framePool.Close();
  105. m_session.Close();
  106. m_swapChain = nullptr;
  107. m_framePool = nullptr;
  108. m_session = nullptr;
  109. m_item = nullptr;
  110. }
  111. m_nv12Buffers.Clear();
  112. m_xrgbBuffers.Clear();
  113. m_rgbToNv12.Close();
  114. Free(m_nv12Frame, [this] { av_frame_free(&m_nv12Frame); });
  115. Free(m_xrgbFrame, [this] { av_frame_free(&m_xrgbFrame); });
  116. }
  117. void SimpleCapture::OnFrameArrived(
  118. Direct3D11CaptureFramePool const& sender,
  119. winrt::Windows::Foundation::IInspectable const&)
  120. {
  121. auto newSize = false;
  122. auto frame = sender.TryGetNextFrame();
  123. auto frameContentSize = frame.ContentSize();
  124. if (frameContentSize.Width != m_lastSize.Width || frameContentSize.Height != m_lastSize.Height) {
  125. // The thing we have been capturing has changed size.
  126. // We need to resize our swap chain first, then blit the pixels.
  127. // After we do that, retire the frame and then recreate our frame pool.
  128. newSize = true;
  129. m_lastSize = frameContentSize;
  130. m_swapChain->ResizeBuffers(
  131. 2,
  132. static_cast<uint32_t>(m_lastSize.Width),
  133. static_cast<uint32_t>(m_lastSize.Height),
  134. static_cast<DXGI_FORMAT>(DirectXPixelFormat::B8G8R8A8UIntNormalized),
  135. 0);
  136. m_nv12Buffers.Clear();
  137. m_xrgbBuffers.Clear();
  138. }
  139. if (m_cnt > 0) {
  140. --m_cnt;
  141. }
  142. m_isCapture = (m_isCapture && !newSize) || m_cnt > 0;
  143. if (m_isCapture) {
  144. auto frameSurface = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
  145. D3D11_TEXTURE2D_DESC desc;
  146. frameSurface->GetDesc(&desc);
  147. auto d3dDevice = GetDXGIInterfaceFromObject<ID3D11Device>(m_device);
  148. // 首先尝试创建 NV12 纹理
  149. auto tmpFormat = desc.Format;
  150. desc.Format = DXGI_FORMAT_NV12;
  151. if (GenNv12Frame(d3dDevice.get(), m_d3dContext.get(), desc, frameSurface.get(),
  152. m_nv12Buffers, m_nv12Frame, m_rgbToNv12)) {
  153. m_pixType = _PixType::NV12;
  154. } else {
  155. desc.Format = tmpFormat;
  156. GenRgbFrame(d3dDevice.get(), m_d3dContext.get(), desc, frameSurface.get(),
  157. m_xrgbBuffers, m_xrgbFrame);
  158. m_pixType = _PixType::RGB;
  159. }
  160. }
  161. // com_ptr<ID3D11Texture2D> backBuffer;
  162. // check_hresult(m_swapChain->GetBuffer(0, guid_of<ID3D11Texture2D>(), backBuffer.put_void()));
  163. // m_d3dContext->CopyResource(backBuffer.get(), m_bufferFiller.GetMap());
  164. // DXGI_PRESENT_PARAMETERS presentParameters = {0};
  165. // auto hr = m_swapChain->Present1(1, 0, &presentParameters);
  166. if (newSize) {
  167. m_framePool.Recreate(
  168. m_device,
  169. DirectXPixelFormat::B8G8R8A8UIntNormalized,
  170. 2,
  171. m_lastSize);
  172. }
  173. }