NDI & SDI Video in TouchDesigner
Route video over IP with NDI and interface with broadcast-grade SDI hardware using AJA and Blackmagic capture cards in professional production rigs.
Video routing at the professional level in TouchDesigner means NDI for flexible network-based workflows and SDI for latency-critical broadcast environments. Understanding both — and knowing when each is appropriate — is essential for large-scale installation and live production work.
NDI: Network Device Interface
NDI is NewTek’s royalty-free protocol for sending uncompressed (or lightly compressed) video over a standard IP network. The protocol uses mDNS for automatic source discovery on a local subnet, which means TD sources and receivers find each other without manual IP configuration as long as they’re on the same broadcast domain.
Key NDI characteristics relevant to TD:
- Codec: SpeedHQ at various quality levels; NDI HX uses H.264/H.265 for WAN scenarios
- Latency: 1–3 frames at 60 fps on a gigabit switch with SpeedHQ at highest quality
- Bandwidth: roughly 125 Mbps for 1080p60 SpeedHQ; 4K60 requires a 10 GbE switch
- CPU cost: NDI encoding/decoding is CPU-based, not GPU — monitor CPU headroom on machines that are also doing heavy rendering
NDI In TOP
The NDI In TOP (Operators > TOP > NDI In) auto-discovers all NDI sources on the local subnet when Source Name is blank. Sources appear in the drop-down as machine_name (source_name). Set Source Name directly for stability in show environments — relying on auto-discovery means the drop-down order can change if a machine restarts.
Critical parameters:
- Sync to Frame Rate: when on, TD drops frames to stay locked to its own cook rate; when off, every available NDI frame is consumed (causes tearing if the source fps differs from TD’s)
- Output Resolution: leave at Use Source unless you need a specific downstream format
- Alpha: NDI supports alpha in some configurations; most cameras output no alpha, so this is a pass-through
For monitoring NDI stream health from Python:
# In a Script DAT, run this periodically via a Timer CHOP trigger
def onCook(dat):
ndi_top = op('ndi_in1')
status = {
'connected': ndi_top.par.Sourcename.val != '',
'width': ndi_top.width,
'height': ndi_top.height,
'cook_time_ms': ndi_top.cookTime * 1000,
}
dat.clear()
dat.appendRow(['key', 'value'])
for k, v in status.items():
dat.appendRow([k, str(v)])
NDI Out TOP
The NDI Out TOP wraps TD’s output in an NDI stream. One instance per unique stream name — you can run multiple NDI Out TOPs to broadcast multiple streams from a single machine, subject to CPU bandwidth.
Parameters to set for live production:
- Stream Name: becomes the source name visible to other NDI devices; use a descriptive, unique name like
TD_MASTER_PGM - Quality: High (highest, most CPU), Low, or Balanced — benchmark on your specific hardware
- Frame Rate: must match your TD cook rate; mismatches cause frame duplication or drops downstream
Cross-Subnet NDI
Automatic mDNS discovery stops at the subnet boundary. For cross-subnet NDI (e.g., sending from backstage to a projection control booth on a different VLAN):
- Install NDI Access Manager on both machines
- Add the source machine’s IP address manually to the remote machine’s NDI Access Manager source list
- The NDI In TOP will then show that source in its drop-down
Alternatively, use NDI Bridge, which is a unicast NDI relay that works across firewalled networks and WAN links.
SDI: Serial Digital Interface
SDI is the physical-layer standard for professional video. Unlike NDI, it is electrically deterministic: a 3G-SDI signal at 1080p60 has exactly the same propagation delay every time, making it suitable for broadcast environments where frame-accurate synchronisation between multiple sources is legally and technically required.
SDI variants:
- SD-SDI: 270 Mbps — legacy standard definition
- HD-SDI: 1.485 Gbps — 1080i/720p
- 3G-SDI: 2.97 Gbps — 1080p60
- 12G-SDI: 11.88 Gbps — 4K60 over a single coax
AJA Capture Cards in TouchDesigner
AJA cards (Kona 4, Kona 5, Io 4K Plus, etc.) are supported via the AJA TOP. Install AJA Desktop Software before launching TD — the TOP relies on AJA’s driver and SDK.
# AJA TOP key parameters:
Device: 0 # AJA device index (0 = first card)
Input: SDI 1 # Physical input connector
Video Format: 1080p 59.94 # Must match incoming signal exactly
Pixel Format: 8-bit YCbCr # or 10-bit for HDR workflows
The AJA TOP outputs directly to the GPU as a texture. TD does not buffer SDI frames — you get the current frame on every cook. If your TD frame rate is lower than the SDI input, you drop frames. If it’s higher (running at 120 Hz with a 60 Hz SDI input), you duplicate the last frame.
For SDI output (sending TD’s composited output to an SDI router):
# In the AJA TOP set to Output mode:
# Device: 0
# Output: SDI 1
# Reference: External (for genlock)
# The TOP input becomes the SDI output signal
Blackmagic Design TOPs
Blackmagic cards (DeckLink Duo 2, DeckLink 8K Pro, etc.) use the Blackmagic Design TOP. Install Blackmagic Desktop Video and Desktop Video SDK before launching TD.
The Blackmagic Design TOP has separate instances for input and output — you cannot use one OP for both simultaneously. Key parameter: Pixel Format — set to 8-bit YUV for standard broadcast, 10-bit YUV for HDR, or 12-bit RGB when feeding a DCI mastering chain.
Genlock and Reference Signals
In a multi-camera broadcast environment, all SDI devices must be genlocked — running in phase-locked synchrony to a common reference signal (typically black burst for SD or tri-level sync for HD). Without genlock, cutting between cameras produces a visible frame boundary glitch on downstream routers and switchers.
AJA and Blackmagic cards in TD can lock to an external reference:
- Distribute the reference signal from a sync generator to all capture cards via BNC
- Set each card’s Reference parameter to External
- Verify lock status in the card’s driver software before show
TD itself does not generate a reference signal — it adapts its cook timing to the locked card’s vertical interval interrupt (V-sync). This means your TD frame rate becomes deterministic and phase-aligned with the rest of the broadcast chain.
Full Example: 4-Camera NDI Setup with Python Failover
This architecture receives four NDI cameras, composites them, and automatically switches to a static fallback image if any source drops.
# In a Script DAT — called every second via a Timer CHOP
SOURCES = ['cam1', 'cam2', 'cam3', 'cam4']
FALLBACK_COLOR = (0.1, 0.1, 0.1, 1.0) # dark grey
def check_sources(dat):
"""Monitor NDI source connectivity and update Switch TOP index."""
switch_top = op('camera_switch')
status_table = op('source_status')
status_table.clear()
status_table.appendRow(['source', 'connected', 'width', 'fps_estimate'])
all_connected = True
for i, src in enumerate(SOURCES):
ndi_op = op(f'ndi_{src}')
# A disconnected NDI TOP outputs a 1×1 black frame
connected = ndi_op.width > 1 and ndi_op.height > 1
if not connected:
all_connected = False
# Log with timestamp
print(f'[{absTime.seconds:.1f}] WARNING: NDI source {src} disconnected')
status_table.appendRow([src, str(connected), str(ndi_op.width),
f'{1.0/ndi_op.cookTime:.1f}' if ndi_op.cookTime > 0 else '0'])
# If all four are connected, use live composite; otherwise hold last good frame
op('composite_switch').par.index = 0 if all_connected else 1
The network topology:
ndi_cam1 ─┐
ndi_cam2 ─┤→ Grid TOP (2×2 layout) ─→ composite_switch ─→ Output
ndi_cam3 ─┤ ↑ (index=1)
ndi_cam4 ─┘ Hold TOP (last good frame)
The Hold TOP is connected to the composite output with a latch: when composite_switch is at index 0 (all good), the Hold TOP records each new frame; when it switches to index 1, it holds the last recorded frame. This gives you a clean freeze rather than a black flash on source failure.
For production, back up the Python monitor script with a second Watchdog Timer that fires if the Script DAT itself hasn’t executed within two seconds — covering the case where TD’s Python environment locks up rather than the NDI source dropping.