NDI discovery
All checks were successful
CI / React UI Build (push) Successful in 11s
CI / Native Windows Build And Tests (push) Successful in 2m10s
CI / Windows Release Package (push) Has been skipped

This commit is contained in:
Aiden
2026-05-30 20:03:01 +10:00
parent 8ffc011ca0
commit 2b995ac058
21 changed files with 493 additions and 56 deletions

View File

@@ -148,11 +148,6 @@ bool NdiOutput::Initialize(const VideoOutputEdgeConfig& config, CompletionCallba
return false;
}
if (config.outputAlphaRequired)
{
mState.statusMessage = "NDI output can carry BGRA alpha when configured; output.keying.alphaRequired is a DeckLink-only requirement.";
}
if (!AcquireNdiRuntime())
{
error = "NDI runtime initialization failed. The CPU/runtime might not support NDI.";
@@ -175,6 +170,8 @@ bool NdiOutput::Initialize(const VideoOutputEdgeConfig& config, CompletionCallba
mInitialized.store(true, std::memory_order_release);
mState.statusMessage = "NDI output sender '" + mSenderName + "' initialized.";
if (config.outputAlphaRequired)
mState.statusMessage += " Output alpha is enabled; external keying is ignored for NDI.";
Log("ndi-output", mState.statusMessage);
return true;
}

View File

@@ -0,0 +1,72 @@
#include "NdiSourceDiscovery.h"
#include "NdiRuntime.h"
#include <Processing.NDI.Lib.h>
#include <algorithm>
#include <cstring>
#include <utility>
namespace RenderCadenceCompositor
{
bool DiscoverNdiSources(std::vector<NdiSourceInfo>& sources, std::string& error, uint32_t waitMilliseconds)
{
sources.clear();
if (!AcquireNdiRuntime())
{
error = "NDI runtime initialization failed. The CPU/runtime might not support NDI.";
return false;
}
NDIlib_find_create_t settings;
std::memset(&settings, 0, sizeof(settings));
settings.show_local_sources = true;
NDIlib_find_instance_t finder = NDIlib_find_create_v2(&settings);
if (finder == nullptr)
{
ReleaseNdiRuntime();
error = "NDI source finder creation failed.";
return false;
}
uint32_t sourceCount = 0;
const NDIlib_source_t* ndiSources = NDIlib_find_get_current_sources(finder, &sourceCount);
if (sourceCount == 0 && waitMilliseconds > 0)
{
NDIlib_find_wait_for_sources(finder, waitMilliseconds);
ndiSources = NDIlib_find_get_current_sources(finder, &sourceCount);
}
if (ndiSources != nullptr)
{
sources.reserve(sourceCount);
for (uint32_t index = 0; index < sourceCount; ++index)
{
const char* name = ndiSources[index].p_ndi_name;
if (name == nullptr || name[0] == '\0')
continue;
NdiSourceInfo source;
source.name = name;
if (ndiSources[index].p_url_address != nullptr)
source.urlAddress = ndiSources[index].p_url_address;
sources.push_back(std::move(source));
}
}
NDIlib_find_destroy(finder);
ReleaseNdiRuntime();
std::sort(sources.begin(), sources.end(), [](const NdiSourceInfo& lhs, const NdiSourceInfo& rhs) {
return lhs.name < rhs.name;
});
sources.erase(std::unique(sources.begin(), sources.end(), [](const NdiSourceInfo& lhs, const NdiSourceInfo& rhs) {
return lhs.name == rhs.name;
}), sources.end());
error.clear();
return true;
}
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include <cstdint>
#include <string>
#include <vector>
namespace RenderCadenceCompositor
{
struct NdiSourceInfo
{
std::string name;
std::string urlAddress;
};
bool DiscoverNdiSources(std::vector<NdiSourceInfo>& sources, std::string& error, uint32_t waitMilliseconds = 250);
}