Update VideoBackendFactory.cpp

This commit is contained in:
2026-05-22 15:51:44 +10:00
parent 2fdb1741f9
commit 6e8f18e24c

View File

@@ -7,9 +7,13 @@
#include "video/decklink/DeckLinkOutput.h" #include "video/decklink/DeckLinkOutput.h"
#include <algorithm> #include <algorithm>
#include <cctype>
#include <chrono> #include <chrono>
#include <functional>
#include <memory> #include <memory>
#include <string_view>
#include <thread> #include <thread>
#include <vector>
namespace RenderCadenceCompositor namespace RenderCadenceCompositor
{ {
@@ -26,15 +30,9 @@ std::string NormalizeBackendName(std::string name)
return name; return name;
} }
bool IsDeckLinkBackend(const std::string& name) bool BackendNameMatches(std::string_view normalizedName, const std::vector<std::string_view>& aliases)
{ {
return NormalizeBackendName(name) == "decklink"; return std::find(aliases.begin(), aliases.end(), normalizedName) != aliases.end();
}
bool IsNoneBackend(const std::string& name)
{
const std::string normalized = NormalizeBackendName(name);
return normalized == "none" || normalized == "disabled" || normalized == "off";
} }
bool WaitForInputWarmup(InputFrameMailbox& mailbox, std::size_t targetReadyFrames, std::chrono::milliseconds timeout) bool WaitForInputWarmup(InputFrameMailbox& mailbox, std::size_t targetReadyFrames, std::chrono::milliseconds timeout)
@@ -50,6 +48,32 @@ bool WaitForInputWarmup(InputFrameMailbox& mailbox, std::size_t targetReadyFrame
return false; return false;
} }
struct VideoInputBackendStartContext
{
const AppConfig& config;
InputFrameMailbox& mailbox;
InputFrameMailboxConfig& mailboxConfig;
const VideoFormat& inputVideoMode;
bool inputVideoModeResolved = false;
};
using VideoOutputBackendCreateFn = std::unique_ptr<IVideoOutputEdge> (*)();
using VideoInputBackendStartFn = std::unique_ptr<VideoInputBackendSession> (*)(const VideoInputBackendStartContext&);
struct VideoOutputBackendRegistration
{
std::vector<std::string_view> aliases;
bool requiresCom = false;
VideoOutputBackendCreateFn create = nullptr;
};
struct VideoInputBackendRegistration
{
std::vector<std::string_view> aliases;
bool requiresCom = false;
VideoInputBackendStartFn start = nullptr;
};
class DisabledVideoOutputEdge final : public IVideoOutputEdge class DisabledVideoOutputEdge final : public IVideoOutputEdge
{ {
public: public:
@@ -174,20 +198,95 @@ private:
DeckLinkInputThread mThread; DeckLinkInputThread mThread;
bool mStarted = false; bool mStarted = false;
}; };
std::unique_ptr<IVideoOutputEdge> CreateDeckLinkOutputBackend()
{
return std::make_unique<DeckLinkOutput>();
}
std::unique_ptr<IVideoOutputEdge> CreateDisabledOutputBackend()
{
return std::make_unique<DisabledVideoOutputEdge>("Video output backend is disabled by config.");
}
std::unique_ptr<VideoInputBackendSession> StartNoInputBackend(const VideoInputBackendStartContext&)
{
Log("app", "Video input backend disabled by config.");
return std::make_unique<NoInputBackendSession>("none");
}
std::unique_ptr<VideoInputBackendSession> StartDeckLinkInputBackend(const VideoInputBackendStartContext& context)
{
if (!context.inputVideoModeResolved)
{
LogWarning("app", "DeckLink input mode was not resolved; runtime shaders will use fallback input until a real input edge is available.");
return std::make_unique<NoInputBackendSession>("decklink");
}
auto session = std::make_unique<DeckLinkInputBackendSession>(context.mailbox);
std::string error;
if (!session->Start(context.mailbox, context.mailboxConfig, context.inputVideoMode, error))
{
LogWarning("app", "DeckLink input edge unavailable; runtime shaders will use fallback input until a real input edge is available. " + error);
return std::make_unique<NoInputBackendSession>("decklink");
}
return session;
}
const std::vector<VideoOutputBackendRegistration>& VideoOutputBackendRegistry()
{
static const std::vector<VideoOutputBackendRegistration> registry = {
VideoOutputBackendRegistration{ { "decklink" }, true, &CreateDeckLinkOutputBackend },
VideoOutputBackendRegistration{ { "none", "disabled", "off" }, false, &CreateDisabledOutputBackend },
};
return registry;
}
const std::vector<VideoInputBackendRegistration>& VideoInputBackendRegistry()
{
static const std::vector<VideoInputBackendRegistration> registry = {
VideoInputBackendRegistration{ { "decklink" }, true, &StartDeckLinkInputBackend },
VideoInputBackendRegistration{ { "none", "disabled", "off" }, false, &StartNoInputBackend },
};
return registry;
}
const VideoOutputBackendRegistration* FindVideoOutputBackend(std::string_view backendName)
{
for (const VideoOutputBackendRegistration& backend : VideoOutputBackendRegistry())
{
if (BackendNameMatches(backendName, backend.aliases))
return &backend;
}
return nullptr;
}
const VideoInputBackendRegistration* FindVideoInputBackend(std::string_view backendName)
{
for (const VideoInputBackendRegistration& backend : VideoInputBackendRegistry())
{
if (BackendNameMatches(backendName, backend.aliases))
return &backend;
}
return nullptr;
}
} }
bool VideoBackendsRequireCom(const AppConfig& config) bool VideoBackendsRequireCom(const AppConfig& config)
{ {
return IsDeckLinkBackend(config.videoInputBackend) || IsDeckLinkBackend(config.videoOutputBackend); const std::string inputBackend = NormalizeBackendName(config.videoInputBackend);
const std::string outputBackend = NormalizeBackendName(config.videoOutputBackend);
const VideoInputBackendRegistration* input = FindVideoInputBackend(inputBackend);
const VideoOutputBackendRegistration* output = FindVideoOutputBackend(outputBackend);
return (input != nullptr && input->requiresCom) || (output != nullptr && output->requiresCom);
} }
std::unique_ptr<IVideoOutputEdge> CreateVideoOutputBackend(const AppConfig& config) std::unique_ptr<IVideoOutputEdge> CreateVideoOutputBackend(const AppConfig& config)
{ {
if (IsDeckLinkBackend(config.videoOutputBackend)) const std::string backendName = NormalizeBackendName(config.videoOutputBackend);
return std::make_unique<DeckLinkOutput>(); const VideoOutputBackendRegistration* backend = FindVideoOutputBackend(backendName);
if (backend != nullptr && backend->create != nullptr)
if (IsNoneBackend(config.videoOutputBackend)) return backend->create();
return std::make_unique<DisabledVideoOutputEdge>("Video output backend is disabled by config.");
return std::make_unique<DisabledVideoOutputEdge>("Unsupported videoOutputBackend: " + config.videoOutputBackend); return std::make_unique<DisabledVideoOutputEdge>("Unsupported videoOutputBackend: " + config.videoOutputBackend);
} }
@@ -199,31 +298,15 @@ std::unique_ptr<VideoInputBackendSession> StartVideoInputBackend(
const VideoFormat& inputVideoMode, const VideoFormat& inputVideoMode,
bool inputVideoModeResolved) bool inputVideoModeResolved)
{ {
if (IsNoneBackend(config.videoInputBackend)) const std::string backendName = NormalizeBackendName(config.videoInputBackend);
const VideoInputBackendRegistration* backend = FindVideoInputBackend(backendName);
if (backend != nullptr && backend->start != nullptr)
{ {
Log("app", "Video input backend disabled by config."); VideoInputBackendStartContext context{ config, mailbox, mailboxConfig, inputVideoMode, inputVideoModeResolved };
return std::make_unique<NoInputBackendSession>("none"); return backend->start(context);
} }
if (!IsDeckLinkBackend(config.videoInputBackend)) LogWarning("app", "Unsupported videoInputBackend '" + config.videoInputBackend + "'; runtime shaders will use fallback input.");
{ return std::make_unique<NoInputBackendSession>(config.videoInputBackend);
LogWarning("app", "Unsupported videoInputBackend '" + config.videoInputBackend + "'; runtime shaders will use fallback input.");
return std::make_unique<NoInputBackendSession>(config.videoInputBackend);
}
if (!inputVideoModeResolved)
{
LogWarning("app", "DeckLink input mode was not resolved; runtime shaders will use fallback input until a real input edge is available.");
return std::make_unique<NoInputBackendSession>("decklink");
}
auto session = std::make_unique<DeckLinkInputBackendSession>(mailbox);
std::string error;
if (!session->Start(mailbox, mailboxConfig, inputVideoMode, error))
{
LogWarning("app", "DeckLink input edge unavailable; runtime shaders will use fallback input until a real input edge is available. " + error);
return std::make_unique<NoInputBackendSession>("decklink");
}
return session;
} }
} }