#pragma once #include "OutputProductionController.h" #include "RenderCadenceController.h" #include "RenderOutputQueue.h" #include "SystemOutputFramePool.h" #include "VideoBackendLifecycle.h" #include "VideoIOTypes.h" #include "VideoPlayoutPolicy.h" #include #include #include #include #include #include #include #include class HealthTelemetry; class OpenGLVideoIOBridge; class RenderEngine; class RuntimeEventDispatcher; class VideoIODevice; class VideoBackend { public: VideoBackend(RenderEngine& renderEngine, HealthTelemetry& healthTelemetry, RuntimeEventDispatcher& runtimeEventDispatcher); ~VideoBackend(); void ReleaseResources(); VideoBackendLifecycleState LifecycleState() const; bool DiscoverDevicesAndModes(const VideoFormatSelection& videoModes, std::string& error); bool SelectPreferredFormats(const VideoFormatSelection& videoModes, bool outputAlphaRequired, std::string& error); bool ConfigureInput(const VideoFormat& inputVideoMode, std::string& error); bool ConfigureOutput(const VideoFormat& outputVideoMode, bool externalKeyingEnabled, std::string& error); bool Start(); bool Stop(); const VideoIOState& State() const; VideoIOState& MutableState(); bool BeginOutputFrame(VideoIOOutputFrame& frame); void EndOutputFrame(VideoIOOutputFrame& frame); bool ScheduleOutputFrame(const VideoIOOutputFrame& frame); VideoPlayoutRecoveryDecision AccountForCompletionResult(VideoIOCompletionResult result, uint64_t readyQueueDepth); void RecordBackendPlayoutHealth(VideoIOCompletionResult result, const VideoPlayoutRecoveryDecision& recoveryDecision); bool HasInputDevice() const; bool HasInputSource() const; unsigned InputFrameWidth() const; unsigned InputFrameHeight() const; unsigned OutputFrameWidth() const; unsigned OutputFrameHeight() const; unsigned CaptureTextureWidth() const; unsigned OutputPackTextureWidth() const; VideoIOPixelFormat InputPixelFormat() const; const std::string& InputDisplayModeName() const; const std::string& OutputModelName() const; bool SupportsInternalKeying() const; bool SupportsExternalKeying() const; bool KeyerInterfaceAvailable() const; bool ExternalKeyingActive() const; const std::string& StatusMessage() const; bool ShouldPrioritizeOutputOverPreview() const; void SetStatusMessage(const std::string& message); void PublishStatus(bool externalKeyingConfigured, const std::string& statusMessage = std::string()); void ReportNoInputDeviceSignalStatus(); private: void HandleInputFrame(const VideoIOFrame& frame); void HandleOutputFrameCompletion(const VideoIOCompletion& completion); void StartOutputCompletionWorker(); void StopOutputCompletionWorker(); void OutputCompletionWorkerMain(); void StartOutputProducerWorker(); void StopOutputProducerWorker(); void OutputProducerWorkerMain(); void NotifyOutputProducer(); bool WarmupOutputPreroll(); std::chrono::milliseconds OutputProducerWakeInterval() const; void ProcessOutputFrameCompletion(const VideoIOCompletion& completion); std::size_t ProduceReadyOutputFrames(const VideoIOCompletion& completion, std::size_t maxFrames); OutputProductionPressure BuildOutputProductionPressure(const RenderOutputQueueMetrics& metrics) const; bool RenderReadyOutputFrame(const VideoIOState& state, const VideoIOCompletion& completion); std::size_t ScheduleReadyOutputFramesToTarget(); bool ScheduleReadyOutputFrame(); bool ScheduleBlackUnderrunFrame(); void RecordFramePacing(VideoIOCompletionResult completionResult); void RecordReadyQueueDepthSample(const RenderOutputQueueMetrics& metrics); void RecordDeckLinkBufferTelemetry(); void RecordSystemMemoryPlayoutStats(); void RecordOutputRenderDuration(double renderMilliseconds, double acquireMilliseconds, double renderRequestMilliseconds, double endAccessMilliseconds); bool ApplyLifecycleTransition(VideoBackendLifecycleState state, const std::string& message); bool ApplyLifecycleFailure(const std::string& message); void PublishBackendStateChanged(const std::string& state, const std::string& message); void PublishInputSignalChanged(const VideoIOFrame& frame, const VideoIOState& state); void PublishInputFrameArrived(const VideoIOFrame& frame); void PublishOutputFrameScheduled(const VideoIOOutputFrame& frame); void PublishOutputFrameCompleted(const VideoIOCompletion& completion); void PublishTimingSample(const std::string& subsystem, const std::string& metric, double value, const std::string& unit); static std::string CompletionResultName(VideoIOCompletionResult result); static std::string PixelFormatName(VideoIOPixelFormat pixelFormat); HealthTelemetry& mHealthTelemetry; RuntimeEventDispatcher& mRuntimeEventDispatcher; VideoBackendLifecycle mLifecycle; VideoPlayoutPolicy mPlayoutPolicy; OutputProductionController mOutputProductionController; RenderCadenceController mRenderCadenceController; RenderOutputQueue mReadyOutputQueue; SystemOutputFramePool mSystemOutputFramePool; std::unique_ptr mVideoIODevice; std::unique_ptr mBridge; std::mutex mOutputCompletionMutex; std::condition_variable mOutputCompletionCondition; std::deque mPendingOutputCompletions; std::thread mOutputCompletionWorker; std::mutex mOutputProducerMutex; std::condition_variable mOutputProducerCondition; std::thread mOutputProducerWorker; VideoIOCompletion mLastOutputProductionCompletion; std::chrono::steady_clock::time_point mLastOutputProductionTime; std::mutex mOutputProductionMutex; std::mutex mOutputSchedulingMutex; mutable std::mutex mOutputMetricsMutex; bool mOutputCompletionWorkerRunning = false; bool mOutputCompletionWorkerStopping = false; bool mOutputProducerWorkerRunning = false; bool mOutputProducerWorkerStopping = false; uint64_t mNextReadyOutputFrameIndex = 0; uint64_t mInputFrameIndex = 0; uint64_t mOutputFrameScheduleIndex = 0; uint64_t mOutputFrameCompletionIndex = 0; bool mHasLastInputSignal = false; bool mLastInputSignal = false; unsigned mLastInputSignalWidth = 0; unsigned mLastInputSignalHeight = 0; std::string mLastInputSignalModeName; std::chrono::steady_clock::time_point mLastPlayoutCompletionTime; double mCompletionIntervalMilliseconds = 0.0; double mSmoothedCompletionIntervalMilliseconds = 0.0; double mMaxCompletionIntervalMilliseconds = 0.0; bool mHasReadyQueueDepthBaseline = false; std::size_t mMinReadyQueueDepth = 0; std::size_t mMaxReadyQueueDepth = 0; uint64_t mReadyQueueZeroDepthCount = 0; double mOutputRenderMilliseconds = 0.0; double mSmoothedOutputRenderMilliseconds = 0.0; double mMaxOutputRenderMilliseconds = 0.0; double mOutputFrameAcquireMilliseconds = 0.0; double mOutputFrameRenderRequestMilliseconds = 0.0; double mOutputFrameEndAccessMilliseconds = 0.0; uint64_t mLastLateStreak = 0; uint64_t mLastDropStreak = 0; uint64_t mLateFrameCount = 0; uint64_t mDroppedFrameCount = 0; uint64_t mFlushedFrameCount = 0; };