decklink start up to separate factory

This commit is contained in:
2026-05-22 15:27:46 +10:00
parent 315cbda9d1
commit 64a6125c3f
14 changed files with 330 additions and 88 deletions

View File

@@ -1,13 +1,11 @@
#include "app/AppConfig.h"
#include "app/AppConfigProvider.h"
#include "app/RenderCadenceApp.h"
#include "app/VideoBackendFactory.h"
#include "frames/InputFrameMailbox.h"
#include "frames/SystemFrameExchange.h"
#include "logging/Logger.h"
#include "render/thread/RenderThread.h"
#include "video/decklink/DeckLinkInput.h"
#include "video/decklink/DeckLinkInputThread.h"
#include "video/decklink/DeckLinkDisplayMode.h"
#include "video/core/VideoIOFormat.h"
#include "video/core/VideoMode.h"
@@ -17,7 +15,6 @@
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
namespace
{
@@ -49,18 +46,6 @@ private:
HRESULT mResult = S_OK;
};
bool WaitForInputWarmup(InputFrameMailbox& mailbox, std::size_t targetReadyFrames, std::chrono::milliseconds timeout)
{
const auto start = std::chrono::steady_clock::now();
while (std::chrono::steady_clock::now() - start < timeout)
{
const InputFrameMailboxMetrics metrics = mailbox.Metrics();
if (metrics.readyCount >= targetReadyFrames)
return true;
std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
return false;
}
}
int main(int argc, char** argv)
@@ -80,11 +65,11 @@ int main(int argc, char** argv)
RenderCadenceCompositor::Logger::Instance().Start(appConfig.logging);
RenderCadenceCompositor::Log(
"app",
"RenderCadenceCompositor starting. Starts render cadence, system-memory exchange, DeckLink scheduled output, and telemetry. Press Enter to stop.");
"RenderCadenceCompositor starting. Starts render cadence, configured video I/O backends, and telemetry. Press Enter to stop.");
RenderCadenceCompositor::Log("app", "Loaded config from " + configProvider.SourcePath().string());
ComInitGuard com;
if (!com.Initialize())
if (RenderCadenceCompositor::VideoBackendsRequireCom(appConfig) && !com.Initialize())
{
std::ostringstream message;
message << "COM initialization failed: 0x" << std::hex << com.Result();
@@ -126,7 +111,7 @@ int main(int argc, char** argv)
const bool outputVideoModeResolved = ResolveConfiguredVideoFormat(appConfig.outputVideoFormat, appConfig.outputFrameRate, outputVideoMode);
if (!inputVideoModeResolved)
{
inputVideoModeError = "Unsupported DeckLink inputVideoFormat/inputFrameRate in config/runtime-host.json: " +
inputVideoModeError = "Unsupported inputVideoFormat/inputFrameRate in config/runtime-host.json: " +
appConfig.inputVideoFormat + " / " + appConfig.inputFrameRate;
RenderCadenceCompositor::LogWarning("app", inputVideoModeError);
}
@@ -134,7 +119,7 @@ int main(int argc, char** argv)
{
RenderCadenceCompositor::LogWarning(
"app",
"Unsupported DeckLink outputVideoFormat/outputFrameRate in config/runtime-host.json; render cadence will use parsed frame-rate fallback: " +
"Unsupported outputVideoFormat/outputFrameRate in config/runtime-host.json; render cadence will use parsed frame-rate fallback: " +
appConfig.outputVideoFormat + " / " + appConfig.outputFrameRate);
}
else
@@ -142,55 +127,12 @@ int main(int argc, char** argv)
appConfig.deckLink.outputVideoMode = outputVideoMode;
}
RenderCadenceCompositor::DeckLinkInput deckLinkInput(inputMailbox);
RenderCadenceCompositor::DeckLinkInputThread deckLinkInputThread(deckLinkInput);
bool deckLinkInputStarted = false;
if (inputVideoModeResolved)
{
RenderCadenceCompositor::DeckLinkInputConfig deckLinkInputConfig;
deckLinkInputConfig.videoFormat = inputVideoMode;
std::string deckLinkInputError;
if (deckLinkInput.Initialize(deckLinkInputConfig, deckLinkInputError))
{
inputMailboxConfig.pixelFormat = deckLinkInput.CapturePixelFormat();
inputMailboxConfig.rowBytes = VideoIORowBytes(inputMailboxConfig.pixelFormat, inputMailboxConfig.width);
inputMailbox.Configure(inputMailboxConfig);
}
if (deckLinkInput.IsInitialized() && deckLinkInputThread.Start(deckLinkInputError))
{
deckLinkInputStarted = true;
RenderCadenceCompositor::Log("app", "DeckLink input edge started for " + inputVideoMode.displayName + ".");
RenderCadenceCompositor::Log("app", "Waiting for DeckLink input warmup frames.");
constexpr std::size_t kInputStartupBufferedFrames = 3;
constexpr std::chrono::milliseconds kInputWarmupTimeout(1000);
if (WaitForInputWarmup(inputMailbox, kInputStartupBufferedFrames, kInputWarmupTimeout))
{
const InputFrameMailboxMetrics metrics = inputMailbox.Metrics();
RenderCadenceCompositor::Log(
"app",
"DeckLink input warmup complete. ready=" + std::to_string(metrics.readyCount) +
" submitted=" + std::to_string(metrics.submittedFrames) + ".");
}
else
{
const InputFrameMailboxMetrics metrics = inputMailbox.Metrics();
RenderCadenceCompositor::LogWarning(
"app",
"DeckLink input warmup timed out; starting render cadence with current input buffer. ready=" +
std::to_string(metrics.readyCount) + " submitted=" + std::to_string(metrics.submittedFrames) + ".");
}
}
else
{
RenderCadenceCompositor::LogWarning("app", "DeckLink input edge unavailable; runtime shaders will use fallback input until a real input edge is available. " + deckLinkInputError);
deckLinkInput.ReleaseResources();
}
}
else
{
RenderCadenceCompositor::LogWarning("app", "DeckLink input mode was not resolved; runtime shaders will use fallback input until a real input edge is available.");
}
auto inputBackend = RenderCadenceCompositor::StartVideoInputBackend(
appConfig,
inputMailbox,
inputMailboxConfig,
inputVideoMode,
inputVideoModeResolved);
RenderThread::Config renderConfig;
renderConfig.width = frameExchangeConfig.width;
@@ -203,17 +145,22 @@ int main(int argc, char** argv)
RenderThread renderThread(frameExchange, &inputMailbox, renderConfig);
RenderCadenceCompositor::RenderCadenceApp<RenderThread, SystemFrameExchange> app(renderThread, frameExchange, appConfig);
app.SetVideoInputMetricsProvider([&deckLinkInput]() {
return deckLinkInput.Metrics();
auto outputBackend = RenderCadenceCompositor::CreateVideoOutputBackend(appConfig);
RenderCadenceCompositor::RenderCadenceApp<RenderThread, SystemFrameExchange> app(
renderThread,
frameExchange,
appConfig,
std::move(outputBackend));
app.SetVideoInputMetricsProvider([inputBackend = inputBackend.get()]() {
return inputBackend ? inputBackend->Metrics() : RenderCadenceCompositor::VideoInputEdgeMetrics();
});
std::string error;
if (!app.Start(error))
{
RenderCadenceCompositor::LogError("app", "RenderCadenceCompositor start failed: " + error);
if (deckLinkInputStarted)
deckLinkInputThread.Stop();
if (inputBackend)
inputBackend->Stop();
RenderCadenceCompositor::Logger::Instance().Stop();
return 1;
}
@@ -221,8 +168,8 @@ int main(int argc, char** argv)
std::string line;
std::getline(std::cin, line);
app.Stop();
if (deckLinkInputStarted)
deckLinkInputThread.Stop();
if (inputBackend)
inputBackend->Stop();
RenderCadenceCompositor::Log("app", "RenderCadenceCompositor stopped.");
RenderCadenceCompositor::Logger::Instance().Stop();
return 0;