config cleanup
This commit is contained in:
32
README.md
32
README.md
@@ -154,23 +154,32 @@ Current native test coverage includes:
|
|||||||
"oscBindAddress": "127.0.0.1",
|
"oscBindAddress": "127.0.0.1",
|
||||||
"oscPort": 9000,
|
"oscPort": 9000,
|
||||||
"oscSmoothing": 0.18,
|
"oscSmoothing": 0.18,
|
||||||
"inputVideoFormat": "1080p",
|
"input": {
|
||||||
"inputFrameRate": "59.94",
|
"backend": "decklink",
|
||||||
"outputVideoFormat": "1080p",
|
"device": "default",
|
||||||
"outputFrameRate": "59.94",
|
"resolution": "1080p",
|
||||||
"videoInputBackend": "decklink",
|
"frameRate": "59.94"
|
||||||
"videoOutputBackend": "decklink",
|
},
|
||||||
|
"output": {
|
||||||
|
"backend": "decklink",
|
||||||
|
"device": "default",
|
||||||
|
"resolution": "1080p",
|
||||||
|
"frameRate": "59.94",
|
||||||
|
"keying": {
|
||||||
|
"external": true,
|
||||||
|
"alphaRequired": false
|
||||||
|
}
|
||||||
|
},
|
||||||
"autoReload": true,
|
"autoReload": true,
|
||||||
"maxTemporalHistoryFrames": 12,
|
"maxTemporalHistoryFrames": 12
|
||||||
"enableExternalKeying": true
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`videoInputBackend` and `videoOutputBackend` select the concrete video I/O backend. Today the app supports `decklink` and `none`; future backends such as NDI, Spout, or file playback can be added behind the same factory boundary.
|
`input.backend` and `output.backend` select the concrete video I/O backend. Today the app supports `decklink` and `none`; future backends such as NDI, Spout, or file playback can be added behind the same factory boundary. `device` is currently accepted as a backend-neutral selector placeholder; DeckLink still chooses the first compatible device.
|
||||||
|
|
||||||
`inputVideoFormat`/`inputFrameRate` select the video capture mode. `outputVideoFormat`/`outputFrameRate` select the playout mode through a backend-neutral mode description; the current DeckLink backend maps that mode to a `BMDDisplayMode` at the DeckLink boundary. Supported modes still depend on the installed card and driver. The shader stack runs at input resolution and the final rendered frame is scaled once into the configured output mode. Common examples include `720p`/`50`, `720p`/`59.94`, `1080i`/`50`, `1080i`/`59.94`, `1080p`/`25`, `1080p`/`50`, `1080p`/`59.94`, and `2160p`/`59.94`.
|
`input.resolution`/`input.frameRate` select the video capture mode. `output.resolution`/`output.frameRate` select the playout mode through a backend-neutral mode description; the current DeckLink backend maps that mode to a `BMDDisplayMode` at the DeckLink boundary. Supported modes still depend on the installed card and driver. The shader stack runs at input resolution and the final rendered frame is scaled once into the configured output mode. Common examples include `720p`/`50`, `720p`/`59.94`, `1080i`/`50`, `1080i`/`59.94`, `1080p`/`25`, `1080p`/`50`, `1080p`/`59.94`, and `2160p`/`59.94`.
|
||||||
|
|
||||||
Legacy `videoFormat` and `frameRate` keys are still accepted and apply to both input and output unless the explicit input/output keys are present.
|
The checked-in config uses the nested `input` and `output` objects as the supported shape.
|
||||||
|
|
||||||
The control UI is available at:
|
The control UI is available at:
|
||||||
|
|
||||||
@@ -290,7 +299,6 @@ If `SLANG_ROOT` or `MSDF_ATLAS_GEN_ROOT` is not set, the workflow falls back to
|
|||||||
- Audio.
|
- Audio.
|
||||||
- Genlock.
|
- Genlock.
|
||||||
- Logs.
|
- Logs.
|
||||||
- Add more video I/O backends now that the DeckLink path is isolated under `src/video/decklink/`.
|
|
||||||
- Support a separate sound shader `.slang` file in shader packages. (https://www.shadertoy.com/view/XsBXWt)
|
- Support a separate sound shader `.slang` file in shader packages. (https://www.shadertoy.com/view/XsBXWt)
|
||||||
- Add WebView2 for an embedded native control surface.
|
- Add WebView2 for an embedded native control surface.
|
||||||
- More shader-library organisation and filtering as the built-in library grows.
|
- More shader-library organisation and filtering as the built-in library grows.
|
||||||
|
|||||||
@@ -4,15 +4,24 @@
|
|||||||
"oscBindAddress": "0.0.0.0",
|
"oscBindAddress": "0.0.0.0",
|
||||||
"oscPort": 9000,
|
"oscPort": 9000,
|
||||||
"oscSmoothing": 0.18,
|
"oscSmoothing": 0.18,
|
||||||
"inputVideoFormat": "1080p",
|
"input": {
|
||||||
"inputFrameRate": "59.94",
|
"backend": "decklink",
|
||||||
"outputVideoFormat": "1080p",
|
"device": "default",
|
||||||
"outputFrameRate": "59.94",
|
"resolution": "1080p",
|
||||||
"videoInputBackend": "decklink",
|
"frameRate": "59.94"
|
||||||
"videoOutputBackend": "decklink",
|
},
|
||||||
|
"output": {
|
||||||
|
"backend": "decklink",
|
||||||
|
"device": "default",
|
||||||
|
"resolution": "1080p",
|
||||||
|
"frameRate": "59.94",
|
||||||
|
"keying": {
|
||||||
|
"external": true,
|
||||||
|
"alphaRequired": false
|
||||||
|
}
|
||||||
|
},
|
||||||
"autoReload": true,
|
"autoReload": true,
|
||||||
"maxTemporalHistoryFrames": 12,
|
"maxTemporalHistoryFrames": 12,
|
||||||
"previewEnabled": true,
|
"previewEnabled": true,
|
||||||
"previewFps": 59.94,
|
"previewFps": 59.94
|
||||||
"enableExternalKeying": true
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ When a runtime shader build completes, the app publishes a render-layer artifact
|
|||||||
|
|
||||||
## Video And Preview
|
## Video And Preview
|
||||||
|
|
||||||
Video input and output are optional edges. `videoInputBackend` and `videoOutputBackend` select the concrete backend through the app-side backend factory. DeckLink is the current concrete backend, and `none` disables that edge. Configured video modes are represented in `src/video/core` and translated to DeckLink display modes only inside `src/video/decklink`.
|
Video input and output are optional edges. `input.backend` and `output.backend` select the concrete backend through the app-side backend factory. DeckLink is the current concrete backend, and `none` disables that edge. `input` and `output` also carry the device selector plus resolution/frame-rate settings. Configured video modes are represented in `src/video/core` and translated to DeckLink display modes only inside `src/video/decklink`.
|
||||||
|
|
||||||
The input edge writes CPU frames into `InputFrameMailbox`. The current DeckLink backend captures BGRA8 directly where possible, or raw UYVY8 for render-thread GPU decode. The input edge does not call GL, render, preview, screenshot, shader, or output scheduling code.
|
The input edge writes CPU frames into `InputFrameMailbox`. The current DeckLink backend captures BGRA8 directly where possible, or raw UYVY8 for render-thread GPU decode. The input edge does not call GL, render, preview, screenshot, shader, or output scheduling code.
|
||||||
|
|
||||||
|
|||||||
@@ -561,22 +561,37 @@ components:
|
|||||||
type: number
|
type: number
|
||||||
previewFps:
|
previewFps:
|
||||||
type: number
|
type: number
|
||||||
enableExternalKeying:
|
input:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
backend:
|
||||||
|
type: string
|
||||||
|
enum: [decklink, none]
|
||||||
|
device:
|
||||||
|
type: string
|
||||||
|
resolution:
|
||||||
|
type: string
|
||||||
|
frameRate:
|
||||||
|
type: string
|
||||||
|
output:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
backend:
|
||||||
|
type: string
|
||||||
|
enum: [decklink, none]
|
||||||
|
device:
|
||||||
|
type: string
|
||||||
|
resolution:
|
||||||
|
type: string
|
||||||
|
frameRate:
|
||||||
|
type: string
|
||||||
|
keying:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
external:
|
||||||
|
type: boolean
|
||||||
|
alphaRequired:
|
||||||
type: boolean
|
type: boolean
|
||||||
videoInputBackend:
|
|
||||||
type: string
|
|
||||||
enum: [decklink, none]
|
|
||||||
videoOutputBackend:
|
|
||||||
type: string
|
|
||||||
enum: [decklink, none]
|
|
||||||
inputVideoFormat:
|
|
||||||
type: string
|
|
||||||
inputFrameRate:
|
|
||||||
type: string
|
|
||||||
outputVideoFormat:
|
|
||||||
type: string
|
|
||||||
outputFrameRate:
|
|
||||||
type: string
|
|
||||||
RuntimeStatus:
|
RuntimeStatus:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
@@ -200,19 +200,22 @@ Currently consumed fields:
|
|||||||
- `oscBindAddress` (reported for compatibility; OSC ingress is not wired yet)
|
- `oscBindAddress` (reported for compatibility; OSC ingress is not wired yet)
|
||||||
- `oscPort` (reported for compatibility; OSC ingress is not wired yet)
|
- `oscPort` (reported for compatibility; OSC ingress is not wired yet)
|
||||||
- `oscSmoothing` (reported for compatibility; OSC ingress is not wired yet)
|
- `oscSmoothing` (reported for compatibility; OSC ingress is not wired yet)
|
||||||
- `inputVideoFormat`
|
- `input.backend`
|
||||||
- `inputFrameRate`
|
- `input.device`
|
||||||
- `outputVideoFormat`
|
- `input.resolution`
|
||||||
- `outputFrameRate`
|
- `input.frameRate`
|
||||||
- `videoInputBackend`
|
- `output.backend`
|
||||||
- `videoOutputBackend`
|
- `output.device`
|
||||||
|
- `output.resolution`
|
||||||
|
- `output.frameRate`
|
||||||
|
- `output.keying.external`
|
||||||
|
- `output.keying.alphaRequired`
|
||||||
- `autoReload`
|
- `autoReload`
|
||||||
- `maxTemporalHistoryFrames`
|
- `maxTemporalHistoryFrames`
|
||||||
- `previewEnabled`
|
- `previewEnabled`
|
||||||
- `previewFps`
|
- `previewFps`
|
||||||
- `enableExternalKeying`
|
|
||||||
|
|
||||||
`videoInputBackend` and `videoOutputBackend` currently support `decklink` and `none`. Backend creation is routed through the app-side video backend factory, so new concrete backends can be added without making `main` or the render cadence path own their startup details.
|
`input.backend` and `output.backend` currently support `decklink` and `none`. Backend creation is routed through the app-side video backend factory, so new concrete backends can be added without making `main` or the render cadence path own their startup details.
|
||||||
|
|
||||||
When `previewEnabled` is true, the preview window runs on `PreviewWindowThread`. It paints BGRA8 system-memory frames with Win32/GDI after render readback has already completed, so it does not bind GL and does not consume frames from DeckLink output. `previewFps` controls the preview repaint cadence; the default is 60 fps and `config/runtime-host.json` tracks the shipped 59.94 output cadence.
|
When `previewEnabled` is true, the preview window runs on `PreviewWindowThread`. It paints BGRA8 system-memory frames with Win32/GDI after render readback has already completed, so it does not bind GL and does not consume frames from DeckLink output. `previewFps` controls the preview repaint cadence; the default is 60 fps and `config/runtime-host.json` tracks the shipped 59.94 output cadence.
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
SystemFrameExchangeConfig frameExchangeConfig;
|
SystemFrameExchangeConfig frameExchangeConfig;
|
||||||
VideoFormatDimensions(
|
VideoFormatDimensions(
|
||||||
appConfig.outputVideoFormat,
|
appConfig.output.resolution,
|
||||||
frameExchangeConfig.width,
|
frameExchangeConfig.width,
|
||||||
frameExchangeConfig.height);
|
frameExchangeConfig.height);
|
||||||
frameExchangeConfig.pixelFormat = VideoIOPixelFormat::Bgra8;
|
frameExchangeConfig.pixelFormat = VideoIOPixelFormat::Bgra8;
|
||||||
@@ -95,7 +95,7 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
InputFrameMailboxConfig inputMailboxConfig;
|
InputFrameMailboxConfig inputMailboxConfig;
|
||||||
VideoFormatDimensions(
|
VideoFormatDimensions(
|
||||||
appConfig.inputVideoFormat,
|
appConfig.input.resolution,
|
||||||
inputMailboxConfig.width,
|
inputMailboxConfig.width,
|
||||||
inputMailboxConfig.height);
|
inputMailboxConfig.height);
|
||||||
inputMailboxConfig.pixelFormat = VideoIOPixelFormat::Bgra8;
|
inputMailboxConfig.pixelFormat = VideoIOPixelFormat::Bgra8;
|
||||||
@@ -107,24 +107,24 @@ int main(int argc, char** argv)
|
|||||||
VideoFormat inputVideoMode;
|
VideoFormat inputVideoMode;
|
||||||
VideoFormat outputVideoMode;
|
VideoFormat outputVideoMode;
|
||||||
std::string inputVideoModeError;
|
std::string inputVideoModeError;
|
||||||
const bool inputVideoModeResolved = ResolveConfiguredVideoFormat(appConfig.inputVideoFormat, appConfig.inputFrameRate, inputVideoMode);
|
const bool inputVideoModeResolved = ResolveConfiguredVideoFormat(appConfig.input.resolution, appConfig.input.frameRate, inputVideoMode);
|
||||||
const bool outputVideoModeResolved = ResolveConfiguredVideoFormat(appConfig.outputVideoFormat, appConfig.outputFrameRate, outputVideoMode);
|
const bool outputVideoModeResolved = ResolveConfiguredVideoFormat(appConfig.output.resolution, appConfig.output.frameRate, outputVideoMode);
|
||||||
if (!inputVideoModeResolved)
|
if (!inputVideoModeResolved)
|
||||||
{
|
{
|
||||||
inputVideoModeError = "Unsupported inputVideoFormat/inputFrameRate in config/runtime-host.json: " +
|
inputVideoModeError = "Unsupported input resolution/frameRate in config/runtime-host.json: " +
|
||||||
appConfig.inputVideoFormat + " / " + appConfig.inputFrameRate;
|
appConfig.input.resolution + " / " + appConfig.input.frameRate;
|
||||||
RenderCadenceCompositor::LogWarning("app", inputVideoModeError);
|
RenderCadenceCompositor::LogWarning("app", inputVideoModeError);
|
||||||
}
|
}
|
||||||
if (!outputVideoModeResolved)
|
if (!outputVideoModeResolved)
|
||||||
{
|
{
|
||||||
RenderCadenceCompositor::LogWarning(
|
RenderCadenceCompositor::LogWarning(
|
||||||
"app",
|
"app",
|
||||||
"Unsupported outputVideoFormat/outputFrameRate in config/runtime-host.json; render cadence will use parsed frame-rate fallback: " +
|
"Unsupported output resolution/frameRate in config/runtime-host.json; render cadence will use parsed frame-rate fallback: " +
|
||||||
appConfig.outputVideoFormat + " / " + appConfig.outputFrameRate);
|
appConfig.output.resolution + " / " + appConfig.output.frameRate);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
appConfig.deckLink.outputVideoMode = outputVideoMode;
|
appConfig.output.videoMode = outputVideoMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto inputBackend = RenderCadenceCompositor::StartVideoInputBackend(
|
auto inputBackend = RenderCadenceCompositor::StartVideoInputBackend(
|
||||||
@@ -137,7 +137,7 @@ int main(int argc, char** argv)
|
|||||||
RenderThread::Config renderConfig;
|
RenderThread::Config renderConfig;
|
||||||
renderConfig.width = frameExchangeConfig.width;
|
renderConfig.width = frameExchangeConfig.width;
|
||||||
renderConfig.height = frameExchangeConfig.height;
|
renderConfig.height = frameExchangeConfig.height;
|
||||||
const double fallbackFrameDurationMilliseconds = FrameDurationMillisecondsFromRateString(appConfig.outputFrameRate);
|
const double fallbackFrameDurationMilliseconds = FrameDurationMillisecondsFromRateString(appConfig.output.frameRate);
|
||||||
renderConfig.frameDurationMilliseconds = outputVideoModeResolved
|
renderConfig.frameDurationMilliseconds = outputVideoModeResolved
|
||||||
? outputVideoMode.frameDurationMilliseconds
|
? outputVideoMode.frameDurationMilliseconds
|
||||||
: fallbackFrameDurationMilliseconds;
|
: fallbackFrameDurationMilliseconds;
|
||||||
|
|||||||
@@ -5,8 +5,16 @@ namespace RenderCadenceCompositor
|
|||||||
AppConfig DefaultAppConfig()
|
AppConfig DefaultAppConfig()
|
||||||
{
|
{
|
||||||
AppConfig config;
|
AppConfig config;
|
||||||
config.deckLink.externalKeyingEnabled = false;
|
config.input.backend = "decklink";
|
||||||
config.deckLink.outputAlphaRequired = false;
|
config.input.device = "default";
|
||||||
|
config.input.resolution = "1080p";
|
||||||
|
config.input.frameRate = "59.94";
|
||||||
|
config.output.backend = "decklink";
|
||||||
|
config.output.device = "default";
|
||||||
|
config.output.resolution = "1080p";
|
||||||
|
config.output.frameRate = "59.94";
|
||||||
|
config.output.externalKeyingEnabled = false;
|
||||||
|
config.output.outputAlphaRequired = false;
|
||||||
config.outputThread.targetBufferedFrames = 4;
|
config.outputThread.targetBufferedFrames = 4;
|
||||||
config.telemetry.interval = std::chrono::seconds(1);
|
config.telemetry.interval = std::chrono::seconds(1);
|
||||||
config.logging.minimumLevel = LogLevel::Log;
|
config.logging.minimumLevel = LogLevel::Log;
|
||||||
@@ -22,12 +30,6 @@ AppConfig DefaultAppConfig()
|
|||||||
config.oscBindAddress = "0.0.0.0";
|
config.oscBindAddress = "0.0.0.0";
|
||||||
config.oscPort = 9000;
|
config.oscPort = 9000;
|
||||||
config.oscSmoothing = 0.18;
|
config.oscSmoothing = 0.18;
|
||||||
config.inputVideoFormat = "1080p";
|
|
||||||
config.inputFrameRate = "59.94";
|
|
||||||
config.outputVideoFormat = "1080p";
|
|
||||||
config.outputFrameRate = "59.94";
|
|
||||||
config.videoInputBackend = "decklink";
|
|
||||||
config.videoOutputBackend = "decklink";
|
|
||||||
config.autoReload = true;
|
config.autoReload = true;
|
||||||
config.maxTemporalHistoryFrames = 12;
|
config.maxTemporalHistoryFrames = 12;
|
||||||
config.previewEnabled = false;
|
config.previewEnabled = false;
|
||||||
|
|||||||
@@ -13,9 +13,29 @@
|
|||||||
|
|
||||||
namespace RenderCadenceCompositor
|
namespace RenderCadenceCompositor
|
||||||
{
|
{
|
||||||
|
struct VideoInputAppConfig
|
||||||
|
{
|
||||||
|
std::string backend = "decklink";
|
||||||
|
std::string device = "default";
|
||||||
|
std::string resolution = "1080p";
|
||||||
|
std::string frameRate = "59.94";
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VideoOutputAppConfig
|
||||||
|
{
|
||||||
|
std::string backend = "decklink";
|
||||||
|
std::string device = "default";
|
||||||
|
std::string resolution = "1080p";
|
||||||
|
std::string frameRate = "59.94";
|
||||||
|
bool externalKeyingEnabled = false;
|
||||||
|
bool outputAlphaRequired = false;
|
||||||
|
VideoFormat videoMode;
|
||||||
|
};
|
||||||
|
|
||||||
struct AppConfig
|
struct AppConfig
|
||||||
{
|
{
|
||||||
VideoOutputEdgeConfig deckLink;
|
VideoInputAppConfig input;
|
||||||
|
VideoOutputAppConfig output;
|
||||||
VideoOutputThreadConfig outputThread;
|
VideoOutputThreadConfig outputThread;
|
||||||
TelemetryHealthMonitorConfig telemetry;
|
TelemetryHealthMonitorConfig telemetry;
|
||||||
LoggerConfig logging;
|
LoggerConfig logging;
|
||||||
@@ -24,12 +44,6 @@ struct AppConfig
|
|||||||
std::string oscBindAddress = "0.0.0.0";
|
std::string oscBindAddress = "0.0.0.0";
|
||||||
unsigned short oscPort = 9000;
|
unsigned short oscPort = 9000;
|
||||||
double oscSmoothing = 0.18;
|
double oscSmoothing = 0.18;
|
||||||
std::string inputVideoFormat = "1080p";
|
|
||||||
std::string inputFrameRate = "59.94";
|
|
||||||
std::string outputVideoFormat = "1080p";
|
|
||||||
std::string outputFrameRate = "59.94";
|
|
||||||
std::string videoInputBackend = "decklink";
|
|
||||||
std::string videoOutputBackend = "decklink";
|
|
||||||
bool autoReload = true;
|
bool autoReload = true;
|
||||||
std::size_t maxTemporalHistoryFrames = 12;
|
std::size_t maxTemporalHistoryFrames = 12;
|
||||||
bool previewEnabled = false;
|
bool previewEnabled = false;
|
||||||
|
|||||||
@@ -79,6 +79,37 @@ void ApplyPort(const JsonValue& root, const char* key, unsigned short& target)
|
|||||||
if (port >= 1.0 && port <= 65535.0)
|
if (port >= 1.0 && port <= 65535.0)
|
||||||
target = static_cast<unsigned short>(port);
|
target = static_cast<unsigned short>(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApplyInputConfig(const JsonValue& root, AppConfig& config)
|
||||||
|
{
|
||||||
|
const JsonValue* input = Find(root, "input");
|
||||||
|
if (!input || !input->isObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ApplyString(*input, "backend", config.input.backend);
|
||||||
|
ApplyString(*input, "device", config.input.device);
|
||||||
|
ApplyString(*input, "resolution", config.input.resolution);
|
||||||
|
ApplyString(*input, "frameRate", config.input.frameRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplyOutputConfig(const JsonValue& root, AppConfig& config)
|
||||||
|
{
|
||||||
|
const JsonValue* output = Find(root, "output");
|
||||||
|
if (!output || !output->isObject())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ApplyString(*output, "backend", config.output.backend);
|
||||||
|
ApplyString(*output, "device", config.output.device);
|
||||||
|
ApplyString(*output, "resolution", config.output.resolution);
|
||||||
|
ApplyString(*output, "frameRate", config.output.frameRate);
|
||||||
|
|
||||||
|
const JsonValue* keying = Find(*output, "keying");
|
||||||
|
if (keying && keying->isObject())
|
||||||
|
{
|
||||||
|
ApplyBool(*keying, "external", config.output.externalKeyingEnabled);
|
||||||
|
ApplyBool(*keying, "alphaRequired", config.output.outputAlphaRequired);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AppConfigProvider::AppConfigProvider() :
|
AppConfigProvider::AppConfigProvider() :
|
||||||
@@ -124,17 +155,12 @@ bool AppConfigProvider::Load(const std::filesystem::path& path, std::string& err
|
|||||||
ApplyString(root, "oscBindAddress", mConfig.oscBindAddress);
|
ApplyString(root, "oscBindAddress", mConfig.oscBindAddress);
|
||||||
ApplyPort(root, "oscPort", mConfig.oscPort);
|
ApplyPort(root, "oscPort", mConfig.oscPort);
|
||||||
ApplyDouble(root, "oscSmoothing", mConfig.oscSmoothing);
|
ApplyDouble(root, "oscSmoothing", mConfig.oscSmoothing);
|
||||||
ApplyString(root, "inputVideoFormat", mConfig.inputVideoFormat);
|
ApplyInputConfig(root, mConfig);
|
||||||
ApplyString(root, "inputFrameRate", mConfig.inputFrameRate);
|
ApplyOutputConfig(root, mConfig);
|
||||||
ApplyString(root, "outputVideoFormat", mConfig.outputVideoFormat);
|
|
||||||
ApplyString(root, "outputFrameRate", mConfig.outputFrameRate);
|
|
||||||
ApplyString(root, "videoInputBackend", mConfig.videoInputBackend);
|
|
||||||
ApplyString(root, "videoOutputBackend", mConfig.videoOutputBackend);
|
|
||||||
ApplyBool(root, "autoReload", mConfig.autoReload);
|
ApplyBool(root, "autoReload", mConfig.autoReload);
|
||||||
ApplySize(root, "maxTemporalHistoryFrames", mConfig.maxTemporalHistoryFrames);
|
ApplySize(root, "maxTemporalHistoryFrames", mConfig.maxTemporalHistoryFrames);
|
||||||
ApplyBool(root, "previewEnabled", mConfig.previewEnabled);
|
ApplyBool(root, "previewEnabled", mConfig.previewEnabled);
|
||||||
ApplyDouble(root, "previewFps", mConfig.previewFps);
|
ApplyDouble(root, "previewFps", mConfig.previewFps);
|
||||||
ApplyBool(root, "enableExternalKeying", mConfig.deckLink.externalKeyingEnabled);
|
|
||||||
|
|
||||||
mLoadedFromFile = true;
|
mLoadedFromFile = true;
|
||||||
error.clear();
|
error.clear();
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
void StartOptionalVideoOutput()
|
void StartOptionalVideoOutput()
|
||||||
{
|
{
|
||||||
if (mConfig.videoOutputBackend == "none")
|
if (mConfig.output.backend == "none")
|
||||||
{
|
{
|
||||||
mVideoOutputEnabled = false;
|
mVideoOutputEnabled = false;
|
||||||
mVideoOutputStatus = "Video output backend disabled by config.";
|
mVideoOutputStatus = "Video output backend disabled by config.";
|
||||||
@@ -146,9 +146,13 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string outputError;
|
std::string outputError;
|
||||||
Log("app", "Initializing optional video output backend: " + mConfig.videoOutputBackend + ".");
|
Log("app", "Initializing optional video output backend: " + mConfig.output.backend + ".");
|
||||||
|
VideoOutputEdgeConfig outputConfig;
|
||||||
|
outputConfig.outputVideoMode = mConfig.output.videoMode;
|
||||||
|
outputConfig.externalKeyingEnabled = mConfig.output.externalKeyingEnabled;
|
||||||
|
outputConfig.outputAlphaRequired = mConfig.output.outputAlphaRequired;
|
||||||
if (!mOutput->Initialize(
|
if (!mOutput->Initialize(
|
||||||
mConfig.deckLink,
|
outputConfig,
|
||||||
[this](const VideoIOCompletion& completion) {
|
[this](const VideoIOCompletion& completion) {
|
||||||
mFrameExchange.ReleaseScheduledByBytes(completion.outputFrameBuffer);
|
mFrameExchange.ReleaseScheduledByBytes(completion.outputFrameBuffer);
|
||||||
},
|
},
|
||||||
@@ -180,7 +184,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
mVideoOutputEnabled = true;
|
mVideoOutputEnabled = true;
|
||||||
mVideoOutputStatus = mConfig.videoOutputBackend + " scheduled output running.";
|
mVideoOutputStatus = mConfig.output.backend + " scheduled output running.";
|
||||||
Log("app", mVideoOutputStatus);
|
Log("app", mVideoOutputStatus);
|
||||||
Log(
|
Log(
|
||||||
"app",
|
"app",
|
||||||
|
|||||||
@@ -274,8 +274,8 @@ const VideoInputBackendRegistration* FindVideoInputBackend(std::string_view back
|
|||||||
|
|
||||||
bool VideoBackendsRequireCom(const AppConfig& config)
|
bool VideoBackendsRequireCom(const AppConfig& config)
|
||||||
{
|
{
|
||||||
const std::string inputBackend = NormalizeBackendName(config.videoInputBackend);
|
const std::string inputBackend = NormalizeBackendName(config.input.backend);
|
||||||
const std::string outputBackend = NormalizeBackendName(config.videoOutputBackend);
|
const std::string outputBackend = NormalizeBackendName(config.output.backend);
|
||||||
const VideoInputBackendRegistration* input = FindVideoInputBackend(inputBackend);
|
const VideoInputBackendRegistration* input = FindVideoInputBackend(inputBackend);
|
||||||
const VideoOutputBackendRegistration* output = FindVideoOutputBackend(outputBackend);
|
const VideoOutputBackendRegistration* output = FindVideoOutputBackend(outputBackend);
|
||||||
return (input != nullptr && input->requiresCom) || (output != nullptr && output->requiresCom);
|
return (input != nullptr && input->requiresCom) || (output != nullptr && output->requiresCom);
|
||||||
@@ -283,12 +283,12 @@ bool VideoBackendsRequireCom(const AppConfig& config)
|
|||||||
|
|
||||||
std::unique_ptr<IVideoOutputEdge> CreateVideoOutputBackend(const AppConfig& config)
|
std::unique_ptr<IVideoOutputEdge> CreateVideoOutputBackend(const AppConfig& config)
|
||||||
{
|
{
|
||||||
const std::string backendName = NormalizeBackendName(config.videoOutputBackend);
|
const std::string backendName = NormalizeBackendName(config.output.backend);
|
||||||
const VideoOutputBackendRegistration* backend = FindVideoOutputBackend(backendName);
|
const VideoOutputBackendRegistration* backend = FindVideoOutputBackend(backendName);
|
||||||
if (backend != nullptr && backend->create != nullptr)
|
if (backend != nullptr && backend->create != nullptr)
|
||||||
return backend->create();
|
return backend->create();
|
||||||
|
|
||||||
return std::make_unique<DisabledVideoOutputEdge>("Unsupported videoOutputBackend: " + config.videoOutputBackend);
|
return std::make_unique<DisabledVideoOutputEdge>("Unsupported output backend: " + config.output.backend);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<VideoInputBackendSession> StartVideoInputBackend(
|
std::unique_ptr<VideoInputBackendSession> StartVideoInputBackend(
|
||||||
@@ -298,7 +298,7 @@ std::unique_ptr<VideoInputBackendSession> StartVideoInputBackend(
|
|||||||
const VideoFormat& inputVideoMode,
|
const VideoFormat& inputVideoMode,
|
||||||
bool inputVideoModeResolved)
|
bool inputVideoModeResolved)
|
||||||
{
|
{
|
||||||
const std::string backendName = NormalizeBackendName(config.videoInputBackend);
|
const std::string backendName = NormalizeBackendName(config.input.backend);
|
||||||
const VideoInputBackendRegistration* backend = FindVideoInputBackend(backendName);
|
const VideoInputBackendRegistration* backend = FindVideoInputBackend(backendName);
|
||||||
if (backend != nullptr && backend->start != nullptr)
|
if (backend != nullptr && backend->start != nullptr)
|
||||||
{
|
{
|
||||||
@@ -306,7 +306,7 @@ std::unique_ptr<VideoInputBackendSession> StartVideoInputBackend(
|
|||||||
return backend->start(context);
|
return backend->start(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogWarning("app", "Unsupported videoInputBackend '" + config.videoInputBackend + "'; runtime shaders will use fallback input.");
|
LogWarning("app", "Unsupported input backend '" + config.input.backend + "'; runtime shaders will use fallback input.");
|
||||||
return std::make_unique<NoInputBackendSession>(config.videoInputBackend);
|
return std::make_unique<NoInputBackendSession>(config.input.backend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,13 +27,13 @@ struct RuntimeStateJsonInput
|
|||||||
inline void WriteVideoIoStatusJson(JsonWriter& writer, const RuntimeStateJsonInput& input)
|
inline void WriteVideoIoStatusJson(JsonWriter& writer, const RuntimeStateJsonInput& input)
|
||||||
{
|
{
|
||||||
writer.BeginObject();
|
writer.BeginObject();
|
||||||
writer.KeyString("backend", input.config.videoOutputBackend);
|
writer.KeyString("backend", input.config.output.backend);
|
||||||
writer.KeyNull("modelName");
|
writer.KeyNull("modelName");
|
||||||
writer.KeyBool("supportsInternalKeying", false);
|
writer.KeyBool("supportsInternalKeying", false);
|
||||||
writer.KeyBool("supportsExternalKeying", false);
|
writer.KeyBool("supportsExternalKeying", false);
|
||||||
writer.KeyBool("keyerInterfaceAvailable", false);
|
writer.KeyBool("keyerInterfaceAvailable", false);
|
||||||
writer.KeyBool("externalKeyingRequested", input.config.deckLink.externalKeyingEnabled);
|
writer.KeyBool("externalKeyingRequested", input.config.output.externalKeyingEnabled);
|
||||||
writer.KeyBool("externalKeyingActive", input.videoOutputEnabled && input.config.deckLink.externalKeyingEnabled);
|
writer.KeyBool("externalKeyingActive", input.videoOutputEnabled && input.config.output.externalKeyingEnabled);
|
||||||
writer.KeyString("statusMessage", input.videoOutputStatus);
|
writer.KeyString("statusMessage", input.videoOutputStatus);
|
||||||
writer.EndObject();
|
writer.EndObject();
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ inline void WriteVideoIoStatusJson(JsonWriter& writer, const RuntimeStateJsonInp
|
|||||||
inline void WriteVideoOutputBackendMetricsJson(JsonWriter& writer, const RuntimeStateJsonInput& input)
|
inline void WriteVideoOutputBackendMetricsJson(JsonWriter& writer, const RuntimeStateJsonInput& input)
|
||||||
{
|
{
|
||||||
writer.BeginObject();
|
writer.BeginObject();
|
||||||
if (input.config.videoOutputBackend == "decklink")
|
if (input.config.output.backend == "decklink")
|
||||||
{
|
{
|
||||||
writer.KeyBool("bufferedAvailable", input.telemetry.deckLinkBufferedAvailable);
|
writer.KeyBool("bufferedAvailable", input.telemetry.deckLinkBufferedAvailable);
|
||||||
writer.Key("buffered");
|
writer.Key("buffered");
|
||||||
@@ -68,7 +68,7 @@ inline void WriteVideoOutputTelemetryJson(JsonWriter& writer, const RuntimeState
|
|||||||
{
|
{
|
||||||
writer.BeginObject();
|
writer.BeginObject();
|
||||||
writer.KeyBool("enabled", input.videoOutputEnabled);
|
writer.KeyBool("enabled", input.videoOutputEnabled);
|
||||||
writer.KeyString("backend", input.config.videoOutputBackend);
|
writer.KeyString("backend", input.config.output.backend);
|
||||||
writer.KeyString("statusMessage", input.videoOutputStatus);
|
writer.KeyString("statusMessage", input.videoOutputStatus);
|
||||||
writer.KeyUInt("scheduleFailures", input.telemetry.scheduleFailures);
|
writer.KeyUInt("scheduleFailures", input.telemetry.scheduleFailures);
|
||||||
writer.KeyUInt("completions", input.telemetry.completions);
|
writer.KeyUInt("completions", input.telemetry.completions);
|
||||||
@@ -81,7 +81,7 @@ inline void WriteVideoOutputTelemetryJson(JsonWriter& writer, const RuntimeState
|
|||||||
|
|
||||||
inline void OutputDimensions(const RuntimeStateJsonInput& input, unsigned& width, unsigned& height)
|
inline void OutputDimensions(const RuntimeStateJsonInput& input, unsigned& width, unsigned& height)
|
||||||
{
|
{
|
||||||
VideoFormatDimensions(input.config.outputVideoFormat, width, height);
|
VideoFormatDimensions(input.config.output.resolution, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const char* ShaderParameterTypeName(ShaderParameterType type)
|
inline const char* ShaderParameterTypeName(ShaderParameterType type)
|
||||||
@@ -291,13 +291,25 @@ inline std::string RuntimeStateToJson(const RuntimeStateJsonInput& input)
|
|||||||
writer.KeyBool("autoReload", input.config.autoReload);
|
writer.KeyBool("autoReload", input.config.autoReload);
|
||||||
writer.KeyUInt("maxTemporalHistoryFrames", static_cast<uint64_t>(input.config.maxTemporalHistoryFrames));
|
writer.KeyUInt("maxTemporalHistoryFrames", static_cast<uint64_t>(input.config.maxTemporalHistoryFrames));
|
||||||
writer.KeyDouble("previewFps", input.config.previewFps);
|
writer.KeyDouble("previewFps", input.config.previewFps);
|
||||||
writer.KeyBool("enableExternalKeying", input.config.deckLink.externalKeyingEnabled);
|
writer.Key("input");
|
||||||
writer.KeyString("videoInputBackend", input.config.videoInputBackend);
|
writer.BeginObject();
|
||||||
writer.KeyString("videoOutputBackend", input.config.videoOutputBackend);
|
writer.KeyString("backend", input.config.input.backend);
|
||||||
writer.KeyString("inputVideoFormat", input.config.inputVideoFormat);
|
writer.KeyString("device", input.config.input.device);
|
||||||
writer.KeyString("inputFrameRate", input.config.inputFrameRate);
|
writer.KeyString("resolution", input.config.input.resolution);
|
||||||
writer.KeyString("outputVideoFormat", input.config.outputVideoFormat);
|
writer.KeyString("frameRate", input.config.input.frameRate);
|
||||||
writer.KeyString("outputFrameRate", input.config.outputFrameRate);
|
writer.EndObject();
|
||||||
|
writer.Key("output");
|
||||||
|
writer.BeginObject();
|
||||||
|
writer.KeyString("backend", input.config.output.backend);
|
||||||
|
writer.KeyString("device", input.config.output.device);
|
||||||
|
writer.KeyString("resolution", input.config.output.resolution);
|
||||||
|
writer.KeyString("frameRate", input.config.output.frameRate);
|
||||||
|
writer.Key("keying");
|
||||||
|
writer.BeginObject();
|
||||||
|
writer.KeyBool("external", input.config.output.externalKeyingEnabled);
|
||||||
|
writer.KeyBool("alphaRequired", input.config.output.outputAlphaRequired);
|
||||||
|
writer.EndObject();
|
||||||
|
writer.EndObject();
|
||||||
writer.EndObject();
|
writer.EndObject();
|
||||||
|
|
||||||
writer.Key("runtime");
|
writer.Key("runtime");
|
||||||
@@ -315,7 +327,7 @@ inline std::string RuntimeStateToJson(const RuntimeStateJsonInput& input)
|
|||||||
writer.KeyBool("hasSignal", input.videoOutputEnabled);
|
writer.KeyBool("hasSignal", input.videoOutputEnabled);
|
||||||
writer.KeyUInt("width", outputWidth);
|
writer.KeyUInt("width", outputWidth);
|
||||||
writer.KeyUInt("height", outputHeight);
|
writer.KeyUInt("height", outputHeight);
|
||||||
writer.KeyString("modeName", input.config.outputVideoFormat + " output-only");
|
writer.KeyString("modeName", input.config.output.resolution + " output-only");
|
||||||
writer.EndObject();
|
writer.EndObject();
|
||||||
|
|
||||||
writer.Key("videoOutput");
|
writer.Key("videoOutput");
|
||||||
@@ -327,7 +339,7 @@ inline std::string RuntimeStateToJson(const RuntimeStateJsonInput& input)
|
|||||||
|
|
||||||
writer.Key("performance");
|
writer.Key("performance");
|
||||||
writer.BeginObject();
|
writer.BeginObject();
|
||||||
writer.KeyDouble("frameBudgetMs", FrameDurationMillisecondsFromRateString(input.config.outputFrameRate));
|
writer.KeyDouble("frameBudgetMs", FrameDurationMillisecondsFromRateString(input.config.output.frameRate));
|
||||||
writer.KeyDouble("renderMs", input.telemetry.renderFrameMilliseconds);
|
writer.KeyDouble("renderMs", input.telemetry.renderFrameMilliseconds);
|
||||||
writer.KeyNull("smoothedRenderMs");
|
writer.KeyNull("smoothedRenderMs");
|
||||||
writer.KeyDouble("budgetUsedPercent", input.telemetry.renderFrameBudgetUsedPercent);
|
writer.KeyDouble("budgetUsedPercent", input.telemetry.renderFrameBudgetUsedPercent);
|
||||||
|
|||||||
@@ -135,24 +135,24 @@ bool ResolveConfiguredVideoFormat(const std::string& videoFormat, const std::str
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ResolveConfiguredVideoFormats(
|
bool ResolveConfiguredVideoFormats(
|
||||||
const std::string& inputVideoFormat,
|
const std::string& inputResolution,
|
||||||
const std::string& inputFrameRate,
|
const std::string& inputFrameRate,
|
||||||
const std::string& outputVideoFormat,
|
const std::string& outputResolution,
|
||||||
const std::string& outputFrameRate,
|
const std::string& outputFrameRate,
|
||||||
VideoFormatSelection& videoModes,
|
VideoFormatSelection& videoModes,
|
||||||
std::string& error)
|
std::string& error)
|
||||||
{
|
{
|
||||||
if (!ResolveConfiguredVideoFormat(inputVideoFormat, inputFrameRate, videoModes.input))
|
if (!ResolveConfiguredVideoFormat(inputResolution, inputFrameRate, videoModes.input))
|
||||||
{
|
{
|
||||||
error = "Unsupported inputVideoFormat/inputFrameRate in config/runtime-host.json: " +
|
error = "Unsupported input resolution/frameRate in config/runtime-host.json: " +
|
||||||
inputVideoFormat + " / " + inputFrameRate;
|
inputResolution + " / " + inputFrameRate;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ResolveConfiguredVideoFormat(outputVideoFormat, outputFrameRate, videoModes.output))
|
if (!ResolveConfiguredVideoFormat(outputResolution, outputFrameRate, videoModes.output))
|
||||||
{
|
{
|
||||||
error = "Unsupported outputVideoFormat/outputFrameRate in config/runtime-host.json: " +
|
error = "Unsupported output resolution/frameRate in config/runtime-host.json: " +
|
||||||
outputVideoFormat + " / " + outputFrameRate;
|
outputResolution + " / " + outputFrameRate;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ double FrameDurationMillisecondsFromRateString(const std::string& rateText, doub
|
|||||||
void VideoFormatDimensions(const std::string& formatName, unsigned& width, unsigned& height);
|
void VideoFormatDimensions(const std::string& formatName, unsigned& width, unsigned& height);
|
||||||
bool ResolveConfiguredVideoFormat(const std::string& videoFormat, const std::string& frameRate, VideoFormat& videoMode);
|
bool ResolveConfiguredVideoFormat(const std::string& videoFormat, const std::string& frameRate, VideoFormat& videoMode);
|
||||||
bool ResolveConfiguredVideoFormats(
|
bool ResolveConfiguredVideoFormats(
|
||||||
const std::string& inputVideoFormat,
|
const std::string& inputResolution,
|
||||||
const std::string& inputFrameRate,
|
const std::string& inputFrameRate,
|
||||||
const std::string& outputVideoFormat,
|
const std::string& outputResolution,
|
||||||
const std::string& outputFrameRate,
|
const std::string& outputFrameRate,
|
||||||
VideoFormatSelection& videoModes,
|
VideoFormatSelection& videoModes,
|
||||||
std::string& error);
|
std::string& error);
|
||||||
|
|||||||
@@ -360,7 +360,7 @@ bool DeckLinkSession::ConfigureOutput(OutputFrameCallback callback, const VideoF
|
|||||||
}
|
}
|
||||||
else if (mState.supportsExternalKeying)
|
else if (mState.supportsExternalKeying)
|
||||||
{
|
{
|
||||||
mState.statusMessage = "Selected DeckLink output supports external keying. Set enableExternalKeying to true in runtime-host.json to request it.";
|
mState.statusMessage = "Selected DeckLink output supports external keying. Set output.keying.external to true in runtime-host.json to request it.";
|
||||||
}
|
}
|
||||||
|
|
||||||
const VideoPlayoutPolicy policy = NormalizeVideoPlayoutPolicy(mPlayoutPolicy);
|
const VideoPlayoutPolicy policy = NormalizeVideoPlayoutPolicy(mPlayoutPolicy);
|
||||||
|
|||||||
@@ -31,17 +31,26 @@ std::filesystem::path WriteConfigFixture()
|
|||||||
<< " \"oscBindAddress\": \"127.0.0.1\",\n"
|
<< " \"oscBindAddress\": \"127.0.0.1\",\n"
|
||||||
<< " \"oscPort\": 9100,\n"
|
<< " \"oscPort\": 9100,\n"
|
||||||
<< " \"oscSmoothing\": 0.25,\n"
|
<< " \"oscSmoothing\": 0.25,\n"
|
||||||
<< " \"inputVideoFormat\": \"720p\",\n"
|
<< " \"input\": {\n"
|
||||||
<< " \"inputFrameRate\": \"50\",\n"
|
<< " \"backend\": \"none\",\n"
|
||||||
<< " \"outputVideoFormat\": \"2160p\",\n"
|
<< " \"device\": \"input-card-1\",\n"
|
||||||
<< " \"outputFrameRate\": \"60\",\n"
|
<< " \"resolution\": \"720p\",\n"
|
||||||
<< " \"videoInputBackend\": \"none\",\n"
|
<< " \"frameRate\": \"50\"\n"
|
||||||
<< " \"videoOutputBackend\": \"decklink\",\n"
|
<< " },\n"
|
||||||
|
<< " \"output\": {\n"
|
||||||
|
<< " \"backend\": \"decklink\",\n"
|
||||||
|
<< " \"device\": \"output-card-1\",\n"
|
||||||
|
<< " \"resolution\": \"2160p\",\n"
|
||||||
|
<< " \"frameRate\": \"60\",\n"
|
||||||
|
<< " \"keying\": {\n"
|
||||||
|
<< " \"external\": true,\n"
|
||||||
|
<< " \"alphaRequired\": true\n"
|
||||||
|
<< " }\n"
|
||||||
|
<< " },\n"
|
||||||
<< " \"autoReload\": false,\n"
|
<< " \"autoReload\": false,\n"
|
||||||
<< " \"maxTemporalHistoryFrames\": 8,\n"
|
<< " \"maxTemporalHistoryFrames\": 8,\n"
|
||||||
<< " \"previewEnabled\": true,\n"
|
<< " \"previewEnabled\": true,\n"
|
||||||
<< " \"previewFps\": 24,\n"
|
<< " \"previewFps\": 24\n"
|
||||||
<< " \"enableExternalKeying\": true\n"
|
|
||||||
<< "}\n";
|
<< "}\n";
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
@@ -64,17 +73,20 @@ void TestLoadsRuntimeHostConfig()
|
|||||||
Expect(config.oscBindAddress == "127.0.0.1", "OSC bind address loads");
|
Expect(config.oscBindAddress == "127.0.0.1", "OSC bind address loads");
|
||||||
Expect(config.oscPort == 9100, "OSC port loads");
|
Expect(config.oscPort == 9100, "OSC port loads");
|
||||||
Expect(config.oscSmoothing == 0.25, "OSC smoothing loads");
|
Expect(config.oscSmoothing == 0.25, "OSC smoothing loads");
|
||||||
Expect(config.inputVideoFormat == "720p", "input format loads");
|
Expect(config.input.resolution == "720p", "input resolution loads");
|
||||||
Expect(config.inputFrameRate == "50", "input frame rate loads");
|
Expect(config.input.frameRate == "50", "input frame rate loads");
|
||||||
Expect(config.outputVideoFormat == "2160p", "output format loads");
|
Expect(config.input.device == "input-card-1", "input device loads");
|
||||||
Expect(config.outputFrameRate == "60", "output frame rate loads");
|
Expect(config.output.resolution == "2160p", "output resolution loads");
|
||||||
Expect(config.videoInputBackend == "none", "video input backend loads");
|
Expect(config.output.frameRate == "60", "output frame rate loads");
|
||||||
Expect(config.videoOutputBackend == "decklink", "video output backend loads");
|
Expect(config.output.device == "output-card-1", "output device loads");
|
||||||
|
Expect(config.input.backend == "none", "video input backend loads");
|
||||||
|
Expect(config.output.backend == "decklink", "video output backend loads");
|
||||||
Expect(!config.autoReload, "auto reload loads");
|
Expect(!config.autoReload, "auto reload loads");
|
||||||
Expect(config.maxTemporalHistoryFrames == 8, "history length loads");
|
Expect(config.maxTemporalHistoryFrames == 8, "history length loads");
|
||||||
Expect(config.previewEnabled, "preview enabled toggle loads");
|
Expect(config.previewEnabled, "preview enabled toggle loads");
|
||||||
Expect(config.previewFps == 24.0, "preview fps loads");
|
Expect(config.previewFps == 24.0, "preview fps loads");
|
||||||
Expect(config.deckLink.externalKeyingEnabled, "external keying loads");
|
Expect(config.output.externalKeyingEnabled, "external keying loads");
|
||||||
|
Expect(config.output.outputAlphaRequired, "output alpha requirement loads");
|
||||||
|
|
||||||
std::filesystem::remove(path);
|
std::filesystem::remove(path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ void WriteFile(const std::filesystem::path& path, const std::string& contents)
|
|||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
RenderCadenceCompositor::AppConfig config = RenderCadenceCompositor::DefaultAppConfig();
|
RenderCadenceCompositor::AppConfig config = RenderCadenceCompositor::DefaultAppConfig();
|
||||||
config.outputVideoFormat = "1080p";
|
config.output.resolution = "1080p";
|
||||||
config.outputFrameRate = "59.94";
|
config.output.frameRate = "59.94";
|
||||||
|
|
||||||
RenderCadenceCompositor::CadenceTelemetrySnapshot telemetry;
|
RenderCadenceCompositor::CadenceTelemetrySnapshot telemetry;
|
||||||
telemetry.renderFps = 59.94;
|
telemetry.renderFps = 59.94;
|
||||||
@@ -117,8 +117,8 @@ int main()
|
|||||||
ExpectContains(json, "\"type\":\"color\"", "state JSON should serialize parameter types for the UI");
|
ExpectContains(json, "\"type\":\"color\"", "state JSON should serialize parameter types for the UI");
|
||||||
ExpectContains(json, "\"width\":1920", "state JSON should expose output width");
|
ExpectContains(json, "\"width\":1920", "state JSON should expose output width");
|
||||||
ExpectContains(json, "\"height\":1080", "state JSON should expose output height");
|
ExpectContains(json, "\"height\":1080", "state JSON should expose output height");
|
||||||
ExpectContains(json, "\"videoInputBackend\":\"decklink\"", "state JSON should expose input backend");
|
ExpectContains(json, "\"input\":{\"backend\":\"decklink\",\"device\":\"default\",\"resolution\":\"1080p\",\"frameRate\":\"59.94\"}", "state JSON should expose nested input config");
|
||||||
ExpectContains(json, "\"videoOutputBackend\":\"decklink\"", "state JSON should expose output backend");
|
ExpectContains(json, "\"output\":{\"backend\":\"decklink\",\"device\":\"default\",\"resolution\":\"1080p\",\"frameRate\":\"59.94\",\"keying\"", "state JSON should expose nested output config");
|
||||||
ExpectContains(json, "\"videoOutput\":{\"enabled\":true,\"backend\":\"decklink\"", "state JSON should expose neutral video output status");
|
ExpectContains(json, "\"videoOutput\":{\"enabled\":true,\"backend\":\"decklink\"", "state JSON should expose neutral video output status");
|
||||||
ExpectContains(json, "\"scheduleFailures\":2", "state JSON should expose neutral video output schedule failures");
|
ExpectContains(json, "\"scheduleFailures\":2", "state JSON should expose neutral video output schedule failures");
|
||||||
ExpectContains(json, "\"backendMetrics\":{\"bufferedAvailable\":true,\"buffered\":4", "state JSON should expose backend-specific video output metrics");
|
ExpectContains(json, "\"backendMetrics\":{\"bufferedAvailable\":true,\"buffered\":4", "state JSON should expose backend-specific video output metrics");
|
||||||
|
|||||||
Reference in New Issue
Block a user