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 }