Files
video-shader-toys/src/DeckLinkPipeline.h
2026-05-02 14:20:38 +10:00

94 lines
3.4 KiB
C++

#pragma once
#include "AppState.h"
#include "D3DProcessor.h"
#include "DeckLinkApi.h"
#include <wrl/client.h>
#include <atomic>
#include <mutex>
#include <string>
class DeckLinkPipeline;
class DeckLinkInputCallback final : public IDeckLinkInputCallback
{
public:
explicit DeckLinkInputCallback(DeckLinkPipeline& pipeline);
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID* ppv) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode* mode, BMDDetectedVideoInputFormatFlags flags) override;
HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame* videoFrame, IDeckLinkAudioInputPacket* audioPacket) override;
private:
std::atomic<ULONG> m_refCount = 1;
DeckLinkPipeline& m_pipeline;
};
class DeckLinkOutputCallback final : public IDeckLinkVideoOutputCallback
{
public:
explicit DeckLinkOutputCallback(DeckLinkPipeline& pipeline);
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID* ppv) override;
ULONG STDMETHODCALLTYPE AddRef() override;
ULONG STDMETHODCALLTYPE Release() override;
HRESULT STDMETHODCALLTYPE ScheduledFrameCompleted(IDeckLinkVideoFrame* completedFrame, BMDOutputFrameCompletionResult result) override;
HRESULT STDMETHODCALLTYPE ScheduledPlaybackHasStopped() override;
private:
std::atomic<ULONG> m_refCount = 1;
DeckLinkPipeline& m_pipeline;
};
class DeckLinkPipeline
{
public:
DeckLinkPipeline(AppState& appState, D3DProcessor& processor);
~DeckLinkPipeline();
bool initialize(std::string& error);
bool start(std::string& error);
void stop();
void onFormatChanged(IDeckLinkDisplayMode* mode, BMDDetectedVideoInputFormatFlags flags);
void onFrameArrived(IDeckLinkVideoInputFrame* videoFrame);
void onOutputFrameCompleted(BMDOutputFrameCompletionResult result);
private:
friend class DeckLinkInputCallback;
friend class DeckLinkOutputCallback;
bool selectDevice(std::string& error);
bool findStartupMode(Microsoft::WRL::ComPtr<IDeckLinkDisplayMode>& selectedMode, std::string& error);
bool configureForMode(IDeckLinkDisplayMode* mode, BMDPixelFormat inputFormat, std::string& error);
bool chooseOutputFormat(BMDDisplayMode displayMode, BMDPixelFormat& outputFormat);
void updateStatusLocked();
std::string deckLinkName(IDeckLink* deckLink) const;
std::string displayModeName(IDeckLinkDisplayMode* mode) const;
AppState& m_appState;
D3DProcessor& m_processor;
mutable std::recursive_mutex m_mutex;
Microsoft::WRL::ComPtr<IDeckLink> m_deckLink;
Microsoft::WRL::ComPtr<IDeckLinkInput> m_input;
Microsoft::WRL::ComPtr<IDeckLinkOutput> m_output;
Microsoft::WRL::ComPtr<IDeckLinkConfiguration> m_configuration;
Microsoft::WRL::ComPtr<IDeckLinkVideoConversion> m_converter;
Microsoft::WRL::ComPtr<IDeckLinkDisplayMode> m_activeMode;
Microsoft::WRL::ComPtr<DeckLinkInputCallback> m_inputCallback;
Microsoft::WRL::ComPtr<DeckLinkOutputCallback> m_outputCallback;
PipelineStatus m_status;
BMDPixelFormat m_inputFormat = bmdFormat8BitYUV;
BMDPixelFormat m_outputFormat = bmdFormat8BitARGB;
BMDTimeValue m_frameDuration = 1001;
BMDTimeScale m_frameTimescale = 30000;
uint64_t m_totalScheduled = 0;
bool m_initialized = false;
bool m_streamStarted = false;
};