#pragma once #include "DeckLinkInput.h" #include #include #include #include namespace RenderCadenceCompositor { struct DeckLinkInputThreadConfig { std::chrono::milliseconds idleSleep = std::chrono::milliseconds(100); }; class DeckLinkInputThread { public: DeckLinkInputThread(DeckLinkInput& input, DeckLinkInputThreadConfig config = DeckLinkInputThreadConfig()) : mInput(input), mConfig(config) { } DeckLinkInputThread(const DeckLinkInputThread&) = delete; DeckLinkInputThread& operator=(const DeckLinkInputThread&) = delete; ~DeckLinkInputThread() { Stop(); } bool Start(std::string& error) { if (mThread.joinable()) return true; mStartSucceeded.store(false, std::memory_order_release); mStartCompleted.store(false, std::memory_order_release); mStopping.store(false, std::memory_order_release); mThread = std::thread([this]() { ThreadMain(); }); while (!mStartCompleted.load(std::memory_order_acquire)) std::this_thread::sleep_for(std::chrono::milliseconds(1)); if (mStartSucceeded.load(std::memory_order_acquire)) return true; error = mStartError; Stop(); return false; } void Stop() { mStopping.store(true, std::memory_order_release); if (mThread.joinable()) mThread.join(); } private: void ThreadMain() { std::string error; if (!mInput.Start(error)) { mStartError = error; mStartCompleted.store(true, std::memory_order_release); return; } mStartSucceeded.store(true, std::memory_order_release); mStartCompleted.store(true, std::memory_order_release); while (!mStopping.load(std::memory_order_acquire)) std::this_thread::sleep_for(mConfig.idleSleep); mInput.Stop(); } DeckLinkInput& mInput; DeckLinkInputThreadConfig mConfig; std::thread mThread; std::atomic mStopping{ false }; std::atomic mStartCompleted{ false }; std::atomic mStartSucceeded{ false }; std::string mStartError; }; }