#pragma once #include "RenderOutputQueue.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; 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 ProcessOutputFrameCompletion(const VideoIOCompletion& completion); bool FillReadyOutputQueue(const VideoIOCompletion& completion); bool RenderReadyOutputFrame(const VideoIOState& state, const VideoIOCompletion& completion); bool ScheduleReadyOutputFrame(); bool ScheduleBlackUnderrunFrame(); void RecordFramePacing(VideoIOCompletionResult completionResult); void RecordReadyQueueDepthSample(const RenderOutputQueueMetrics& metrics); void RecordOutputRenderDuration(double renderMilliseconds); 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; RenderOutputQueue mReadyOutputQueue; std::unique_ptr mVideoIODevice; std::unique_ptr mBridge; std::mutex mOutputCompletionMutex; std::condition_variable mOutputCompletionCondition; std::deque mPendingOutputCompletions; std::thread mOutputCompletionWorker; bool mOutputCompletionWorkerRunning = false; bool mOutputCompletionWorkerStopping = 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; uint64_t mLateFrameCount = 0; uint64_t mDroppedFrameCount = 0; uint64_t mFlushedFrameCount = 0; };