#pragma once #include "DeckLinkAPI_h.h" #include "DeckLinkDisplayMode.h" #include "DeckLinkFrameTransfer.h" #include "DeckLinkVideoIOFormat.h" #include "VideoIOFormat.h" #include "VideoIOTypes.h" #include "VideoPlayoutPolicy.h" #include "VideoPlayoutScheduler.h" #include #include #include #include #include class OpenGLComposite; class DeckLinkSession : public VideoIODevice { public: DeckLinkSession() = default; ~DeckLinkSession(); void ReleaseResources() override; bool DiscoverDevicesAndModes(const VideoFormatSelection& videoModes, std::string& error) override; bool SelectPreferredFormats(const VideoFormatSelection& videoModes, bool outputAlphaRequired, std::string& error) override; bool ConfigureInput(InputFrameCallback callback, const VideoFormat& inputVideoMode, std::string& error) override; bool ConfigureOutput(OutputFrameCallback callback, const VideoFormat& outputVideoMode, bool externalKeyingEnabled, std::string& error) override; bool PrepareOutputSchedule() override; bool StartInputStreams() override; bool StartScheduledPlayback() override; bool Start() override; bool Stop() override; bool HasInputDevice() const { return mState.hasInputDevice; } bool HasInputSource() const { return mState.hasInputSource; } void SetInputSourceMissing(bool missing) { mState.hasInputSource = !missing; } bool InputOutputDimensionsDiffer() const { return mState.inputFrameSize != mState.outputFrameSize; } const FrameSize& InputFrameSize() const { return mState.inputFrameSize; } const FrameSize& OutputFrameSize() const { return mState.outputFrameSize; } unsigned InputFrameWidth() const { return mState.inputFrameSize.width; } unsigned InputFrameHeight() const { return mState.inputFrameSize.height; } unsigned OutputFrameWidth() const { return mState.outputFrameSize.width; } unsigned OutputFrameHeight() const { return mState.outputFrameSize.height; } VideoIOPixelFormat InputPixelFormat() const { return mState.inputPixelFormat; } VideoIOPixelFormat OutputPixelFormat() const { return mState.outputPixelFormat; } bool InputIsTenBit() const { return VideoIOPixelFormatIsTenBit(mState.inputPixelFormat); } bool OutputIsTenBit() const { return VideoIOPixelFormatIsTenBit(mState.outputPixelFormat); } unsigned InputFrameRowBytes() const { return mState.inputFrameRowBytes; } unsigned OutputFrameRowBytes() const { return mState.outputFrameRowBytes; } unsigned CaptureTextureWidth() const { return mState.captureTextureWidth; } unsigned OutputPackTextureWidth() const { return mState.outputPackTextureWidth; } const std::string& FormatStatusMessage() const { return mState.formatStatusMessage; } const std::string& InputDisplayModeName() const { return mState.inputDisplayModeName; } const std::string& OutputModelName() const { return mState.outputModelName; } bool SupportsInternalKeying() const { return mState.supportsInternalKeying; } bool SupportsExternalKeying() const { return mState.supportsExternalKeying; } bool KeyerInterfaceAvailable() const { return mState.keyerInterfaceAvailable; } bool ExternalKeyingActive() const { return mState.externalKeyingActive; } const std::string& StatusMessage() const { return mState.statusMessage; } void SetStatusMessage(const std::string& message) { mState.statusMessage = message; } const VideoIOState& State() const override { return mState; } VideoIOState& MutableState() override { return mState; } double FrameBudgetMilliseconds() const; VideoPlayoutRecoveryDecision AccountForCompletionResult(VideoIOCompletionResult completionResult, uint64_t readyQueueDepth) override; bool BeginOutputFrame(VideoIOOutputFrame& frame) override; void EndOutputFrame(VideoIOOutputFrame& frame) override; bool ScheduleOutputFrame(const VideoIOOutputFrame& frame) override; void HandleVideoInputFrame(IDeckLinkVideoInputFrame* inputFrame, bool hasNoInputSource); void HandlePlayoutFrameCompleted(IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult completionResult); private: bool AcquireNextOutputVideoFrame(CComPtr& outputVideoFrame); bool PopulateOutputFrame(IDeckLinkMutableVideoFrame* outputVideoFrame, VideoIOOutputFrame& frame); bool ScheduleFrame(IDeckLinkMutableVideoFrame* outputVideoFrame); void UpdateScheduleLeadTelemetry(); void MaybeRealignScheduleCursorForLowLead(); void RealignScheduleCursorToPlayback(); bool ScheduleSystemMemoryFrame(const VideoIOOutputFrame& frame); bool ScheduleBlackFrame(IDeckLinkMutableVideoFrame* outputVideoFrame); void RefreshBufferedVideoFrameCount(); static VideoIOCompletionResult TranslateCompletionResult(BMDOutputFrameCompletionResult completionResult); CComPtr captureDelegate; CComPtr playoutDelegate; CComPtr input; CComPtr output; CComPtr keyer; std::deque> outputVideoFrameQueue; std::mutex mScheduledSystemFrameMutex; std::unordered_map mScheduledSystemFrameBuffers; VideoIOState mState; VideoPlayoutPolicy mPlayoutPolicy; VideoPlayoutScheduler mScheduler; bool mScheduleRealignmentPending = false; bool mScheduleRealignmentArmed = true; bool mProactiveScheduleRealignmentArmed = true; InputFrameCallback mInputFrameCallback; OutputFrameCallback mOutputFrameCallback; };