pixtreme-transport-ndi
Full NDI® video and audio output for pixtreme.transport. NDI® is a registered trademark of Vizrt NDI AB. See NDI.
Send processed GPU frames from a transport core FrameBuffer to NDI receivers.
The package provides the Python Output factory, a C++ shared library, public
headers, a CMake package, and a bundled libndi runtime. It provides output only.
Installation
pip install pixtreme-transport-ndi
Supported wheels target Linux x86_64 (including WSL2), CPython 3.12 and 3.13,
and manylinux_2_28_x86_64 (glibc 2.28 or newer). Processing requires an NVIDIA
GPU and a driver that supports CUDA 13. The transport core supplies CUDA kernels
for sm 86, sm 89, and sm 120. The wheel requires no CUDA Toolkit or NDI SDK
installation.
Avahi's libavahi-client.so.3, libavahi-common.so.3, and their dependencies
must be installed on the host. Install libavahi-client3 on Debian/Ubuntu or
avahi-libs on RHEL-family systems. NDI mDNS discovery also needs a running
avahi-daemon. Import errors identify a missing Avahi library and the packages
to install.
The dependency pixtreme-transport>=0.17.1 installs the transport core, which
supplies frame types, buffers, worker threads, audio processing, and pixel
serialization. Its native ABI must match the ABI used to build this module;
import rejects an incompatible core before loading the NDI extension. The core
library stays in its own wheel. This package installs libndi under its own
_ndi directory and uses relative library paths, so LD_LIBRARY_PATH is not
needed to locate the installed NDI and core libraries.
Using the output
from fractions import Fraction
from pixtreme.transport.ndi import Output
from pixtreme.transport.session import ExitSettings, FrameBuffer
post = FrameBuffer(2)
settings = ExitSettings(Fraction(1001, 30000)) # 30000/1001 fps
settings.audio.enabled = True
settings.audio.accepted_formats = [
(48000, 2, "stereo", "s16le"),
(48000, 2, "stereo", "f32le"),
]
settings.audio.output_format = (48000, 2, "stereo", "f32le")
settings.audio.target_format = "FLTP"
settings.ancillary_kinds = ["caption"]
output = Output(0, post, settings, "Processed output")
output.open()
try:
for frame in processed_frames: # TransportFrame values from your pipeline.
post.put(frame)
post.close()
output.join()
finally:
output.close()
Output(device, buffer, settings, name) requires all four arguments. Device
numbers follow the core's CUDA device selection. Output returns the core's
Exit, with open, request_stop, join, close, check, and
inspection. open() creates the NDI source; video begins after the first
frame is acquired. The output never closes the caller's buffer.
Output is a factory function;
use isinstance(output, Exit) to check the returned session, with Exit imported
from pixtreme.transport.session.
ExitSettings.prefill_frames defaults to 2. Set it to 1 to start with one
buffered frame. The value must be positive and fit the buffer's capacity.
Closing the buffer drains its remaining frames even below that count.
While an open buffer has no new frame, the output repeats the latest picture
with silent audio. request_stop() stops acquisition and drains accepted work;
close() joins the workers and destroys the source.
Video, audio, and timecode
The NDI SDK video clock controls the sending interval. The output uses
Pacing.SDK_CLOCK with clock_video enabled and clock_audio disabled.
Resolution follows each input image, and frame rate follows
ExitSettings.frame_period. Image widths must be divisible by two.
RGB images (without a matrix) are serialized as RGBA; images without alpha receive opaque alpha. YCbCr images (with a matrix) are serialized as UYVY: 8-bit 4:2:2, legal range, with byte order Cb0, Y0, Cr0, Y1. The output preserves the input matrix, colorspace, and transfer function. Convert incompatible images in your pipeline before submitting them.
NDI interprets UYVY colour according to the image resolution:
| Resolution | Required matrix | Required colorspace |
|---|---|---|
| Width > 1920 or height > 1080 | BT.2020 | Rec.2020 |
| Otherwise, width > 720 or height > 576 | BT.709 | Rec.709 |
| Otherwise | BT.601 | Preserved from the input |
An incompatible YCbCr image stops the output before reaching the SDK. The error identifies its matrix, colorspace, resolution, and the required NDI standard. The core serializes pixels into page-locked host memory, which the output passes directly to the SDK. That memory remains valid until serialization and SDK reads finish, including during shutdown.
When audio is enabled, the core supplies interleaved f32le PCM at the
requested sample rate and channel layout. The output rearranges it into NDI's
planar float layout without changing sample values or counts. The core handles
dropped frames, repeats, padding, and trimming. At 48 kHz and 30000/1001 fps,
five periods contain 8008 samples per channel. Disabled audio is not sent.
An input FrameTiming.source_timecode is converted to the NDI video frame's
100 ns timecode units. Its displayed hours, minutes, seconds, and nominal-rate
frame fraction are preserved, including for drop-frame labels. Fractional ticks
round to the nearest integer, with halves rounding up. Repeated pictures retain
that input timecode. Pictures without an input timecode receive the current
system time on every send, including repeats.
Ancillary metadata
Declare accepted kinds in settings.ancillary_kinds; the core rejects
undeclared kinds. Each new picture's AncillaryData.items becomes XML in the
NDI video frame's metadata:
<pixtreme_ancillary encoding="base64"><item kind="Y2FwdGlvbg==">PCY=</item></pixtreme_ancillary>
The example carries kind caption and payload bytes <&. Each AncillaryItem
becomes one item; its kind and payload use standard padded base64. Order,
duplicate kinds, opaque bytes, and empty payloads are preserved. Empty
collections produce no metadata. Repeats omit the original ancillary metadata.
C++ integration
The wheel installs its CMake package under pixtreme/transport/ndi/cmake.
Set pixtreme-transport-ndi_DIR to that directory and pixtreme_transport_DIR
to the core's CMake directory, call
find_package(pixtreme-transport-ndi CONFIG REQUIRED), and link pixtreme::ndi.
Include <pixtreme/transport/ndi/output.hpp> to use Output. Public headers
require the core SDK and do not require NDI SDK headers. The C session owns the
NDI sender; the C++ Output is a view of that session. Close the session explicitly
or release its last owning handle to stop it. Overriding the C++ view's processing
hooks to replace NDI sending is not supported.
License
This module's code is distributed under the MIT license.
The bundled libndi is subject to the NDI SDK License Agreement and the notices
in libndi_licenses.txt.
The wheel includes the complete nanobind and robin_map license texts and a
libndi notice in its .dist-info/licenses/ directory.
NDI terms and attribution
libndi is bundled with libndi_licenses.txt. NDI SDK redistribution remains
subject to its license conditions. Applications using NDI must supply the
applicable SDK license terms and notices to users, link to
NDI, and show the NDI® trademark and the attribution
“NDI® is a registered trademark of Vizrt NDI AB” near NDI selection or use,
in their About box, and in their trademark notices.
Metadata
Release files for pixtreme-transport-ndi 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pixtreme_transport_ndi-0.3.0-cp313-cp313-manylinux_2_28_x86_64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.28+ x86-64 | Details |
| pixtreme_transport_ndi-0.3.0-cp312-cp312-manylinux_2_28_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.28+ x86-64 | Details |
Total release size: 7.0 MB
Release files / pixtreme_transport_ndi-0.3.0-cp313-cp313-manylinux_2_28_x86_64.whl
| Download URL | pixtreme_transport_ndi-0.3.0-cp313-cp313-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 3.5 MB |
| Tags | CPython 3.13 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
fa96c2dee09f1d50e4d5e3b398e809c9b9c2d92e13a7579fcc0b00d84f87d383
|
|
BLAKE2b-256 checksum How to use checksums |
023bfbcd929ad89fec0fbe205c1fe1f76ec143abd462190ff550b2b1adb78a75
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.22
|
Release files / pixtreme_transport_ndi-0.3.0-cp312-cp312-manylinux_2_28_x86_64.whl
| Download URL | pixtreme_transport_ndi-0.3.0-cp312-cp312-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 3.5 MB |
| Tags | CPython 3.12 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
68d8e4fa65c48be199bf6dda27fec5e94bcfed3d031a962febd8a0a4c6551c27
|
|
BLAKE2b-256 checksum How to use checksums |
e30e34a921b52d28f893f47e0233bdad2bc9f5d2f2d18507c8cf8b3b6620ae28
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.22
|
Security for pixtreme-transport-ndi 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.