Files
video-shader-toys/apps/RenderCadenceCompositor/RenderCadenceCompositor.cpp
Aiden ce28904891
All checks were successful
CI / React UI Build (push) Successful in 11s
CI / Native Windows Build And Tests (push) Successful in 3m2s
CI / Windows Release Package (push) Has been skipped
input testing
2026-05-12 20:06:23 +10:00

164 lines
5.4 KiB
C++

#include "app/AppConfig.h"
#include "app/AppConfigProvider.h"
#include "app/RenderCadenceApp.h"
#include "frames/InputFrameMailbox.h"
#include "frames/SystemFrameExchange.h"
#include "logging/Logger.h"
#include "render/RenderThread.h"
#include "video/DeckLinkInput.h"
#include "video/DeckLinkInputThread.h"
#include "DeckLinkDisplayMode.h"
#include "VideoIOFormat.h"
#include <windows.h>
#include <iostream>
#include <sstream>
#include <string>
namespace
{
class ComInitGuard
{
public:
~ComInitGuard()
{
if (mInitialized)
CoUninitialize();
}
bool Initialize()
{
const HRESULT result = CoInitialize(nullptr);
mInitialized = SUCCEEDED(result);
mResult = result;
return mInitialized;
}
HRESULT Result() const { return mResult; }
private:
bool mInitialized = false;
HRESULT mResult = S_OK;
};
}
int main(int argc, char** argv)
{
RenderCadenceCompositor::AppConfigProvider configProvider;
std::string configError;
if (!configProvider.LoadDefault(configError))
{
RenderCadenceCompositor::Logger::Instance().Start(RenderCadenceCompositor::DefaultAppConfig().logging);
RenderCadenceCompositor::LogError("app", "Config load failed: " + configError);
RenderCadenceCompositor::Logger::Instance().Stop();
return 1;
}
configProvider.ApplyCommandLine(argc, argv);
RenderCadenceCompositor::AppConfig appConfig = configProvider.Config();
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::Log("app", "Loaded config from " + configProvider.SourcePath().string());
ComInitGuard com;
if (!com.Initialize())
{
std::ostringstream message;
message << "COM initialization failed: 0x" << std::hex << com.Result();
RenderCadenceCompositor::LogError("app", message.str());
RenderCadenceCompositor::Logger::Instance().Stop();
return 1;
}
SystemFrameExchangeConfig frameExchangeConfig;
RenderCadenceCompositor::VideoFormatDimensions(
appConfig.outputVideoFormat,
frameExchangeConfig.width,
frameExchangeConfig.height);
frameExchangeConfig.pixelFormat = VideoIOPixelFormat::Bgra8;
frameExchangeConfig.rowBytes = VideoIORowBytes(frameExchangeConfig.pixelFormat, frameExchangeConfig.width);
frameExchangeConfig.capacity = 12;
SystemFrameExchange frameExchange(frameExchangeConfig);
InputFrameMailboxConfig inputMailboxConfig;
RenderCadenceCompositor::VideoFormatDimensions(
appConfig.inputVideoFormat,
inputMailboxConfig.width,
inputMailboxConfig.height);
inputMailboxConfig.pixelFormat = VideoIOPixelFormat::Bgra8;
inputMailboxConfig.rowBytes = VideoIORowBytes(inputMailboxConfig.pixelFormat, inputMailboxConfig.width);
inputMailboxConfig.capacity = 4;
InputFrameMailbox inputMailbox(inputMailboxConfig);
VideoFormat inputVideoMode;
std::string inputVideoModeError;
const bool inputVideoModeResolved = ResolveConfiguredVideoFormat(appConfig.inputVideoFormat, appConfig.inputFrameRate, inputVideoMode);
if (!inputVideoModeResolved)
{
inputVideoModeError = "Unsupported DeckLink inputVideoFormat/inputFrameRate in config/runtime-host.json: " +
appConfig.inputVideoFormat + " / " + appConfig.inputFrameRate;
RenderCadenceCompositor::LogWarning("app", inputVideoModeError);
}
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) &&
deckLinkInputThread.Start(deckLinkInputError))
{
deckLinkInputStarted = true;
RenderCadenceCompositor::Log("app", "DeckLink input edge started for " + inputVideoMode.displayName + ".");
}
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.");
}
RenderThread::Config renderConfig;
renderConfig.width = frameExchangeConfig.width;
renderConfig.height = frameExchangeConfig.height;
renderConfig.frameDurationMilliseconds = RenderCadenceCompositor::FrameDurationMillisecondsFromRateString(appConfig.outputFrameRate);
renderConfig.pboDepth = 6;
RenderThread renderThread(frameExchange, &inputMailbox, renderConfig);
RenderCadenceCompositor::RenderCadenceApp<RenderThread, SystemFrameExchange> app(renderThread, frameExchange, appConfig);
app.SetDeckLinkInputMetricsProvider([&deckLinkInput]() {
return deckLinkInput.Metrics();
});
std::string error;
if (!app.Start(error))
{
RenderCadenceCompositor::LogError("app", "RenderCadenceCompositor start failed: " + error);
if (deckLinkInputStarted)
deckLinkInputThread.Stop();
RenderCadenceCompositor::Logger::Instance().Stop();
return 1;
}
std::string line;
std::getline(std::cin, line);
app.Stop();
if (deckLinkInputStarted)
deckLinkInputThread.Stop();
RenderCadenceCompositor::Log("app", "RenderCadenceCompositor stopped.");
RenderCadenceCompositor::Logger::Instance().Stop();
return 0;
}