VAST.NDI Library
The VAST.NDI library provides support for NewTek's Network Device Interface (NDI) protocol, enabling low-latency video and audio transmission over local networks. It supports receiving and sending NDI streams, automatic device discovery, PTZ camera control, and integration with the VASTreaming capture device framework.
Overview
| Feature | Description |
|---|---|
| NDI Source | Receive video and audio from NDI sources on the network |
| NDI Sink | Send video and audio as an NDI source |
| Device Discovery | Automatic enumeration of NDI sources |
| PTZ Control | Full PTZ camera control for supported devices |
| Failover | Automatic failover source configuration |
| Capture Integration | Seamless integration with capture device framework |
Requirements
- .NET: .NET 6.0 or later
- Dependencies: VAST.Common
- External Dependencies: NDI SDK runtime libraries (available from NDI.tv)
NDI SDK Setup
The VAST.NDI library requires the NDI SDK runtime libraries. Configure the library paths before using any NDI functionality:
// Configure NDI library paths
VAST.NDI.NdiGlobal.DynamicLibrary32BitPath = @"C:\Program Files\NDI\NDI 5 Runtime\v5\Processing.NDI.Lib.x86.dll";
VAST.NDI.NdiGlobal.DynamicLibrary64BitPath = @"C:\Program Files\NDI\NDI 5 Runtime\v5\Processing.NDI.Lib.x64.dll";
Important
The NDI SDK must be installed separately. Download it from ndi.tv/sdk.
Receiving NDI Streams
NdiSource
The NdiSource class receives video and audio from NDI sources on the network.
URI Format
ndi://<source-name>?vast-url=<url-address>
| Parameter | Description |
|---|---|
source-name |
The NDI source name (e.g., MACHINE-NAME (Source)) |
vast-url |
Optional direct IP address and port for faster connection |
Usage
var source = new VAST.NDI.NdiSource();
source.Uri = "ndi://MACHINE-NAME (OBS)";
source.NewStream += (sender, e) =>
{
Console.WriteLine($"Stream {e.StreamIndex}: {e.MediaType.ContentType}");
};
source.NewSample += (sender, e) =>
{
ProcessSample(e.Sample);
};
source.StateChanged += (sender, state) =>
{
if (state == MediaState.Opened)
{
source.Start();
}
};
source.Open();
Direct Connection
For faster connection when the IP address is known:
source.Uri = "ndi://MACHINE-NAME (OBS)?vast-url=192.168.1.100:5961";
Supported Pixel Formats
| Format | Description |
|---|---|
| UYVY | YUV 4:2:2 packed |
| BGRA | 32-bit BGRA |
| RGBA | 32-bit RGBA |
Supported Audio Format
| Format | Description |
|---|---|
| FLTP | 32-bit float planar |
PTZ Camera Control
PTZ camera control is available when using NDI sources through the capture device framework via CreateVideoCapture. The video capture source provides access to camera control functionality through its CameraControl property.
// Create video capture source for NDI device
var capture = VAST.Media.SourceFactory.CreateVideoCapture("[NDI]MACHINE-NAME (PTZ Camera)");
capture.StateChanged += (sender, state) =>
{
if (state == MediaState.Started)
{
// Check if PTZ is supported
if (capture.CameraControl != null && capture.CameraControl.IsPanTiltSupported)
{
var ptz = capture.CameraControl;
// Set pan/tilt position (-1.0 to +1.0)
ptz.SetPanTilt(0.5f, 0.0f);
// Set zoom level (0.0 to 1.0)
ptz.CurrentZoom = 0.5f;
}
capture.Start();
}
};
capture.Open();
PTZ Features
| Feature | Method/Property | Description |
|---|---|---|
| Pan/Tilt | SetPanTilt(pan, tilt) |
Set absolute position (-1.0 to +1.0) |
| Pan/Tilt Speed | SetPanTiltSpeed(panSpeed, tiltSpeed) |
Continuous movement |
| Zoom | CurrentZoom |
Set zoom level (0.0 to 1.0) |
| Zoom Speed | SetZoomSpeed(speed) |
Continuous zoom (-1.0 to +1.0) |
| Auto Focus | Focus() |
Trigger auto-focus |
| Manual Focus | SetManualFocus(value) |
Set focus (0.0=infinity to 1.0=close) |
| Focus Speed | SetManualFocusSpeed(speed) |
Continuous focus adjustment |
| Presets | StorePreset(n), RecallPreset(n, speed) |
Save and recall positions |
| White Balance | SetAutoWhiteBalance(preset) |
Auto, Indoor, Outdoor, OneShot |
| Manual WB | SetManualWhiteBalance(red, blue) |
Manual color adjustment |
| Auto Exposure | SetAutoExposure() |
Enable auto exposure |
| Manual Exposure | SetManualExposure(level) |
Set exposure level |
| Full Manual | SetManualExposure(iris, gain, shutter) |
Full manual control |
Web Control
Some NDI sources provide a web control interface. The URL is available via the WebControlUri property after the source is opened.
source.StateChanged += (sender, state) =>
{
if (state == MediaState.Opened)
{
if (!string.IsNullOrEmpty(source.WebControlUri))
{
Console.WriteLine($"Web control: {source.WebControlUri}");
}
source.Start();
}
};
Sending NDI Streams
NdiSink
The NdiSink class broadcasts video and audio as an NDI source visible to other devices on the network.
URI Format
ndi://<source-name>?vast-group-name=<group>&vast-failover-name=<failover>
| Parameter | Description |
|---|---|
source-name |
The name that will identify this source on the network |
vast-group-name |
Optional NDI group for source organization |
vast-failover-name |
Optional failover source name |
Usage
var sink = new VAST.NDI.NdiSink();
sink.Uri = "ndi://My Application";
sink.AddStream(0, videoMediaType);
sink.AddStream(1, audioMediaType);
sink.StateChanged += (sender, state) =>
{
if (state == MediaState.Opened)
{
sink.Start();
}
};
sink.Open();
// Push media samples
sink.PushMedia(0, videoSample);
sink.PushMedia(1, audioSample);
// When done
sink.Stop();
NDI Groups
Use groups to organize NDI sources:
sink.Uri = "ndi://Camera Feed?vast-group-name=Production";
Failover Configuration
Configure a backup source that receivers will use if this source becomes unavailable:
sink.Uri = "ndi://Primary Feed?vast-failover-name=Backup Feed";
Supported Pixel Formats for Sending
| Format | Description |
|---|---|
| UYVY | YUV 4:2:2 packed |
| P216 | YUV 4:2:2 16-bit |
| YV12 | YUV 4:2:0 planar |
| IYUV | YUV 4:2:0 planar (I420) |
| NV12 | YUV 4:2:0 semi-planar |
| BGRA | 32-bit BGRA |
| RGBA | 32-bit RGBA |
Note
If the input is encoded or its pixel format is not in the supported list, the sink automatically decodes/converts it to a supported format.
Supported Audio Format for Sending
| Format | Description |
|---|---|
| FLTP | 32-bit float planar |
Note
If the input is encoded or its audio format is not FLTP, the sink automatically decodes/converts it.
Device Discovery
Warning
NDI device discovery is notoriously unreliable and can take a long time, especially on larger networks. The library uses multiple optimizations to mitigate these issues, including caching and background enumeration. However, for best results, configure your application with the exact NDI source names beforehand and connect directly without relying on discovery.
Enumerating NDI Sources
The NdiGlobal class provides methods to discover NDI sources on the network.
Video Sources
var videoDevices = await VAST.NDI.NdiGlobal.EnumerateVideoSources();
foreach (var device in videoDevices)
{
Console.WriteLine($"Video: {device.Name} ({device.DeviceId})");
}
Audio Sources
var parameters = new AudioDeviceEnumeratorParameters
{
EnableChannelFilter = true,
GroupChannelsBy = 2 // Group channels in pairs (stereo)
};
var audioDevices = await VAST.NDI.NdiGlobal.EnumerateAudioSources(parameters);
foreach (var device in audioDevices)
{
Console.WriteLine($"Audio: {device.Name} ({device.DeviceId})");
}
Discovery Configuration
Configure source discovery behavior:
// Set enumeration timeout (default: 10 seconds)
VAST.NDI.NdiGlobal.SourceEnumerationTimeout = 50000000L; // 5 seconds in 100ns units
// Set cache expiration (default: 10 seconds)
VAST.NDI.NdiGlobal.SourceEnumerationExpiration = 100000000L; // 10 seconds
// Specify NDI groups to search
VAST.NDI.NdiGlobal.SourceEnumerationGroups = "Production,Test";
// Add extra IP addresses to search
VAST.NDI.NdiGlobal.SourceEnumerationExtraIps = "192.168.1.100,192.168.1.101";
// Filter source types
VAST.NDI.NdiGlobal.AllowVideoSources = true;
VAST.NDI.NdiGlobal.AllowAudioSources = true;
Pre-registering Known Devices
For faster startup, pre-register known NDI devices:
VAST.NDI.NdiGlobal.RegisterKnownDevice(
"MACHINE-NAME (OBS)", // Source name
"192.168.1.100:5961", // IP address and port
audioDetected: true,
videoDetected: true
);
Capture Device Integration
NDI sources integrate seamlessly with the VASTreaming capture device framework, allowing them to be used alongside local capture devices.
Video Capture
// Use with IVideoCaptureSource2
var capture = VAST.Media.SourceFactory.CreateVideoCapture("[NDI]MACHINE-NAME (OBS)");
capture.Open();
Audio Capture
// Use with IAudioCaptureSource2
var capture = VAST.Media.SourceFactory.CreateAudioCapture("[NDI]MACHINE-NAME (OBS)");
capture.Open();
Shared Source Optimization
When both video and audio capture sources are created from the same NDI source, they internally share a single NdiSource instance. This optimization reduces network bandwidth and CPU usage by avoiding duplicate NDI connections to the same source.
// Both capture sources share the same underlying NdiSource
var videoCapture = VAST.Media.SourceFactory.CreateVideoCapture("[NDI]MACHINE-NAME (OBS)");
var audioCapture = VAST.Media.SourceFactory.CreateAudioCapture("[NDI]MACHINE-NAME (OBS)");
videoCapture.Open();
audioCapture.Open();
Cleanup
When finished using NDI functionality, unload the library:
VAST.NDI.NdiGlobal.Unload();
Otherwise it may prevent your app from being closed.
Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|---|---|
| No sources found | NDI SDK not installed | Install NDI SDK from ndi.video/for-developers/ndi-sdk |
| Library load failure | Wrong library path | Verify DynamicLibrary paths |
| Source not discovered | Network firewall | Allow NDI traffic (TCP/UDP 5960-5969) |
| Slow discovery | Large network | Use SourceEnumerationExtraIps for known IPs |
| PTZ not working | Source doesn't support PTZ | Check CameraControl is not null before using |
| Format conversion | Unsupported input format | Automatic conversion handles this |
Network Requirements
| Protocol | Ports | Description |
|---|---|---|
| TCP | 5960-5969 | NDI discovery and control |
| UDP | 5960-5969 | NDI video/audio data |
| mDNS | 5353 | NDI source discovery |
See Also
- Supported Platforms - Platform compatibility matrix
- VAST.Common Library - Core media types and interfaces