SimpleCapture.cpp 5.7 KB

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