/ src / modules / ZoomIt / ZoomIt / CaptureFrameWait.cpp
CaptureFrameWait.cpp
  1  //==============================================================================
  2  //
  3  // Zoomit
  4  // Sysinternals - www.sysinternals.com
  5  //
  6  // Video capture code derived from https://github.com/robmikh/capturevideosample
  7  //
  8  //==============================================================================
  9  #include "pch.h"
 10  #include "CaptureFrameWait.h"
 11  
 12  namespace winrt
 13  {
 14      using namespace Windows::Foundation;
 15      using namespace Windows::Graphics;
 16      using namespace Windows::Graphics::Capture;
 17      using namespace Windows::Graphics::DirectX;
 18      using namespace Windows::Graphics::DirectX::Direct3D11;
 19      using namespace Windows::Storage;
 20      using namespace Windows::UI::Composition;
 21  }
 22  
 23  namespace util
 24  {
 25      using namespace robmikh::common::uwp;
 26  }
 27  
 28  //----------------------------------------------------------------------------
 29  //
 30  // CaptureFrameWait::CaptureFrameWait
 31  //
 32  //----------------------------------------------------------------------------
 33  CaptureFrameWait::CaptureFrameWait(
 34      winrt::IDirect3DDevice const& device,
 35      winrt::GraphicsCaptureItem const& item,
 36      winrt::SizeInt32 const& size)
 37  {
 38      m_device = device;
 39      m_item = item;
 40  
 41      m_nextFrameEvent = wil::shared_event(wil::EventOptions::ManualReset);
 42      m_endEvent = wil::shared_event(wil::EventOptions::ManualReset);
 43      m_closedEvent = wil::shared_event(wil::EventOptions::ManualReset);
 44  
 45      m_framePool = winrt::Direct3D11CaptureFramePool::CreateFreeThreaded(
 46          m_device,
 47          winrt::DirectXPixelFormat::B8G8R8A8UIntNormalized,
 48          1,
 49          size);
 50      m_session = m_framePool.CreateCaptureSession(m_item);
 51  
 52      m_framePool.FrameArrived({ this, &CaptureFrameWait::OnFrameArrived });
 53      m_session.StartCapture();
 54  }
 55  
 56  //----------------------------------------------------------------------------
 57  //
 58  // CaptureFrameWait::~CaptureFrameWait
 59  //
 60  //----------------------------------------------------------------------------
 61  CaptureFrameWait::~CaptureFrameWait()
 62  {
 63      StopCapture();
 64      // We might end the capture before we ever get another frame.
 65      m_closedEvent.wait(200);
 66  }
 67  
 68  //----------------------------------------------------------------------------
 69  //
 70  // CaptureFrameWait::TryGetNextFrame
 71  //
 72  // Fetches next available frame
 73  //
 74  //----------------------------------------------------------------------------
 75  std::optional<CaptureFrame> CaptureFrameWait::TryGetNextFrame()
 76  {
 77      if (m_currentFrame != nullptr)
 78      {
 79          m_currentFrame.Close();
 80      }
 81      m_nextFrameEvent.ResetEvent();
 82  
 83      std::vector<HANDLE> events = { m_endEvent.get(), m_nextFrameEvent.get() };
 84      auto waitResult = WaitForMultipleObjectsEx(static_cast<DWORD>(events.size()), events.data(), false, INFINITE, false);
 85      auto eventIndex = -1;
 86      switch (waitResult)
 87      {
 88      case WAIT_OBJECT_0:
 89      case WAIT_OBJECT_0 + 1:
 90          eventIndex = waitResult - WAIT_OBJECT_0;
 91          break;
 92      }
 93      WINRT_VERIFY(eventIndex >= 0);
 94  
 95      auto signaledEvent = events[eventIndex];
 96      if (signaledEvent == m_endEvent.get())
 97      {
 98          return std::nullopt;
 99      }
100  
101      return std::optional<CaptureFrame>(
102          {
103              m_currentFrame.Surface(),
104              m_currentFrame.ContentSize(),
105              m_currentFrame.SystemRelativeTime(),
106          });
107  }
108  
109  
110  //----------------------------------------------------------------------------
111  //
112  // CaptureFrameWait::StopCapture
113  //
114  // Stops frame capture and notified any frame waiters
115  //
116  //----------------------------------------------------------------------------
117  void CaptureFrameWait::StopCapture()
118  {
119      auto lock = m_lock.lock_exclusive();
120      m_endEvent.SetEvent();
121      m_framePool.Close();
122      m_session.Close();
123  }
124  
125  //----------------------------------------------------------------------------
126  //
127  // CaptureFrameWait::OnFrameArrived
128  //
129  // Callback for new frames
130  //
131  //----------------------------------------------------------------------------
132  void CaptureFrameWait::OnFrameArrived(
133      winrt::Direct3D11CaptureFramePool const& sender,
134      winrt::IInspectable const&)
135  {
136      auto lock = m_lock.lock_exclusive();
137      if (m_endEvent.is_signaled())
138      {
139          m_closedEvent.SetEvent();
140          return;
141      }
142      auto frame = sender.TryGetNextFrame();
143      if( frame ) {
144          m_currentFrame = frame;
145          m_nextFrameEvent.SetEvent();
146      }
147  }