arrow-left

All pages
gitbookPowered by GitBook
1 of 27

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Startup and Shutdown

The functions NDIlib_initialize and NDIlib_destroy can be called to initialize or de-initialize the library. Although never absolutely required, it is recommended that you call these (Internally, all objects are reference-counted; the libraries are initialized on the first object creation and destroyed on the last, so these calls are invoked implicitly.)

In the latest version of NDI on platforms where the application has permissions, it will attempt to configure the firewall settings for the application to allow it to perform video communication over NDI.

The only negative side-effect of this behavior is that more work will be done than is required if you repeatedly create and destroy a single object. These calls allow that to be avoided. There is no scenario under which these calls can cause a problem, even if you call NDIlib_destroy while you still have active objects. NDIlib_initialize will return false on an unsupported CPU.

Dynamic Loading of NDI Libraries

At times you might prefer not to link directly against the NDI libraries, loading them dynamically at run time instead. This can be of value in Open-Source projects.

There is a structure that contains all the NDI entry points for a particular SDK version; calling a single entry point in the library will recover all these functions. The basic procedure is relatively simple, and an example is provided with the SDK.

hashtag
Locating the Library

You can, of course, include the NDI runtime within your application folder. Alternatively, on Windows, you can install the NDI runtime and use an environment variable to locate it on disk. If you are unable to locate the library on disk, you may ask users to perform a download from a standardized URL. System dependent #defines are provided to make this a simple process:

  • NDILIB_LIBRARY_NAME is a C #define to represent the dynamic library name (as, for example, the dynamic library Processing.NDI.Lib.x64.dll).

  • NDILIB_REDIST_FOLDER is a C #define variable that references an environment variable to the installed NDI runtime library (for example, C:\Program Files\NDI\NDI 5 Runtime\).

On the Mac, it is not possible to specify global environment variables, and so there is no standard way for the application to specify a path. For this reason, the redistributable on MacOS is installed within /usr/local/lib. It is our intent to make the process of cross-platform loading of the run times easier for the next version of NDI.

hashtag
Recovering the Function Pointers

Once you have located the library, you can look for a single exported function NDIlib_v5_load(). This function returns a structure of type NDIlib_v5 that gives you a reference to every NDI function.

hashtag
Calling NDI Functions

Once you have a pointer to NDIlib_v5, you can replace every function with a simple new reference. For instance, to initialize a sender you can replace a call to NDIlib_find_create_v2 in the following way:

NDIlib_find_create_v2(...) becomes p_NDILib->NDIlib_find_create_v2(...)

Software Distribution

To clarify which files may be distributed with your applications, the following are the files and the distribution terms under which they may be used for the SDK.

circle-info

Note that open-source projects have the right to include the header files within their distributions, which may then be used with dynamic loading of the NDI libraries.

hashtag
Header Files (NDI_SDK_DIR\INCLUDE\*.H)

These files may be distributed with open-source projects under the terms of the MIT license and may be included in open-source projects (see “Dynamic Loading” section for preferred mechanism). However, the requirements of these projects in terms of visual identification of NDI shall be as outlined within the License section above.

hashtag
Binary Files (NDI_SDK_DIR\BIN\*.*)

You may distribute these files within your application if your EULA terms cover the specific requirements of the NDI SDK EULA, and your application covers the terms of the License section above.

hashtag
❗Redistributables (NDI_SDK_DIR\REDIST\*.EXE)

You may distribute the NDI redistributable and install them within your own installer. However, you must make all reasonable efforts to keep the versions you distribute up to date. You may use the command line with /verysilent to install without any user intervention, but if you do, then you must ensure that the terms of the NDI license agreement are fully covered elsewhere in your application.

An alternative is to provide a user link to the NDI-provided download of this application at . At runtime, the location of the NDI runtime DLLs can be determined from the environment variable NDI_RUNTIME_DIR_V5.

hashtag
❗Content Files (NDI_SDK_DIR\LOGOS\*.*)

You may distribute all files in this folder as you need and use them in any marketing, product, or web material.

hashtag
Libraries

Components included in the SDK provide support for finding (find), receiving (recv), and sending (send). These share common structures and conventions to facilitate development and may all be used together.

hashtag
NDI-SEND

This is used to send video, audio, and metadata over the network. You establish yourself as a named source on the network, and then anyone may see and use the media that you are providing.

Video can be sent at any resolution and framerate in RGB(+A) and YCbCr color spaces, and any number of receivers can connect to an individual NDI-Send.

hashtag
NDI-FIND

This is used to locate all of the sources on the local network that are serving media capabilities for use with NDI.

hashtag
NDI-RECEIVE

This allows you to take sources on the network and receive them. The SDK internally includes all the requisite codecs and handles all the complexities of reliably receiving high-performance network video.

hashtag
Utilities

To make the library easy to use, the SDK includes several utilities that can be used to convert between common formats. For instance, conversion between different audio formats is provided as a service.

hashtag
Command Line Tools

There are also several important command line tools within the SDK, including a discovery server implementation and a command line application that can be used for recording.

Licensing

Our latest release brings an update to the NDI SDK terms, bringing these in line with our commitment to the health and growth of the NDI ecosystem. The NDI SDK remains royalty-free, subject to the SDK terms and conditions. For more details including a full explanation and updated list of exclusions please consult the terms and conditions by downloading the NDI 6.2.1 SDK.

These changes apply to the NDI SDK only and are not applicable to the NDI Advanced SDK.

You may use this SDK in accordance with its License Agreement, which is available for review in the root level of the SDK folder. Your use of any part of the SDK for any purpose is an acknowledgment that you agree to these license terms. For distribution, you must implement this SDK within your applications respecting the following requirements:

  • Your application must provide a link to ndi.videoarrow-up-right in a location close to all locations where NDI is used/selected within the product, on your website, and in its documentation. This link will point to a landing page that provides information about NDI and access to the tools we provide, along with updates and news.

  • You may not distribute the NDI tools; if you wish to make these accessible to your users, you may provide a link to .

  • NDI is a registered trademark of Vizrt NDI AB and should be used only with the ® as follows: NDI®, along with the statement “NDI® is a registered trademark of Vizrt NDI AB” located on the same page near the mark where it is first used, or at the bottom of the page in footnotes. You are required to use the registered trademark designation only on the first use of the word NDI within a single document.

  • Your application’s About Box and any other locations where trademark attribution is provided should also specifically indicate that “NDI® is a registered trademark of Vizrt NDI AB”. If you have questions, please do let us know.

circle-exclamation

Note that if you wish to use “NDI” within the name of your product please reach out to the .

  • You should include the NDI DLLs as part of your own application and keep them in your application folders so that there is no chance that NDI DLLs installed by your application might conflict with other applications on the system that also use NDI. Please do not install your NDI DLLs into the system path for this reason. If you are distributing the NDI DLLs, you need to ensure that your application complies with the License Agreement, this section, and the license terms outlined in “3rd party rights” towards the end of this manual.

We are very interested in how our technology is being used and would like to maintain a full list of applications using NDI technology. Please let us know about your commercial application (or an interesting non-commercial one) using NDI by reaching out to the . If you have any questions, comments, or requests, please do not hesitate to let us know. Our goal is to provide you with this technology and encourage its use while ensuring that both end-users and developers enjoy a consistent high-quality experience.

circle-exclamation

Because AAC, H.264, and H.265 are formats that potentially are not license-free, it is your responsibility to ensure that these are correctly licensed for your product if you are using these with this SDK.

SDK

circle-exclamation

This documentation refers to the NDI SDK, which is open to use and explore, and available only for software. If you're looking to integrate the full features and potential of our connectivity tech into both software and hardware, including support for our most advanced codecs, and maximum personalization of all connection settings, you should request NDI Advancedarrow-up-right.

This documentation is paramount for developers and integrators seeking to consistently embed the full potential of NDI technology into their products.

This comprehensive guide aims to provide a clear roadmap to understanding and implementing NDI within your applications, systems, and workflows. Whether you're a seasoned developer or a newcomer to NDI, it will empower you to seamlessly leverage the capabilities of NDI, enabling your products to seamlessly connect with other NDI-enabled products and transmit high-quality, low-latency video and audio over IP networks.

From setup and configuration to advanced usage scenarios, this SDK documentation is your go-to resource to unlock our connectivity tech, facilitating innovation and efficiency across a broad spectrum of applications.

This documentation is continuously updated to match the most recent version of our Core Technology. We now offer NDI 6.3 You can check the most meaningful updates in our

circle-info

Read our if you'd like to know more about the vision of NDI and our technology's fundamental features, protocols, and settings.

CPU Requirements

NDI Lib is heavily optimized (much of it is written in assembly). While it detects available architecture and uses the best path it can, the minimum required SIMD level is (introduced by Intel in 2005).

The NDI library running on ARM platforms requires NEON support. To the degree possible, hardware acceleration of streams uses GPU-based fixed function pipelines for decompression and is supported on Windows, macOS, iOS, and tvOS platforms; all GPUs on these platforms are supported with special case-optimized support for Intel QuickSync and nVidia.

However, this is not required, and we will always fall back to software-based compression and decompression.

Example Code

The NDI SDK includes many examples including examples that show the sending, and receiving of data, finding sources, use of 10-bit video, and many more. To get you started check out the following articles.

ndi.link/NDIRedistV5arrow-up-right
ndi.video/toolsarrow-up-right
NDI teamarrow-up-right
NDI teamarrow-up-right
release notes
White Paper
SSSE3arrow-up-right

NDILIB_REDIST_URL is a C #define for a URL where the redistributable for your platform may be downloaded (for example, ).

These are just a few examples among many offered. You can also find plenty of examples in the folder marked "Examples" if yo downloaded the SDK. If you used Windows just navigate to the default install location "C:\Program Files\NDI\NDI 6 SDK". We recommend that you look closely at these since they provide good, simple illustrations of many possible SDK use cases.

NDI Sending instancearrow-up-right
How to Receive Audio or Videoarrow-up-right

Support

If you have any problems or doubts about this documentation or any utilization of the SDK, please sign up on our , and we will do our best to support you.

http://ndi.link/NDIRedistV6arrow-up-right
NDI Genlockarrow-up-right
NDI support hubarrow-up-right

3rd Party Rights

The NDI libraries make minor use of other third-party libraries, for which we are very grateful to the authors. If you are distributing NDI DLLs yourself, it is important that your distribution is compliant with the licenses for these third-party libraries. For the sake of convenience, we have combined these licenses within a single file that you should include, Processing.NDI.Lib.Licenses.txt, which is included beside the NDI binary files.

NDI Sender Advertiser

The NDIlib_send_advertiser_create function creates an instance of the sender advertiser. This function returns an instance of type NDIlib_send_advertiser_create_t (or NULL if it fails), representing the sender advertiser instance.

The function takes parameters defined by NDIlib_send_advertiser_create_t, as follows:

Parameter
Description

p_url_address (const char*)

This parameter represents the URL address of the NDI Discovery Server to connect to. If NULL, the default NDI discovery server will be used. If no discovery server is available, the sender advertiser will not be instantiated, and the create function will return NULL. The format of this field is expected to be the hostname or IP address, optionally followed by a colon and a port number. If the port number is not specified, port 5959 will be used.

For example: 127.0.0.1:5959, 127.0.0.1, or hostname:5959. This field can also specify multiple addresses separated by commas for redundancy support.

Once the structure is filled out, NDIlib_send_advertiser_create will create an instance for you. The sender advertiser instance is destroyed by passing it into NDIlib_send_advertiser_destroy.

hashtag
Adding a Sender for Advertising

To add your NDI sender for advertising, call the following function:

This function adds the sender to the list of senders being advertised. It returns false if the sender has been previously registered.

Parameters:

  • p_instance: The sender advertiser instance from the NDIlib_send_advertiser_create call.

  • p_sender: An already instantiated NDI sender instance from the NDIlib_send_create call.

hashtag
Removing a Sender from Advertising

To remove the sender from the list of senders being advertised, call the corresponding function:

This function returns false if the sender was not previously advertised.

Example Code:

The following code illustrates how to add/register a sender and remove it from the advertiser. Note: A full example is provided with the SDK that illustrates registering a sender for advertisement (we will not reproduce that code here).

This example demonstrates the creation, registration, and destruction of an NDI sender and its associated advertiser.

HDR

NDI SDK v6 supports 16-bit data formats and standardizes metadata elements to specify wide gamut color primaries and HDR transfer functions, including HLG and PQ. This enables broadcasting high bit depth, wide color gamut, and high dynamic range video, with brightness up to 10000 nits when using the PQ transfer function.

circle-info

For in-depth information about HDR production, please consult the , "Guidance for operational practices in HDR television production".

The specific HDR capabilities available to your system will vary depending on your license and the SDK you use, as described next.


NDI-FIND

This is provided to locate sources available on the network and is normally used in conjunction with NDI-Receive. Internally, it uses a cross-process P2P mDNS implementation to locate sources on the network. (It commonly takes a few seconds to locate all the sources available since this requires other running machines to send response messages.)

Although discovery uses mDNS, the client is entirely self-contained; Bonjour (etc.) is not required. mDNS is a P2P system that exchanges located network sources and provides a highly robust and bandwidth-efficient way to perform discovery on a local network.

On mDNS initialization (often done using the NDI-FIND SDK), a few seconds might elapse before all sources on the network are located. Be aware that some network routers might block mDNS traffic between network segments.

hashtag

allow_monitoring: A flag to allow monitoring of the sender.

Windows DirectShow Filter

The Windows version of the NDI SDK includes a DirectShow audio and video filter. This is particularly useful for people wishing to build simple tools and integrate NDI video into WPF applications.

Both x86 and x64 versions of this filter are included in the SDK. If you wish to use them, you must first register those filters using regsvr32. The SDK install will register these filters for you. The redistributable NDI installer will also install and register these filters, which can be downloaded by users herearrow-up-right. You may, of course, include the filters in your own application installers under the terms of the NDI license agreement.

Once the filter is registered, you can instantiate it by using the GUID:

DEFINE_GUID(CLSID_NdiSourceFilter, 0x90f86efc, 0x87cf, 0x4097, 
            0x9f, 0xce, 0xc, 0x11, 0xd5, 0x73, 0xff, 0x8f);

The filter name is “NDI Source”. The filter presents audio and video pins you may connect to. Audio is supported in floating-point and 16-bit, and video is supported in UYVY and BGRA.

The filter can be added to a graph and will respond to the IFileSourceFilter interface. This takes “filenames” in the form ndi://computername/source. This will connect to the “source” on a particular “computer name“. For instance, to connect to an NDI source called “MyComputer (Video 1)”, you must escape the characters and use the following URL: ndi://MyComputer/Video+1

To receive just the video stream, use the audio=false option as follows:

NDI://computername/source?audio=false

Use the video=false option to receive just the audio stream, as in the example below:

NDI://computername/source?video=false

Additional options may be specified using the standard method to add to URLs, for example:

NDI://computername/source?low_quality=true NDI://computername/source?audio=false&low_quality=true&force_aspect=1.33333&rgb=true

Parameters

Creating the find instance is very similar to the other APIs – one fills out a NDIlib_find_create_t structure to describe the device that is needed. It is possible to specify a NULL creation parameter, in which case default parameters are used.

If you wish to specify the parameters manually, then the member values are as follows:

Supported Values

show_local_sources (bool)

This flag tells the finder whether it should locate and report NDI-SEND sources that are running on the current local machine.

p_groups (const char*)

This parameter specifies groups for which this NDI finder will report sources. A full description of this parameter and what a NULL default value means is provided in the description of the NDI-SEND SDK.

p_extra_ips (const char*)

This parameter will specify a comma-separated list of IP addresses that will be queried for NDI sources and added to the list reported by NDI find.

These IP addresses need not be on the local network and can be in any IP visible range. NDI-FIND will be able to find and report any number of NDI sources running on remote machines and will correctly observe them coming online and going offline.

Once you have a handle to the NDI-FIND instance, you can recover the list of current sources by calling NDIlib_find_get_current_sources at any time. This will immediately return with the current list of located sources.

The pointer returned by NDIlib_find_get_current_sources is owned by the finder instance, so there is no reason to free it. It will be retained until the next call to NDIlib_find_get_current_sources, or until the NDIlib_find_destroy function is destroyed.

You can call NDIlib_find_wait_for_sources to wait until the set of network sources has been changed; this takes a time-out in milliseconds. If a new source is found on the network, or one has been removed before this time has elapsed, the function will return true immediately. If no new sources are seen before the time has elapsed, it will return false.

The following code will create an NDI-FIND instance and then list the currently available sources. It uses NDIlib_find_wait_for_sources to sleep until new sources are found on the network and, when they are seen, calls NDIlib_find_get_current_sources to get the current list of sources:

It is important to understand that mDNS discovery might take some time to locate all network sources. This means that an ‘early’ return to NDIlib_find_get_current_sources might not include all the sources on the network; these will be added (or removed) as additional or new sources are discovered. It commonly takes a few seconds to discover all sources on a network.

For applications that wish to list the current sources in a user interface menu, the recommended approach would be to create an NDIlib_find_instance_t instance when your user interface is opened and then – each time you wish to display the current list of available sources – call NDIlib_find_get_current_sources.

If you are running NDI applications on a Linux distribution (such as CentOS, RHEL, or Ubuntu), Avahi is typically required for mDNS functionality, both for advertising a source and for a receiver looking for available sources.

NDI Source (Advertising): The NDI library on Linux generally relies on the Avahi daemon to register and advertise the NDI source service over mDNS.

NDI Receiver (Discovering): Similarly, Avahi is usually needed for the receiver to successfully resolve the .local hostnames and discover the advertised NDI sources on the local network via mDNS.

You would typically need to install and ensure the avahi-daemon service is running and configured correctly (e.g., using packages like avahi and avahi-tools).

bool NDIlib_send_advertiser_add_sender(
     NDIlib_send_advertiser_instance_t p_instance,
     NDIlib_send_instance_t p_sender,
     bool allow_monitoring
);
bool NDIlib_send_advertiser_del_sender(
     NDIlib_send_advertiser_instance_t p_instance,
     NDIlib_send_instance_t p_sender
);
// Create an unconnected sender that will be set up for advertising.
NDIlib_send_instance_t pNDI_sender = NDIlib_send_create();
if (!pNDI_sender) {
    // Handle error
}
 
// Create an instance of the sender advertiser
NDIlib_send_advertiser_instance_t pNDI_send_advertiser = NDIlib_send_advertiser_create();
if (!pNDI_send_advertiser) {
    // Handle error
}
 
// Register the sender with the advertiser
NDIlib_send_advertiser_add_sender(pNDI_send_advertiser, pNDI_sender, true);
 
// Do stuff
...
 
// Remove the sender from the advertiser before destroying it
NDIlib_send_advertiser_del_sender(pNDI_send_advertiser, pNDI_sender);
 
// Destroy the sender advertiser
NDIlib_send_advertiser_destroy(pNDI_send_advertiser);
 
// Destroy the sender
NDIlib_send_destroy(pNDI_sender);
// Create the descriptor of the object to create 
NDIlib_find_create_t find_create; 
find_create.show_local_sources = true; 
find_create.p_groups = NULL;

// Create the instance
NDIlib_find_instance_t pFind = NDIlib_find_create_v2(&find_create); 
if (!pFind)
    /* Error */;
    
while (true) // You would not loop forever of course ! 
{
    // Wait up till 5 seconds to check for new sources to be added or removed 
    if (!NDIlib_find_wait_for_sources(pFind, 5000))
    {
       // No new sources added!
       printf("No change to the sources found.\n"); 
    }
    else
    {
       // Get the updated list of sources 
       uint32_t no_sources = 0;
       const NDIlib_source_t* p_sources =
          NDIlib_find_get_current_sources(pFind, &no_sources);
          
       // Display all the sources.
       printf("Network sources (%u found).\n", no_sources); 
       for (uint32_t i = 0; i < no_sources; i++)
          printf("%u. %s\n", i + 1, p_sources[i].p_ndi_name);
    }
}
// Destroy the finder when you’re all done finding things 
NDIlib_find_destroy(pFind);
hashtag
Differences between the NDI SDK and the NDI Advanced SDK

Systems licensed to integrate the NDI Advanced SDK:

  • Can receive and process HDR content

  • Can send HDR content

circle-exclamation

When using the trial version of the NDI Advanced SDK, sending HDR content is limited to 30 minutes (the stream will stop automatically afterward).

Systems that integrate the NDI SDK:

- Can receive and process HDR content

- Cannot send content with HDR metadata

triangle-exclamation

Any systems integrating NDI 5 or older versions of both the NDI SDK and the NDI Advanced SDK cannot send or receive HDR content (in this case, a placeholder frame will be displayed).

hashtag
HDR Metadata

Video frames can be annotated with HDR metadata by writing an XML string into the p_metadata member of the NDIlib_video_frame_v2_t struct.

The receiver can use this metadata to interpret the received frames' content correctly. The NDI SDK will not alter the content of the frame in any way.

The HDR metadata format consists of an ndi_color_info XML element containing the following three attributes:

  • "primaries" - specifies the chromaticity coordinates of the color primaries of the video frame.

  • "transfer" - specifies the brightness transfer characteristic.

  • "matrix" - Specifies the matrix coefficients used in deriving luma and chroma from RGB or XYZ primaries.

The following values are defined for these attributes:

"primaries"
"transfer"
“matrix”

“bt_601”

“bt_601”

“bt_601”

“bt_709”

“bt_709”

“bt_709”

circle-info

For a detailed description of these video format properties please consult ITU-T H.273arrow-up-right.

Example:

If multiple XML elements must be added to the same frame, use an ndi_metadata_group XML element as root node.

Example:

circle-info

For in-depth information about the individual options please consult ITU-T Rec. H.273arrow-up-right, "Coding-independent code points for video signal type identification".

hashtag
Sending Compressed HDR Frames

Sending compressed 10-bit or 12-bit H.264 and HEVC frames is much like non-HDR frames, but with the addition of frame annotations supplying HDR metadata as described above.

hashtag
Sending Uncompressed HDR Frames

HDR transfer functions are defined in ITU BT.2100 and specify 10 and 12- bit integer representations for both PQ and HLG variants.

To send uncompressed 10-bit and 12-bit HDR frames via SHQ streams, first convert the video data to 16-bit, limited range, and write it into a P216 buffer (or a PA16 buffer if an alpha channel is required).

For limited range 10-bit and 12-bit HDR formats, simply padding the lower bits with zeroes is sufficient to result in a valid 16-bit limited range value.

Please note that full-range signals are not supported by NDI Tools at this point. To convert full-range signals to 16-bit limited range signals, normalize the full-range signal to the 0.0...1.0 floating point range, and convert to limited range 16-bit integers using the quantization equations specified in the ITU BT.2100 recommendation.

hashtag
Receiving Compressed HDR Frames

The p_metadata member of the NDIlib_video_frame_v2_t data structure may contain the HDR metadata described above. (Please note that the ndi_color_info may be nested under a ndi_metadata_group XML root element.)

NDI receivers receiving HDR frames using NDI SDK versions older than v6 will send a placeholder image showing the incompatibility of the stream.

hashtag
Receiving Uncompressed HDR Frames

The NDI SDK can uncompress high-bit depth frames to P216 or PA16 buffer formats if required.

When a high bit depth stream is supplied, configure the NDI receiver to use the "best" color format to receive high bit depth frames:

circle-exclamation

Note that if the video frame is requested in 8-bit format, the NDI SDK does not attempt down-mapping from HDR to SDR.

report ITU-R BT.2408arrow-up-right

Release Notes

circle-info

These release notes refer to changes in our complete technology, including the SDKs, NDI Tools, and any other items. Take your time to comb through the documentation and decide what is more relevant for your specific context.

*Any reference to a ChangeLog refers to the release notes shown below

February 9, 2026

hashtag
NDI 6.3.1

hashtag
Fixed

  • Potential deadlock issue in the new discovery server with sources for older versions

  • Rare rash in on Mac when enabling NDI output and allowing network access

  • Issue where fails to auto launch at starup if the selected source is unavailable

January 21, 2026

hashtag
NDI 6.3.0

hashtag
NDI Tools

August 21, 2025

hashtag
NDI 6.2.1

Fixed

circle-exclamation

June 3, 2025

hashtag
NDI 6.2

hashtag
NDI Tools

December 23, 2024

hashtag
NDI 6.1.1

Fixes

  • Resolved a low-level exception that occurred when importing recorded SpeedHQ files into Adobe Premiere Pro.

December 5, 2024

hashtag
NDI 6.1.0

SDK

  • FPGA improvements.

May 8, 2024

hashtag
NDI 6.0.1

hashtag
NDI Tools - HDR

March 25, 2026

hashtag
NDI 6.0.0

hashtag
SDK

Platform Considerations

Of course, all platforms are slightly different, and the location of configuration files and the settings can differ slightly between platforms. On all platforms, if there is an environment variable NDI_CONFIG_DIRset before initializing the SDK, then we will load the ndi-config.v1.json from this folder when the library is used.

hashtag
Windows

The Windows platform is fully supported and provides high performance in all paths of NDI. As with all operating systems, the x64 version provides the best performance. All modern CPU feature sets are supported. Please note that the next major version of NDI will deprecate support for 32-bit Windows platforms.

We have found that on some computer systems, if you install "WireShark" to monitor network traffic, a virtual device driver called "NPCap Loopback Driver" installs can interfere with NDI, potentially causing it to fail to communicate. This is also a potential performance problem for networking since it is designed to intercept network traffic. This driver is not required or used by modern versions of Wireshark. If you find it is installed on your system, we recommend that you go to your network settings and use the context menu on the adapter to disable it.

The NDI Tools bundle for Windows includes “Access Manager”, a user interface for configuring most of the settings outlined above. These settings are also stored in C:\ProgramData\NDI\ndi-config.v1.json.

hashtag
Windows UWP

Unfortunately, the Universal Windows Platform imposes significant restrictions that can negatively affect NDI, and about which you need to be aware. These are listed below.

  • The UWP platform does not allow the receiving of network traffic from Localhost. This means that any sources on your local machine will not be able to be received by a UWP NDI receiver.

  • The current Windows 10 UWP mDNS discovery library has a bug that will not correctly remove an advertisement from the network after the source is no longer available; this source will eventually “time out” on other finders; however, this might take a minute or two.

  • Due to sandboxing, UWP applications cannot load external DLLs. This makes it unlikely that NDI|HX will work correctly.

hashtag
MacOS

The Mac platform is fully supported and provides high performance in all paths of NDI. As with all operating systems, the x64 version provides the best performance. Reliable UDP support requires macOS 10.14 or later, which enables IPv6 socket properties; NDI will work on earlier versions, but Reliable UDP will not be used.

Because of recent changes made within macOS in regard to the signing of libraries, if you wish NDI HX version 1 to work within your applications, you should locate the options in XCode under “Targets->Signing & Capabilities” and ensure that the option “Hardened Runtime -> Disable Library Validation” is checked.

In iOS 14 and XCode 12, a new setting was introduced to enable support for mDNS and Bonjour. Under “Bonjour Services”, one should assign “Item 0” as being “_ndi._tcp.” in order for NDI discovery to operate correctly.

The configuration settings are stored in $HOME/.ndi/ndi-config.v1.json.

hashtag
Android

Because Android handles discovery differently than other NDI platforms, some additional work is needed. The NDI library requires the use of the “NsdManager” from Android, and there is no way for a third-party library to do this on its own. As long as an NDI sender, finder, or receiver is instantiated, an instance of the NsdManager will need to exist to ensure that Android’s Network Service Discovery Manager is running and available to NDI.

This is normally done by adding the following code to the beginning of your long-running activities:

private NsdManager m_nsdManager;

At some point before creating an NDI sender, finder, or receiver, instantiate the NsdManager:

m_nsdManager = (NsdManager)getSystemService(Context.NSD_SERVICE);

You will also need to ensure that your application is configured to have the correct privileges required for this functionality to operate.

hashtag
iOS

iOS supports NDI finding, sending, and receiving.

In iOS 14 and XCode 12, a new setting was introduced to enable support for mDNS and Bonjour. Under “Bonjour Services”, one should assign “Item 0” as being “_ndi._tcp.” In order for NDI discovery to operate correctly. It is also required to enable networking in the App sandbox settings.

The configuration settings are stored in $HOME/.ndi/ndi-config.v1.json.

hashtag
Linux

The Linux version is fully supported and provides high performance in all paths of NDI. The NDI library on Linux depends on two 3rd party libraries:

libavahi-common.so.3

libavahi-client.so.3

The usage of these libraries depends on the avahi-daemon service to be installed and running.

The configuration settings are stored in $HOME/.ndi/ndi-config.v1.json.

circle-exclamation

Please take careful note of the comments under Linux in the Reliable UDP in the Performance and Implementation section.

NDI Routing

Using NDI routing, you can create an output on a machine that looks just like a ‘real’ video source to all remote systems. However, rather than producing actual video frames, it directs sources watching this output to receive video from a different location.

For instance: if you have two NDI video sources - Video Source 1 and Video Source 2 – you can create an NDI_router called Video Routing 1 and direct it at Video Source 1. Video Routing 1 will be visible to any NDI receivers on the network as an available video source. When receivers connect to “Video Routing 1”, the data they receive will actually be from “Video Source 1”.

NDI routing does not actually transfer any data through the computer hosting the routing source; it merely instructs receivers to look at another location when they wish to receive data from the router. Thus, a computer can act as a router exposing potentially hundreds of routing sources to the network – without any bandwidth overhead. This facility can be used for large-scale dynamic switching of sources at a network level.

// // HDR require metadata information in video frame
// note 'transfer' have two possible values for HDR: bt_2100_pq or bt_2100_hlg
NDI_video_frame_16bit.p_metadata =
    "<ndi_color_info "
    "   transfer=\"bt_2100_hlg\" "
    "   matrix=\"bt_2020\" "
    "   primaries=\"bt_2020\" "
    "/> ";
<ndi_color_info primaries="bt_2020" transfer="bt_2100_hlg" matrix="bt_2020" />
<ndi_metadata_group>
    <ndi_color_info primaries="bt_2020" transfer="bt_2100_hlg" matrix="bt_2020" />
</ndi_metadata_group>
NDIlib_recv_create_v3_t NDI_recv_create_desc;
NDI_recv_create_desc.source_to_connect_to = *p_hdr_source;
NDI_recv_create_desc.color_format = NDIlib_recv_color_format_best;
 
// Create the receiver
NDIlib_recv_instance_t pNDI_recv = NDIlib_recv_create_v3(&NDI_recv_create_desc);
If the incoming NDI stream is high bit depth then the video frame received via NDIlib_recv_capture_v2 will have a fourCC of either NDIlib_FourCC_video_type_P216 or NDIlib_FourCC_video_type_PA16.

“bt_2020”

“bt_2020”

“bt_2020”

“bt_2100”

“bt_2100_hlg”

“bt_2100”

“bt_2100_pq”

When you create a new UWP project, you must ensure you have all the correct capabilities specified in the manifest for NDI to operate. Specifically, at time of writing, you need:

  • Internet (Client & Server)

  • Internet (Client)

  • Private Networks (Client & Server)

https://docs.microsoft.com/en-us/windows/iot-core/develop-your-app/loopbackarrow-up-right
You create a video routing source using:

The creation settings allow you to assign a name and group to the source that is created. Once the source is created, you can tell it to route video from another source using:

and:

Finally, when you are finished, you can dispose of the router using:

NDIlib_routing_instance_t NDIlib_routing_create( 
    const NDIlib_routing_create_t* p_create_settings);
bool NDIlib_routing_change(NDIlib_routing_instance_t p_instance, 
                           const NDIlib_source_t* p_source);
bool NDIlib_routing_clear(NDIlib_routing_instance_t p_instance);
void NDIlib_routing_destroy(NDIlib_routing_instance_t p_instance);
NDI Bridge Service auto-start issue where the service appeared running but failed to start
  • Added new command-line options in the NDI Recording tool. Please refer to the SDK documentation for details.

  • Sender Monitoring Enhancements
    : The
    now includes sender discovery and monitoring on both Windows and macOS.

    Default Sender Monitoring Support: Enabled by default in existing sender-based NDI Tools apps.

    Windows: NDI Test Patterns, NDI Screen Capture, NDI Screen Capture HX, NDI VLC Plugin.

    macOS: NDI Test Patterns, NDI Scan Converter.

    NDI Discovery Server Improvements: Enhanced sender discovery and monitoring capabilities. The NDI server utility is now available as a standalone installer for Windows and Linux and can run as a service. See documentation for setup details.

    hashtag
    Fixed

    • Fixed an issue in the NDI plugin for Adobe Premiere where the field sequence was incorrectly displayed when playing SpeedHQ progressive clips in interlaced sequences.

    • Resolved poor NDI HX encoding performance on AMD GPU/CPU systems in Screen Capture HX and NDI Bridge.

    • Fixed NDI Virtual Input on macOS failing to receive video when connected via Discovery Server and Access Manager.

    • Resolved an issue where would stop receiving video from the NDI HX Camera app when the camera resolution was changed.

    • Corrected video preview rendering in NDI Webcam to properly respect the source aspect ratio.

    • Fixed terminating active streams upon application closure.

    hashtag
    NDI SDK

    New APIs: Introduced APIs for sender discovery and monitoring, designed for integration with the NDI Discovery Server. See documentation for details.

    Performance Improvements: Enhanced SpeedHQ codec quality across multiple generations.

    Enabled passthrough of the NDI capabilities message from NDI receiver to the NDI sender.

    Enhanced Receiver Passthrough Control: Introduced per-codec passthrough override control via receiver creation JSON in the NDI Advanced SDK, enabling selective decompression of compressed formats. Please refer to the SDK documentation for details.

    Improvements to FPGA reference design. Please refer to the ChangeLog files for more details.

    Our latest release brings an update to the NDI SDK terms, bringing these in line with our commitment to the health and growth of the NDI ecosystem. The NDI SDK remains royalty-free, subject to the SDK terms and conditions. For more details including a full explanation and updated list of exclusions please consult the terms and conditions by downloading the NDI 6.2.1 SDK. These changes apply to the NDI SDK only and are not applicable to the NDI Advanced SDK. For more information see the Community Announcementarrow-up-right in our Forums.
    • Updated the NDI Tools installer to display the Privacy Policy on the data collection agreement page.

    • Fixed an issue with silent installation of NDI Tools.

    • Fixed an issue where the NDI Discovery Server running as a service would not start automatically after windows restart.

    • Added URL connection reporting in the when monitoring NDI receivers connected to HX1 sources.

    • Fixed a localization issue in the statistics window.

    • Fixed a crash that could occur when destroying an NDI receiver during an active connection attempt to a source. Improved handling of deinterlacing in r.

    • A new 'deinterlacing' option has been added to the Video Settings menu.

    • Fixed incorrect byte order handling when using NDIlib_recv_color_format_RGBX_RGBA.

    • Fixed an issue where NDI output from could change resolution when clips on the timeline ended.

    • Resolved an issue where could incorrectly select a temporary GPU adapter, which might become unavailable when remote desktop sessions end.

    • Fixed a potential issue where an NDI Finder could block indefinitely in certain environments.

    • Removed the application from the NDI Tools Suite. See for more details

    Introduced the NDI Discovery app in the Tools suite for macOS and Windows for NDI receiver discovery, monitoring and control.

  • NDI Tools now includes support for anonymous usage data collection to help improve future releases. Users can choose to opt in or out during setup and update their preference anytime from the NDI Tools Launcher.

  • Updated NDI Studio Monitor (Windows) and NDI Video Monitor (Mac) to enable settings for receiver monitoring and remote source control when used with the new NDI Discovery Server.

  • Improved Access Manager for easier multicast configuration on Windows and Mac.

  • Added a new setting in Screen Capture applications on Windows to enable or disable notifications for new connections.

  • Improved error handling and user notifications in Screen Capture applications on Windows.

  • hashtag
    Standalone Tools

    • Enhanced existing NDI Discovery Server with new capabilities for receiver discovery, monitoring, and control. It is now available as a standalone installer for Windows and Linux, allowing it to run as a service. Refer to the documentation for details.

    • Updated the NDI Bridge Service to include local mode support.

    hashtag
    Fixed

    • A problem in NDI Webcam and NDI Router where the preview window could freeze or fail to render video.

    • Issue where the NDI record binary would stop recording when the record chop command was used with the -noautochop flag.

    • Crash in Scan Converter on macOS that occurred when its signal was received in Video Monitor or Studio Monitor.

    • Addressed a localization issue that skewed statistics in .

    • Usage of incorrect units for packet lost metric in statistics window.

    • Issue where the host could crash during stream cleanup or closure.

    • Fixed a potential crash in the NDI VST output plugin when used with certain DAW applications.

    • Issue where audio frameworks could fail to load at runtime on macOS, causing to detect no audio devices.

    hashtag
    NDI SDK

    • Introduced a new set of APIs for receiver discovery, monitoring, and control, designed for integration with the NDI Discovery Server. Refer to the documentation for details.

    • Added visionOS support to Apple SDKs.

    • Optimized audio resampler performance in NDI Frame Sync on ARM-based platforms.

    • Improved single-TCP sending performance by using scatter-gather to reduce per-message ACKs.

    hashtag
    Fixed

    • Resolved a potential crash in the NDI library when handling UDP streams on certain ARM-based processors.

    Fixed an issue where NDI Virtual Input might stop functioning after a few seconds on certain macOS platforms.

  • Improved handling of connection metadata when used with the NDI Routing API.

  • Addressed a possible issue with the Discovery Server where sources might not appear intermittently.

  • Resolved a potential memory leak issue in NDI Test Patterns on Windows.

  • Added support for 16-bit color formats on FPGA platforms.

  • Introduced encoder support for planar alpha.

  • Added support for new packed and semi-planar video formats.

  • Implemented 64-bit addressing in raw audio/video input and output logic. For more details, refer to the ChangeLog files.

  • The Advanced SDK now features a new API that enables dynamic adjustment of the received bandwidth for NDI video streams. For more information, please consult the Advanced SDK documentation.

  • Added new audio conversion utility APIs for NDIlib_audio_frame_v3_t structure.

  • Made improvements to the SpeedHQ codec to verify the correctness of the bitstream before decompression.

  • SDK - Fixes

    • Fixed incorrect HDR color information in MOV files recorded using the NDI Recorder utility.

    • Addressed an issue where the NDI library took longer than expected to unload in specific scenarios.

    • Addressed a potential frame drop issue with NDI HX streams under specific conditions.

    • General improvements to the .

    NDI Tools

    • NDI Tools launcherarrow-up-right layout and style improvements. (macOS and Windows).

    • The NDI Virtual Input app on macOS has been updated to utilize modern system extensions introduced in macOS Sonoma 14.1.

    • All NDI Tools apps on Windows have been updated to use .NET 8.

    NDI Tools - NDI Bridge

    • A connection test feature was added to determine optimal buffer delay settings for your network.

    • Introduced a dedicated statistics window with timeline graphs to monitor system and bridge usage.

    • Added a logging window with support for log-level filters to view bridge logs more effectively.

    • Local mode now includes an option to configure the local send group for bridge sources.

    NDI Tools - New Utilities

    • The NDI Bridge Service is now available for free downloadarrow-up-right on the NDI website. It allows you to run NDI Bridge in a headless mode as a Windows service. Please refer to the documentation for more details.

    • The NDI Free Audio utility is now available for free downloadarrow-up-right on Windows and Linux via the NDI website. It also includes enhanced ASIO support for Windows devices.

    • The NDI Analysis tool has been improved to include additional information about NDI stream timings when exporting to a CSV file. Please refer to the NDI Analysis documentation for more details.

    NDI Tools - Fixes

    • NDI Access Manager (macOS) now supports inputting multiple discovery server IP addresses.

    • Corrected an issue in NDI Router (macOS) where HDR images were not rendered properly in the preview.

    • Resolved a potential exception in the source menu of NDI Router (macOS) when parsing NDI sources.

    • Resolved an issue where failed to auto-start in Local mode.

    • Fixed a potential deadlock when closing an stream in Join mode.

    • Corrected NDI Test Patterns to ensure the full Rec.709 color range is output for imported images (Windows).

    • Fixed an issue with when enumerating system audio devices.

    • Resolved a potential issue in when rendering test patterns with alpha transparency.

    • Enabled high bit-depth decoding in for streams with BT.2020 color primaries.

    • Added support for higher color depth when playing SDR files using the VLC player with the NDI output plugin enabled.

    • Fixed audio driver stability issues with .

    NDI Tools - Known Issues

    • NDI Virtual Input may stop working after a few seconds with certain macOS platforms.

    The NDI output plugin for VLC now includes HDR support<html>

    hashtag
    NDI Tools - Fixes

    • Corrected rendering issue when importing custom images from older versions of NDI Test Patterns on Windows.

    • Resolved a potential crash in NDI Remote.

    • Resolved a minor talkback audio issue in NDI Remote.

    • Added a firewall exception rule for the app.

    • Resolved an issue with loading the on newer macOS versions.

    • on Mac was not playing audio.

    • Ensured correct permissions were set on the NDI Runtime installer on MacOS.

    • Resolved an issue where the NDI Tools registration state was not being saved correctly.

    hashtag
    NDI SDK - Fixes

    • Resolved a source limitation issue with the NDI Discovery server running on Linux.

    • Addressed an issue with NDI Frame Sync, restoring correct behavior in audio capture.

    • Fixed a potential threading issue when loading and unloading the NDI library on Windows.

    • Support for 16-bit color formats improved (P216/PA16).

    • There is a new specification for NDI HDR metadata (read the new dedicated HDR section in the NDI SDK for more details).

    • New receiver formats permit SpeedHQ pass-through with UYVY/P216 video.

    • HDR example code samples are provided with NDI SDK.

    • The NDI Advanced SDK includes a new for hardware (currently available for Linux), with comprehensive guidance on its use.

    • enhanced to capture NDI HDR streams.

    circle-info

    Please note: The NDI Advanced SDK licensing scheme has been enhanced. To use NDI 6.0 features, advanced SDK users will need a new License ID (which replaces the former Vendor ID). Please contact [email protected]envelope

    hashtag
    SDK - Fixes

    Improved audio synchronization with NDI Frame Sync API.

    hashtag
    NDI Tools

    • A new NDI Router tool for macOS has been released.

    hashtag
    NDI Tools - HDR

    • NDI Test Patterns now supports HDR patterns (macOS and Windows).

    • NDI Studio Monitor now supports displaying HDR content in PQ and HLG (Windows).

    • NDI Studio Monitor (Windows) has been enhanced to capture NDI HDR streams.

    • has received 10-bit HEVC transcoding and HDR pass-through.

    • has received support for HDR screens and 10-bit HEVC.

    • in Frame Checker mode will now output HDR color information if present.

    hashtag
    NDI Tools - More

    • NDI Video Monitor (macOS) now includes new KVM support.

    • The NDI Launcher app adds a one-click link to extensive online Docs & Guides.

    hashtag
    NDI Tools - Fixes

    • Reduced latency from NDI Screen Capture HX (Windows).

    • Resolved NDI Bridge Local mode issue when handling a source that has multiple machine names.

    • NDI Bridge has been enhanced to leverage the increased number of encoders supported by NVIDIA GeForce cards (may require NVIDIA driver update).

    • Resolved an audio driver stability issue.

    Premiere Pro
    NDI Webcam
    NDI Discovery app
    NDI Webcam
    NDI Router
    Discovery UI
    NDI Bridge
    NDI Studio Monito
    Adobe Premiere
    NDI Bridge
    NDI Remote
    here arrow-up-right
    NDI Bridge
    NDI Bridge
    NDI Bridge
    Free Audio
    Reliable UDP protocol
    NDI Bridge
    NDI Bridge
    NDI Remote
    NDI Studio Monitor
    NDI Studio Monitor
    NDI Webcam
    NDI Remote
    NDI output plugin for Final Cut Pro
    NDI Video Monitor
    NDI Bridge Utility
    NDI Recorder utility
    NDI Bridge
    NDI Screen Capture HX (Windows)
    NDI Analysis
    NDI Webcam

    NDI Sender Listener

    The NDIlib_send_listener_create function creates an instance of the sender listener. This function returns an instance of type NDIlib_send_listener_instance_t (or NULL if it fails), representing the sender listener instance. The parameters of the structure NDIlib_send_listener_instance_t are documented below.

    Parameter
    Description

    p_url_address (const char*)

    Once the structure is filled out, NDIlib_send_listener_create will create an instance for you. The sender listener instance can be destroyed by passing it into the NDIlib_send_listener_destroy function.

    Key Functions:

    hashtag
    Check Listener Connection Status

    To check if the sender listener is actively connected to the configured NDI Discovery server, call the following function:

    bool NDIlib_send_listener_is_connected(NDIlib_send_listener_instance_t p_instance);

    This function returns true if connected, otherwise false.

    hashtag
    Retrieve Server URL

    To retrieve the URL address of the NDI Discovery server that the sender listener is connected to, call:

    const char* NDIlib_send_listener_get_server_url(NDIlib_recv_listener_instance_t p_instance);

    This function returns NULL if the sender instance pointer is invalid.

    hashtag
    Wait for Senders

    To wait until the set of online senders has changed, call

    bool NDIlib_send_listener_wait_for_senders(NDIlib_send_listener_instance_t p_instance, uint32_t timeout_in_ms);

    This function takes a timeout in milliseconds. If a new sender is found or removed before the timeout elapses, the function returns true immediately. If no new senders are seen before the timeout, it returns false.

    Example Code:

    The following code will create an NDI sender listener instance and then retrieves the current list of advertised senders that are registered with the NDI Sender Advertiser API.

    It uses the NDIlib_send_listener_wait_for_senders to sleep until new senders are found and, when they are seen, calls NDIlib_send_listener_get_senders to get the current list of senders:

    The call to NDIlib_send_listener_get_senders will give you a list of the advertised senders. The returned structure NDIlib_sender_t is only valid until the next call to NDIlib_send_listener_get_senders or until NDIlib_send_listener_destroy is called.

    For a given NDIlib_send_listener_instance_t, do not call NDIlib_send_listener_get_senders asynchronously.

    hashtag
    Sender Information Structure

    The structure for NDIlib_sender_t is documented below, which describes a sender that has been discovered.

    Parameters
    Description

    We recommend reviewing the NDI SDK example code (NDIlib_Send_Advertiser and NDIlib_Send_Listener), which provides a simple illustration of how to implement these API’s.

    circle-info

    For monitoring sender events, access to the Advanced SDK APIs is required. Refer to the section for more details.

    Configuration Files

    The NDI configuration settings are stored in JSON files. The location of these files varies per platform and is described in the next section of the manual.

    circle-info

    When using the NDI Advanced SDK, all settings are per instance and so entirely separate settings may be used for every finder, sender, and receiver; this is incredibly powerful by allowing you to specify per sender or receiver which NICs are used, formats are used, what the machine name is, etc...

    Please pay extra attention to the value types, as it is important that these match what is listed here (e.g., true rather than “true”). Also, please note that all these parameters have default values that are the recommended best configuration for most machines; we only suggest you change these values if there is a very specific need for your installation.

    port (int)

    The port number of the sender

    p_groups (const char**)

    An array of strings, one for each group that the sender belongs to. The last entry in this list will be NULL.

    num_groups (uint32_t)

    How many elements are in the p_groups array, excluding the NULL terminating entry.

    events_subscribed (bool)

    Indicates whether the sender is currently subscribed to receiving events.

    This parameter represents the URL address of the NDI Discovery Server to connect to. If NULL, the default NDI discovery server will be used. If no discovery server is available, the sender listener will not be instantiated, and the create function will return NULL. The format of this field is expected to be the hostname or IP address, optionally followed by a colon and a port number. If the port number is not specified, port 5959 will be used.

    For example: 127.0.0.1:5959, 127.0.0.1, or hostname:5959. If this field is a comma-separated list, only the first address will be used.

    p_uuid (const char*)

    The unique identifier for the sender on the network.

    p_name (const char*)

    The human-readable name of the sender.

    p_metadata(const char*)

    Source metadata for the sender

    p_address (const char*)

    Advanced SDK

    The known IP address of the sender.

    // Create the descriptor of the object to create
    NDIlib_send_listener_create_t sender_listener_create;
     
    // The URL address of the discovery server to connect to
    sender_listener_create.p_url_address = "127.0.0.1";
     
    // Create an instance of the sender listener
    NDIlib_send_listener_instance_t pNDI_send_listener = NDIlib_send_listener_create(&sender_listener_create);
    if (!pNDI_send_listener) {
        return 0; // Handle error
    }
     
    // To remember the last connected state
    bool last_connected = false;
     
    while (true) { // You would not loop forever in a real application!
        // Check if the sender listener is currently connected
        bool curr_connected = NDIlib_send_listener_is_connected(pNDI_send_listener);
     
        // Has the connection state changed?
        if (last_connected != curr_connected) {
            printf("The listener is now %s.\n", curr_connected ? "connected" : "disconnected");
            last_connected = curr_connected;
        }
     
        // Wait up to 5 seconds to check for new senders
        if (!NDIlib_send_listener_wait_for_senders(pNDI_send_listener, 5000)) {
            // No new senders added
            printf("No change to the senders found.\n");
    }
    else
    {
            // Get the updated list of senders
            uint32_t num_senders = 0;
            const NDIlib_sender_t* p_senders = NDIlib_send_listener_get_senders(pNDI_send_listener, &num_senders);
     
            // Display all of the found senders
            printf("Network senders (%u found).\n", num_senders);
            for (uint32_t i = 0; i != num_senders; i++) {
                printf("%u. %s\n", i + 1, p_senders[i].p_name);
            }
        }
    }
     
    // Destroy the sender listener
    NDIlib_send_listener_destroy(pNDI_send_listener);

    The following is example of a JSON configuration file that illustrates the parent/child relationship between the hierarchy of objects. Some of these settings such as vendor are only relevant to the Advanced SDK.

    NDI-Recv Discovery, Monitor, and Control

    Updated as of Version 6.2

    hashtag
    Introduction

    With NDI 6.2, the NDI SDK introduces a comprehensive set of APIs that enable the registration of NDI receivers for discovery, monitoring, and control when configured with the NDI Discovery Server. Previously, the NDI Discovery Server was solely responsible for NDI source discovery, detecting sources across the network. However, with this update, the discovery server's functionality has been extended to also support NDI receiver advertisement and discovery, allowing for advanced monitoring and control of NDI receivers. We have ensured the new Discovery Server is backward compatible with existing NDI sources. However, to fully utilize the new NDI receiver discovery, monitoring, and control features, you will need to use NDI 6.2.

    hashtag
    The NDI SDK now includes two additional header files:

    Processing.NDI.RecvAdvertiser.h – Provides the API for advertising NDI receivers within the Discovery Service, ensuring they can be discovered by other systems.

    Processing.NDI.RecvListener.h – Offers the API for retrieving a list of advertised receivers, enabling the monitoring of receiver events and the control of the sources connected to those receivers.These APIs provide a powerful method for discovering, monitoring, and controlling receivers in real time. The NDI Receiver Advertiser API and NDI Receiver Listener API are both included as part of the Standard SDK.

    For more advanced functionality, the includes additional APIs, such as:

    • Receiver Event Subscription – For monitoring receiver events.

    • Command Requests – For controlling receivers by sending connection or disconnection commands to the sources they are connected to.

    The full details of the Advanced APIs can be found in the manual under the section "NDI Recv Event Monitoring and Commands."

    hashtag
    NDI RECV Advertiser

    The NDIlib_recv_advertiser_create function creates an instance of the receiver advertiser. This function returns an instance of type NDIlib_recv_advertiser_instance_t (or NULL if it fails), representing the receiver advertiser instance.

    The function takes parameters defined by NDIlib_recv_advertiser_create_t, as follows:

    Parameter
    Description

    Once the structure is filled out, NDIlib_recv_advertiser_create will create an instance for you. The receiver advertiser instance is destroyed by passing it into NDIlib_recv_advertiser_destroy.

    hashtag
    Adding a Receiver for Advertising

    To add your NDI receiver for advertising, call the following function:

    This function adds the receiver to the list of receivers being advertised. It returns false if the receiver has been previously registered.

    Parameters:

    • p_instance: The receiver advertiser instance from the NDIlib_recv_advertiser_create call.

    • p_receiver: An already instantiated NDI receiver instance from the NDIlib_recv_create call.

    hashtag
    Removing a Receiver from Advertising

    To remove the receiver from the list of receivers being advertised, call the corresponding function:

    This function returns false if the receiver was not previously advertised.

    Example Code:

    The following code illustrates how to add/register a receiver and remove it from the advertiser. Note: A full example is provided with the SDK that illustrates registering a receiver for advertisement (we will not reproduce that code here).

    This example demonstrates the creation, registration, and destruction of an NDI receiver and its associated advertiser.

    hashtag
    NDI RECV Listener

    The NDIlib_recv_listener_create function creates an instance of the receiver listener. This function returns an instance of type NDIlib_recv_listener_instance_t (or NULL if it fails), representing the receiver listener instance. The parameters of the structure NDIlib_recv_listener_instance_t are documented below.

    Parameter
    Description

    Once the structure is filled out, NDIlib_recv_listener_create will create an instance for you. The receiver listener instance can be destroyed by passing it into the NDIlib_recv_listener_destroy function.

    hashtag
    Key Functions:

    hashtag
    Check Connection Status

    To check if the receiver listener is actively connected to the configured NDI Discovery server, call the following function:

    bool NDIlib_recv_listener_is_connected(NDIlib_recv_listener_instance_t p_instance);

    This function returns true if connected, otherwise false.

    hashtag
    Retrieve Server URL

    To retrieve the URL address of the NDI Discovery server that the receiver listener is connected to, call:

    const char* NDIlib_recv_listener_get_server_url(NDIlib_recv_listener_instance_t p_instance);

    This function returns NULL if the receiver instance pointer is invalid.

    hashtag
    Wait for Receivers

    To wait until the set of online receivers has changed, call

    bool NDIlib_recv_listener_wait_for_receivers(NDIlib_recv_listener_instance_t p_instance, uint32_t timeout_in_ms);

    This function takes a timeout in milliseconds. If a new receiver is found or removed before the timeout elapses, the function returns true immediately. If no new sources are seen before the timeout, it returns false.

    Example Code:

    The following code will create an NDI receiver listener instance and then retrieves the current list of advertised receivers that are registered with the NDI Receiver Advertiser API.

    It uses the NDIlib_recv_listener_wait_for_receivers to sleep until new receivers are found and, when they are seen, calls NDIlib_recv_listener_get_receivers to get the current list of receivers:

    The call to NDIlib_recv_listener_get_receivers will give you a list of the advertised receivers. The returned structure NDIlib_receiver_t is only valid until the next call to NDIlib_recv_listener_get_receivers or until NDIlib_recv_listener_destroy is called.

    For a given NDIlib_recv_listener_instance_t, do not call NDIlib_recv_listener_get_receivers asynchronously.

    hashtag
    Receiver Information Structure

    The structure for NDIlib_receiver_t is documented below, which describes a receiver that has been discovered.

    Parameters
    Description

    We recommend reviewing the NDI SDK example code (NDIlib_Recv_Advertiser and NDIlib_Recv_Listener), which provides a simple illustration of how to implement these API’s.

    circle-info

    For monitoring receiver events or controlling receivers, access to the Advanced SDK APIs is required. Refer to the section for more details.

    Performance and Implementation

    hashtag
    Upgrading Your Applications

    The libraries (DLLs) for the latest version of NDI should be entirely backward compatible with NDI v4 and, to the degree possible, even earlier versions. In many cases, you should be able to simply update these in your application to get most of the benefits of the new version – without a single code change.

    circle-info

    {
      "ndi": {
        "vendor": {
          "name": "SKU LAST 4, Customer name first4,dateofissuance 6digits mmddyy",
          "id": "Generated License"
        },
        "machinename": "MachineName",
        "send": {
          "metadata": "<My very cool source/>"
        },
        "networks": {
          "ips": "192.168.1.92,",
          "discovery": "65.52.14.139,65.52.14.138"
        },
        "groups": {
          "send": "Public",
          "recv": "Public"
        },
        "sourcefilter": {
          "regex": "MACHINE .*"
        },
        "adapters": {
          "allowed": [
            "10.28.2.10",
            "10.28.2.11"
          ]
        },
        "tcp": {
          "recv": {
            "enable": true
          }
        },
        "rudp": {
          "recv": {
            "enable": true
          }
        },
        "unicast": {
          "recv": {
            "enable": true
          }
        },
        "multicast": {
          "send": {
            "ttl": 1,
            "enable": false,
            "netmask": "255.255.0.0",
            "netprefix": "239.255.0.0"
          }
        },
        "codec": {
          "shq": {
            "quality": 100,
            "mode": "auto"
          }
        },
        "bridge": {
          "host": true,
          "join": false,
          "address": "127.0.0.1",
          "port": 5990,
          "secure": "123abc",
          "ntk": true,
          "reflect": true,
          "srcgroups": "0ca7b4fd-4bbe-41d8-b263-b8cbeec1188c",
          "bufferdelay": 0,
          "diag": "info",
          "id": "NiceCamera"
        }
      }
    }
    
    
    Note: There are several exceptions to the statement above, however. If you have software that was built before NDI 4.5 on macOS and Linux applications, you will need to recompile your applications; this change was made because the size of some struct members changed.

    hashtag
    General Recommendations

    • Throughout the system, use YCbCr color, if possible, as it offers both higher performance and better quality.

    • If your system has more than one NIC and you are using more than a few senders and receivers, it is worth connecting all available ports to the network. Bandwidth will be distributed across multiple network adapters.

    • Use the latest version of the SDK whenever possible. Naturally, the experience of huge numbers of NDI users in the field provides numerous minor edge cases, and we work hard to resolve all of these as quickly as possible.

    • We also have ambitious plans for the future of NDI and IP video, and we are continually laying the groundwork for these in each new version so that these will already be in place when the related enhancements become available for public use.

    • The SDK is designed to take advantage of the latest CPU instructions available, particularly AVX2 (256-bit instructions) on Intel platforms and NEON instructions on ARM platforms. Generally, NDI speed limitations relate more to system memory bandwidth than CPU processing performance since the code is designed to keep all execution pipelines on a CPU busy.

    • NDI takes advantage of multiple CPU cores when decoding and encoding one or more streams and, for higher resolutions, will use multiple cores to decode a single stream.

    hashtag
    Sending Video

    • Use UYVY or UYVA color, if possible, as this avoids internal color conversions. If you cannot generate these color formats and you would use the CPU to perform the conversion, it is better to let the SDK perform the conversion.

    • Doing so yields performance benefits in most cases, particularly when using asynchronous frame submission. If the data that you are sending to NDI is on the GPU, and you can have the GPU perform the color conversion before downloading it to system memory, you are likely to find that this has the best performance.

    • Sending BGRA or BGRX video will incur a performance penalty. This is caused by the increased memory bandwidth required for these formats and the conversion to YCbCr color space for compression. With that said, performance was significantly improved in NDI 4.

    • Using asynchronous frame submission almost always yields significant performance benefits.

    hashtag
    Receiving Video

    • Using NDIlib_recv_color_format_fastest for receiving will yield the best performance.

    • Having separate threads query for audio and video via NDIlib_recv_capture_v3 is recommended.

    circle-info

    Note that NDIlib_recv_capture_v3 is multi-thread safe, allowing multiple threads to be waiting for data at once. Using a reasonable timeout on NDIlib_recv_capture_v3 is better and more efficient than polling it with zero time-outs.

    • In the modern versions of NDI, there are internal heuristics that attempt to guess whether hardware acceleration would enable better performance. That said, it is possible to explicitly enable hardware acceleration if you believe that it would be beneficial for your application. This can be enabled by sending an XML metadata message to a receiver as follows:

    <ndi_video_codec type="hardware"/>

    • Bear in mind that decoding resources on some machines are designed for processing a single video stream. In consequence, while hardware assistance might benefit some small number of streams, it may hurt performance as the number of streams increases.

    • Modern versions of NDI almost certainly already default to using hardware acceleration in most situations where it would be beneficial, and so these settings are not likely to make a significant improvement. In earlier versions, concerns around hardware codec driver stability made us less likely to enable these by default, but we believe that this caution is no longer needed.

    hashtag
    Reliable UDP with Multi-stream Congestion Control

    In NDI 5, the default communication mechanism is a reliable UDP protocol that represents the state-of-the-art communication protocol that is implemented by building upon all the experience we have seen in the real world with NDI across a massive variety of different installations. By using UDP, it does not rely on any direct round-trip, congestion control, or flow control issues that are typically associated with TCP. Most importantly, our observation has been that on real-world networks, as you approach the total bandwidth available across many different channels of video, the management of the network of bandwidth becomes the most common problem. Our reliable UDP solves this by moving all streams between sources into a single connection across which the congestion control is applied in aggregate to all streams at once, which represents a massive improvement in almost all installations. These streams are all entirely non-blocking with each other so that even under high packet loss situations, there is no possibility of a particular loss impacting any other portions of the connection.

    One of the biggest problems with UDP packet sending is the need to send many small packets onto the network, which results in a very large OS kernel overhead. Our implementation works around this by supporting fully asynchronous sending of many packets at once and supporting packet coalescing on the receiving side to allow the kernel and network card driver to offload a huge fraction of the processing.

    This protocol also supports high network latencies by having the current best congestion control systems published. This allows many packets to be in flight at a time and very accurately tracks which packets have been received and adjusts the number to the currently measured round-trip time.

    On Windows, where this is supported, receiver-side scaling is used to achieve very optimized network receiving that ensures that, as the network card interrupts are received, they are always handed off directly to a thread that has an execution context available (which are then directly passed into the NDI processing chain).

    For the absolute best performance, reliable UDP supports UDP Segmentation Offload (USO), which allows network interface cards to offload the segmentation of UDP datagrams that are larger than the maximum transmission unit (MTU) of the network medium, which can significantly reduce CPU usage.

    On Linux, to get the best performance, we need to take advantage of Generic Segmentation Offload (GSO) for UDP sending, which might also be referred to as UDP_SEGMENT, which was made available in Linux Kernel 4.18. Without this, UDP sending can see significantly increased CPU overhead.

    hashtag
    Multicast

    NDI supports multicast-based video sources using multicast UDP with forward error correction to correct for packet loss.

    It is important to be aware that using multicast on a network that is not configured correctly is very similar to a “denial of service” attack on the entire network; for this reason, multicast sending is disabled by default.

    Every router that we have tested has treated multicast traffic as if it was broadcast traffic by default. Because most multicast traffic on a network is low bandwidth, this is of little consequence, and generally allows a network router to run more efficiently because no packet filtering is required.

    What this means, though, is that every multicast packet received is sent to every destination on the network, regardless of whether it was needed there or not. Because NDI requires high bandwidth multicast, even with a limited number of sources on a large network, the burden of sending this much data to all network sources can cripple the entire network’s performance.

    To avoid this serious problem, it is essential to ensure that every router on the network has proper multicast filtering enabled. This option is most referred to as “IGMP snooping”. If you are unable to find a way to enable this option, we recommend that you use multicast NDI with all due caution.

    hashtag
    Debugging with Multicast

    Another important cautionary note is that a software application like NDI will subscribe to a multicast group and will unsubscribe from it when it no longer needs that group.

    Unlike most operations in the operating system, the un-subscription step is not automated by the OS; once you are subscribed to a group, your computer will continue to receive data until the router sends an IGMP query to verify whether it is still needed. This happens about every 5 minutes on typical networks.

    The result is that if you launch an NDI multicast stream and kill your application without closing the NDI connection correctly, your computer will continue to receive the data from the network until this timeout expires.

    NDI Sender Discovery & Monitor

    NDI 6.3 expands the NDI SDK by introducing APIs for registering NDI senders, mirroring the functionality already available for receivers (added in version 6.2). These APIs enable sender discovery and monitoring when used with the NDI Discovery Server. This new method does not break compatibility with the original sender advertising system (which we refer to as legacy senders advertisement); both will coexist. The key advantage of the new source advertisers is that they allow a listener to monitor most of their events and properties, a capability unavailable with the legacy method.

    The NDI SDK now includes two additional header files:

    • Processing.NDI.SendAdvertiser.h – Provides the API for advertising NDI senders within the Discovery Service, ensuring they can be discovered by other systems.

    • Processing.NDI.SendListener.h – Offers the API for retrieving a list of advertised senders, enabling the monitoring of sender events.

    These APIs provide a powerful method for discovering, monitoring senders in real time. The NDI Sender Advertiser API and NDI Sender Listener API are both included as part of the Standard SDK.

    For more advanced functionality, the Advanced SDK includes additional APIs, such as:

    • Sender Event Subscription – For monitoring sender events.

    The full details of the Advanced APIs can be found in the manual under the section NDI Sender Event Monitoring

    allow_controlling: A flag to allow controlling of the receiver.
  • allow_monitoring: A flag to allow monitoring of the receiver.

  • p_input_group_name: An optional input group name for the receiver. This can be used to associate two separate receivers (e.g., a video receiver and an audio receiver) with a common input name.

  • p_address (const char*)

    The known IP address of the receiver.

    p_streams (NDIlib_receiver_type_e*)

    An array of streams that the receiver can receive from the source it's connected to. The last entry is NDIlib_receiver_type_none. Supported types: NDIlib_receiver_type_metadata, NDIlib_receiver_type_video, NDIlib_rec eiver_type_audio, NDIlib_receiver_type_none.

    num_streams (uint32_t)

    The number of elements in the p_streams array, excluding the NDIlib_receiver_type_none entry

    p_commands (NDIlib_receiv er_command_e*)

    An array of commands that the receiver can process. The last entry is NDIlib_receiver_command_none. Supported commands: NDIlib_receiver_command_connect, NDIlib_receiver_command_none.

    num_commands (uint32_t)

    The number of elements in the p_commands array, excluding the NDIlib_receiver_command_none entry.

    events_subscribed (bool)

    Indicates whether the receiver is currently subscribed to receiving events.

    p_url_address (const char*)

    This parameter represents the URL address of the NDI Discovery Server to connect to. If NULL, the default NDI discovery server will be used. If no discovery server is available, the receiver advertiser will not be instantiated, and the create function will return NULL. The format of this field is expected to be the hostname or IP address, optionally followed by a colon and a port number. If the port number is not specified, port 5959 will be used.

    For example: 127.0.0.1:5959, 127.0.0.1, or hostname:5959. This field can also specify multiple addresses separated by commas for redundancy support.

    p_url_address (const char*)

    This parameter represents the URL address of the NDI Discovery Server to connect to. If NULL, the default NDI discovery server will be used. If no discovery server is available, the receiver listener will not be instantiated, and the create function will return NULL. The format of this field is expected to be the hostname or IP address, optionally followed by a colon and a port number. If the port number is not specified, port 5959 will be used.

    For example: 127.0.0.1:5959, 127.0.0.1, or hostname:5959. If this field is a comma-separated list, only the first address will be used.

    p_uuid (const char*)

    The unique identifier for the receiver on the network.

    p_name (const char*)

    The human-readable name of the receiver.

    p_input_uuid (const char*)

    The unique identifier for the input group that the receiver belongs to.

    p_input_name (const char*)

    Advanced SDK
    Advanced SDK

    The human-readable name of the input group that the receiver belongs to.

    This is an option that allows you to change how your machine is identified on the network using NDI, overriding the local name of the machine. This option should be used with great care since a clash of machine names on the network is incompatible with mDNS and can cause all other sources not to work correctly. When using this, it is essential to ensure that all machine names on the network are unique. We recommend avoiding using this parameter when at all possible.

    In NDI 5, it is possible to specify metadata for the current source when creating an NDI sender with the Advanced SDK. When using the NDI finder, it is then possible to receive this metadata in order to receive any number of properties about the source. Please note that you should always make your meta-data in XML format and be careful to escape it correctly when adding it to the JSON configuration file.

    These are extra IP addresses for machines from which you wish to discover NDI sources. Each local machine runs a service on port 5960, which is then connected to the machine this configuration is run on. This allows sources to be discovered on those IP addresses without needing mDNS to discover it. Hint: When a Discovery server is used, receivers combine the list of sources found on the discovery server with those discovered via mDNS. Senders, however, will avoid using mDNS when a discovery server is configured, allowing you to run entirely without network multicast if you desire. Starting in NDI 5, it is possible to use a comma-delimited list of discovery servers for full support for redundancy. For more information, please review the section of the manual regarding the discovery server.

    The discovery server list may include port numbers. If you do not list the port numbers, the default port of 5959 will be used.

    This is the list of groups that the senders on this system are going to be part of by default. If groups are not specified, senders will be part of the public group by default.

    In NDI 5, there is the ability to specify a regular expression that will be used to filter further the set of sources that will be visible to NDI finders. This is an advanced option that allows you to specify exactly which sources are going to be visible to the local machine. If your regular expression is not valid, then it will not be applied.

    Starting in NDI version 5, this lists all the network adapters that will be used for network transmission. One or more NICs can be used for the transmission and receiving of video and audio data. This capability can be used to ensure that the NDI primary stream data remains on a group of network adapters, allowing you to ensure that dedicated audio is on a separate network card from the NDI video.

    It is generally preferred that you let NDI select the network adapters automatically, as it can smartly select which to use and how to choose the ones that result in the best bandwidth. While in some modes, NDI can automatically balance bandwidth across multiple NICs, it is normally better for you to use NIC teaming at a machine configuration level which can result in much better performance than what is possible in software.

    If this setting is configured incorrectly to specify NICs that might not exist, then NDI might fail to function correctly. Also please note that the operation of computer systems that are separately on entirely different networks with different IP address ranges is often not handled robustly by the operating system, and NDI might not fully function in these configurations.

    The following connections are available in NDI version 5 and allow the force enabling and disabling of the reliable UDP mode, which is the default connection type on NDI version 5 and later. The full details of this connection type are described in the section for “Performance and Implementations” section of this manual.

    There are separate settings for sending and receiving. Both sides need to allow this mode to be applied; sources and receivers have it enabled by default.

    This is the default connection type and represents the preferred type for most network configurations, and we recommend its use where possible.

    These settings enable or disable the use of multicast for receiving. If you explicitly disable it on a machine then, even if the sender is configured for multicast, it will use unicast. When multicast receiving is enabled, and a sender is available in the same local network, the receiver can negotiate for a multicast stream to be sent. If the sender is not on the same local network, this negotiation does not occur (since it could lead to a multicast stream being sent but never able to arrive at the receiver). If you have a correctly configured network and can ensure a multicast stream can route reliably from a different network to the receiver’s local network, you can specify the sender’s subnet in the “subnets” setting to allow multicast negotiation to occur. These settings pertain to the multicast NDI setting on this machine. The first setting determines whether multicast sending is enabled or not. By default, multicast sending is disabled. Next is the IP address prefix and mask. In this example, multicast IP addresses will be chosen in the range 239.255.0.0 - 239.255.255.255. NDI will attempt to use different multicast addresses to ensure that the streams can be filtered efficiently by the network adapter. NDI senders need a range of multicast addresses available. The TTL value controls how many “hops” the multicast sending traffic will take, allowing it to move outside of the local network. There are separate settings for sending and receiving. Both sides need to allow this mode to be applied; sources and receivers have it enabled by default.

    We generally discourage the use of Multicast since configuration and ensuring that high performance is achieved is very difficult at a network level; in most cases, the default protocols (particularly reliable UDP) perform much better.

    These settings enable or disable multi-TCP sending or receiving. If multi-TCP is disabled, then unicast UDP will be used. If unicast UDP is also disabled, then the base TCP connection will be used.

    There are separate settings for sending and receiving. Both sides need to allow this mode to be applied; sources and receivers have it enabled by default.

    Multi-TCP is not the default mode in NDI 5, which performs better with Reliable UDP.

    These settings enable or disable unicast UDP sending or receiving. If unicast UDP is disabled, then the base TCP connection will be used.

    Unicast settings determine whether UDP with forwards- error correction is used for sending. While configurable, we recommended that this be enabled by default and not changed. Our experience has been that our UDP implementation handles poor networks and packet loss more robustly than TCP/IP, which can encounter timeout problems when acknowledgment packets are dropped (while rare, this can happen over a period of hours).

    The UDP implementation also fully implements paced network sending with zero memory copy scatter-gather lists and jittered timing to reduce the chance of packet loss on networks with many synchronized video streams. By default, 4Kb UDP packets are used, although jumbo packets do not need to be enabled on the network.

    All versions of NDI fall to TCP/IP if a particular protocol is not supported by both sides. Again, note that that a sender implementation can simultaneously send internally in multiple modes based on what receivers require.

    There are separate UDP unicast settings for sending and receiving. Both sides need to allow this for UDP mode to be applied; sources and receivers have it enabled by default.

    Unicast UDP is not the default mode in NDI 5, which performs better with Reliable UDP.

    These settings are only available in the NDI Advanced SDK and allow you to override the default codec quality settings of NDI. The “quality” setting is a percentage scale to apply to the bit-rate control; for instance, a value of 200 would mean that NDI targets a bitrate that is double the NDI default. Be careful when specifying high bitrates because the CPU usage required for compression and decompression might increase, and the strain on the network and the OS networking stack is correspondingly increased. Once the bitrate hits a maximum level for a particular media type (e.g., the codec q value becomes the maximum), then increasing it further might have no impact. The “mode” allows you to force NDI into a particular color mode. The default is “auto,” which uses heuristics to best allocate bits between the luminance and chroma fields. You may specify “4:2:2” or “4:2:0” here to force the codec into a particular chroma-subsampling mode. Please note that often forcing it into a particular mode will cause the codec to be less high quality than letting the codec choose the bit allocation that results in the best PSNR.

    bool NDIlib_recv_advertiser_add_receiver( 
        NDIlib_recv_advertiser_instance_t p_instance, 
        NDIlib_recv_instance_t p_receiver,
        bool allow_controlling, bool allow_monitoring,
        const char* p_input_group_name NDILIB_CPP_DEFAULT_VALUE(NULL)
    );
    bool NDIlib_recv_advertiser_del_receiver( 
        NDIlib_recv_advertiser_instance_t p_instance, 
        NDIlib_recv_instance_t p_receiver
    );
    // Create an unconnected receiver that will be set up for advertising. NDIlib_recv_instance_t pNDI_recv = NDIlib_recv_create_v3();
    if (!pNDI_recv) {
     // Handle error
    }
     
    // Create an instance of the receiver advertiser
    NDIlib_recv_advertiser_instance_t pNDI_recv_advertiser = NDIlib_recv_advertiser_create(); 
    if (!pNDI_recv_advertiser) {
     // Handle error
    }
     
    // Register the receiver with the advertiser
    NDIlib_recv_advertiser_add_receiver(pNDI_recv_advertiser, pNDI_recv, true, true);
     
    // Do stuff
    ...
     
    // Remove the receiver from the advertiser before destroying it
    NDIlib_recv_advertiser_del_receiver(pNDI_recv_advertiser, pNDI_recv);
     
    // Destroy the receiver advertiser NDIlib_recv_advertiser_destroy(pNDI_recv_advertiser);
     
    // Destroy the receiver NDIlib_recv_destroy(pNDI_recv);
    // Create the descriptor of the object to create 
    NDIlib_recv_listener_create_t listener_create;
     
    // The URL address of the discovery server to connect to 
    listener_create.p_url_address = "127.0.0.1";
     
    // Create an instance of the receiver listener
    
    NDIlib_recv_listener_instance_t pNDI_recv_listener = NDIlib_recv_listener_create(&listener_create);
    if (!pNDI_recv_listener) { return 0; // Handle error
    }
     
    // To remember the last connected state 
    bool last_connected = false;
     
    while (true) { // You would not loop forever in a real application!
     // Check if the listener is currently connected
     bool curr_connected = NDIlib_recv_listener_is_connected(pNDI_recv_listener);
     
     // Has the connection state changed?
     if (last_connected != curr_connected) {
      printf("The listener is now %s.\n", curr_connected ? "connected" : "disconnected");
      last_connected = curr_connected;
    }
     
    // Wait up to 5 seconds to check for new receivers
    if (!NDIlib_recv_listener_wait_for_receivers(pNDI_recv_listener, 5000)) {
      // No new receivers added
      printf("No change to the receivers found.\n");
    }
    else
    {
      // Get the updated list of receivers
      uint32_t num_receivers = 0;
      const NDIlib_receiver_t* p_receivers =
    NDIlib_recv_listener_get_receivers(pNDI_recv_listener, &num_receivers);
     
      // Display all of the found receivers
      printf("Network receivers (%u found).\n", num_receivers); 
      for (uint32_t i = 0; i != num_receivers; i++) {
        printf("%u. %s\n", i + 1, p_receivers[i].p_name);
        }
      }
    }
     
    // Destroy the receiver listener NDIlib_recv_listener_destroy(pNDI_recv_listener);
    {
       "ndi": {
          "machinename": "Hello World",
    "send": {
      "metadata": "<My very cool source/>"
    },
    "networks": {
      "ips": "192.168.86.32,",
      "discovery": "127.0.0.1,127.0.0.1"
    },
    "groups": {
      "send": "Public",
      "recv": "Public"
    },
    "sourcefilter": {
      "regex": "MACHINE .*"
    },
    "adapters": {
     "allowed": ["10.28.2.10","10.28.2.11"]
    },
    "rudp": {
      "send": {
        "enable": true
      }, 
      "recv": {
        "enable": true
      }
    },
    "multicast": {
      "send": {
        "ttl": 1,
        "enable": false,
        "netmask": "255.255.0.0",
        "netprefix": "239.255.0.0"
      },
      "recv": {
        "enable": true
      } 
    },
    "tcp": {
      "send": {
        "enable": false
      }, 
      "recv": {
        "enable": false
      }
    },
    "unicast": {
      "send": {
        "enable": false
      },
      "recv": {
        "enable": false
      }
    },
    "codec": {
          "shq": {
            "quality": 100,
            "mode": "auto"
          }
        }, 
      }
    }

    Command Line Tools

    hashtag
    Recording

    A full cross-platform native NDI recording is provided in the SDK. This is provided as a command-line application in order to allow it to be integrated into both end-user applications and scripted environments. All input and output from this application is provided over stdin and stdout, allowing you to read and/or write to these in order to control the recorder.

    The NDI recording application implements most of the complex components of file recording and may be included in your applications under the SDK license. The functionality provided by the NDI recorder is as follows:

    • Record any NDI source. For full-bandwidth NDI sources, no video recompression is performed. The stream is taken from the network and simply stored on disk, meaning that a single machine will take almost no CPU usage in order to record streams. File writing uses asynchronous block file writing, which should mean that the only limitation on the number of recorded channels is the bandwidth of your disk sub-system and the efficiency of the system network and disk device drivers.

    • All sources are synchronized. The recorder will time-base correct all recordings to lock to the current system clock. This is designed so that if you are recording a large number of NDI sources, the resulting files are entirely synchronized with each other. Because the files are written with timecode, they may then be used in a nonlinear editor without any additional work required for multi-angle or multi-source synchronization.

    Recording is implemented as a stand-alone executable, which allows it either to be used in your own scripting environments (both locally and remotely), or called from an application. The application is designed to take commands in a structured form from stdin and put feedback out onto stdout.

    hashtag
    Command Line Arguments

    The primary use of the application would be to run it and specify the NDI source name and the destination file- name. For instance, if you wished to record a source called My Machine (Source 1) into a file C:\Temp\A.mov. The command line to record this would be:

    "NDI Record.exe" –I "My Machine (Source 1)" –o "C:\Temp\A.mov"

    This would then start recording when this source has first provided audio and video (both are required in order to determine the format needed in the file). Additional command line options are listed below:

    Command Line Option
    Description

    Once running, the application can be interacted with by taking input on stdin, and will provide response onto stdout. These are outlined below.

    If you wish to quit the application, the preferred mechanism is described in the input settings section. However, one may also press CTRL+C to signal an exit, and the file will be correctly closed. If you kill the recorder process while it is running, the resulting file will be invalid since QuickTime files require an index at the end of the file. The Windows version of the application will also monitor its launching parent process; if that should exit, it will correctly close the file and exit.

    hashtag
    Input Settings

    While this application is running, a number of commands can be sent to stdin. These are all in XML format and can control the current recording settings. These are outlined as follows.

    Command Line Option
    Description

    hashtag
    Output Settings

    Output from NDI recording is provided onto stdout. The application will place all non-output settings onto stderr , allowing a listening application to distinguish between feedback and notification messages. For example, in the run log below, different colors are used to highlight what is placed on stderr (blue) and stdout (green).

    Once recording starts, it will put out an XML message specifying the filename for the recording and provide you with the framerate.

    It then gives you the timecode for each recorded frame and the current audio level in decibels (if the audio is silent, then the dB level will be -inf). If a recording stops, it will give you the final timecode written into the file. Timecodes are specified as UTC time since the Unix Epoch (1/1/1970 00:00) with 100 ns precision.

    hashtag
    Error Handling

    A number of different events can cause recording errors. The most common is when the drive system that you are recording to is too slow to record the video data being stored on it, or the seek times to write multiple streams end up dominating the performance (note that we do use block writers to avoid this as much as possible).

    The recorder is designed to never drop frames in a file; however, when it cannot write to disk sufficiently fast, it will internally “buffer” the compressed video until it has fallen about two seconds behind what can be written to disk. Thus, temporary disk or connection performance issues do not damage the recording.

    Once a true error is detected, it will issue a record-error command as follows:

    [14:20:24.344]: <record_error error="The error message goes here."/>

    If the option for autochop is enabled, the recorder will start attempting to write a new file. This process ensures that each file always has all frames without drops, but if data needs to be dropped because of insufficient disk performance, that data will be missing between files.

    hashtag
    Discovery Service

    In modern networked media workflows, efficient discovery and management of NDI audio and video sources are critical. The NDI Discovery Service is a dedicated server and protocol designed to replace automatic mDNS-based discovery with a centralized registry for NDI sources and receivers. This approach is particularly beneficial in environments where reducing network traffic is essential or where multicast is not possible or desirable.

    circle-info

    It is very common that cloud computing services do not allow multicast traffic.

    The Discovery Service can operate as a remote server-based service or a local application, accepting connections from senders, finders, and receivers. It facilitates seamless device visibility, real-time status updates, and low-latency connections with minimal configuration. NDI 6.2 expands the functionality of the Discovery Service beyond simple source advertising and listing, introducing new capabilities for discovery, monitoring, and control of NDI receivers, enhancing real-time interaction and management.

    To support seamless integration with third-party applications, the NDI SDK provides a new set of APIs that allow developers to directly interact with the Discovery Service. These APIs enable querying available sources, subscribing to real-time updates, and efficiently managing connections, ensuring broad interoperability across diverse applications and workflows.

    The full details of these APIs can be found in the manual under the section .

    By offering a robust alternative to mDNS, the NDI Discovery Service significantly reduces network traffic while maintaining full support for essential NDI features, including NDI Groups.

    hashtag
    Server

    The NDI Discovery Service can be deployed either as an application by running Bin\Utilities\x64\NDI Discovery Service.exe or as a system service named NDI Discovery Service, offering flexibility for diverse deployment scenarios across different platforms. Both 32-bit and 64-bit versions are available, with the 64-bit version recommended for optimal performance. While the service uses minimal CPU resources, it may require additional RAM and generate network traffic when managing a large number of connections, such as sources, receiver listeners, and receiver advertisers, to effectively coordinate and update source lists.

    The NDI Discovery Service is also available as a standalone installer for both Windows and Linux. You can download the respective installers by visiting the website.

    hashtag
    Clients

    Clients should be configured to connect with the discovery server instead of using mDNS to locate sources. When there is a discovery server, the SDK will use both mDNS and the discovery server for finding and receiving to locate sources on the local network that are not on machines configured to use discovery.

    For senders, if a discovery service is specified, that mDNS will not be used; these sources will only be visible to other finders and receivers that are configured to use the discovery server.

    hashtag
    Configuration

    To configure the discovery server for NDI clients, you can use Access Manager (included in the ) to enter the IP address of the discovery server machine or utilize the NDI Discovery tool, both of which are included in the NDI Tools bundle. The NDI Discovery tool is a new addition to the NDI Tools suite and is available on both Windows and macOS platforms.

    hashtag
    Command Line Options

    hashtag
    Usage:

    "NDI Discovery Service.exe" -bind <ip-address> -port <port_number> -config <json path> - help

    It is possible to run the Discovery server with a command line option that specifies which NIC is operating from with:

    DiscoveryServer.exe -bind 192.168.1.100

    This will ask the discovery server to only advertise on the IP address specified. Likewise, it is possible to specify a port number that will be used for the discovery server using:

    DiscoveryServer.exe -port 5400

    This allows you to work on a non-default port number or run multiple discovery servers for multiple groups of sources on a single machine. If a port of 0 is specified, then a port number is selected by the operating system and will be displayed at run-time.

    circle-check

    It is, of course, recommended that you have a static IP address so that any clients configured to access it will not lose connections if the IP is dynamically re-assigned.

    hashtag
    General Options (Windows & Linux):

    • -bind <ip_address> : This is an optional argument that specifies the IP address to bind the service to (default: 0.0.0.0).

    • -port <port_number> : This is an optional argument that sets the port number (default: 5959).

    • -config <json path> : This is an optional argument that loads configuration from a JSON file. This option will override both -bind and -port options as it will take precedence

    hashtag
    Linux/Unix-Specific Option

    • -service : This will run the NDI Discovery in service mode for background execution.

    hashtag
    JSON configuration file:

    The default paths for the configuration file are:

    • Linux:

      • /etc/ndi/ndi-discovery-service.v1.json

      • /usr/local/etc/ndi/ndi-discovery-service.v1.json

    An example of the JSON configuration file can be seen below:

    hashtag
    Running as a service

    On Windows, you can register and manage the NDI Discovery Service as a Windows service using the following command-line options:

    • “NDI Discovery Service.exe” install : Installs or reinstalls the service.

    • “NDI Discovery Sevice.exe” remove : Uninstalls the service.

    • “NDI Discovery Service.exe” start : Starts the service.

    These commands should be executed from the command prompt with administrative privileges to properly install, start, or remove the service.

    On Linux, to run the NDI Discovery Service as a service, you can utilize systemd or init.d for management. The standalone version of the Discovery server for Linux includes template scripts along with comprehensive documentation. After configuring the scripts, you can launch the NDI Discovery Service in service mode using the following command-line options.

    • “NDI Discovery Service.exe” -service : Runs the NDI Discovery in service mode for background execution.

    hashtag
    NDI Benchmark

    To help gauge your machine performance for NDI, a tool is provided that will initiate one NDI stream per core on your system and measure how many 1080p streams can be decoded in real-time. Note that this number reflects the best-case performance and is designed to exclude any impact of networking and only gauge the system CPU performance.

    This can be used to compare performance across machines, and because NDI is highly optimized on all platforms, it is a good measure of the total CPU performance that is possible when all reasonable opportunity is taken to achieve high performance on a typical system. For instance, on Windows, NDI will use all extended vector instructions (SSSE3 and up, including VEX instructions), while on ARM, it will use NEON instructions when possible.

    Port Numbers

    Each NDI connection will require one more port number. Current versions try for these to be in a predictable port range, although if some of this range is taken by other applications, it might need to use higher numbers. The following table describes the used port numbers, their types, and their purpose.

    It is recommended that you use the connection types that are the default for the current version of NDI since these represent the best recommendations that we have tested and observed to yield the best performance in the field. Earlier versions of NDI might use ports in the ephemeral range, although modern versions of NDI no longer use these to ensure that the port numbers are more predictable and easier to configure in.

    Port Number
    Type
    Use
    NDI Version

    NDI-SEND

    A call to NDIlib_send_create will create an instance of the sender. This will return an instance of the type NDIlib_send_instance_t (or NULL if it fails) representing the sending instance.

    hashtag
    Parameters

    The set of creation parameters applied to the sender is specified by filling out a structure called NDIlib_send_create_t

    5353

    UDP

    This is the standard port used for mDNS communication and is always used for multicast sending of the current sources onto the network.

    NDI 5

    5960 and up

    UDP

    When using reliable UDP connections it will use a very small number of ports in the range of 5960 for UDP. These port numbers are shared with the TCP connections. Because connection sharing is used in this mode, the number of ports required is very limited and only one port is needed per NDI process running and not one port per NDI connection.

    NDI 5

    5960

    TCP

    This is a TCP port used for remote sources to query this machine and discover all the sources running on it. This is used for instance when a machine is added by IP address in the access manager so that from an IP address alone all the sources currently running on that machine can be discovered automatically.

    NDI 5

    5961 and up

    TCP

    These are the base TCP connection used for each NDI stream. For each current connection, at least one port number will be used in this range.

    NDI 4

    6960 and up

    TCP/UDP

    When using multi-TCP or UDP receiving, at least one port number in this range will be used for each connection.

    NDI 4

    7960 and up

    TCP/UDP

    When using multi-TCP, unicast UDP, or multicast UDP sending, at least one port number in this range will be used for each connection.

    NDI 4

    Still better, if you lock the clock between multiple computer systems using NTP, recordings done independently on all computer systems will always be automatically synchronized.
  • The complexities of discontinuous and unlocked sources are handled correctly. The recorder will handle cases in which audio and/or video are discontinuous or not on the same clock. It should correctly provide audio and video synchronization in these cases and adapt correctly even when poor input signals are used.

  • High Performance. Using asynchronous block-based disk writing without any video compression in most cases means that the number of streams written to disk is largely limited only by available network bandwidth and the speed of your drives. On a fast system, even a large number of 4K streams may be recorded to disk!

  • And much more... Having worked with a large number of companies wanting recording capabilities, we realized that providing a reference implementation that handles a lot of the edge cases and problems of recording would be hugely beneficial. Allowing all sources to be synchronized makes NDI a fundamentally more powerful and useful tool for video in all cases.

  • The implementation provided is cross-platform and may be used under the SDK license in commercial and free applications. Note that audio is recorded in floating-point and so is never subject to audio clipping at record time.

  • Optional. Specify whether a proxy file should be written. By default, this option is enabled.

    -noautochop

    Optional. When specified, this specifies that if the video properties change (resolution, framerate, aspect ratio), the existing file is chopped, and a new one starts with a number appended. When false, it will simply exit when the video properties change, allowing you to start it again with a new file name should you want. By default, if the video format changes, it will open a new file in that format without dropping any frames.

    -noautostart

    Optional. This command may be used to achieve frame-accurate recording as needed. When specified, the record application will run and connect to the remote source; however, it will not immediately start recording. It will then start immediately when you send a <start/> message to stdin.

    Enable (or disable) automatic gain control for audio, which will use an expander/compressor to normalize the audio while it is being recorded.

    <record_chop/>

    Immediately stop recording, then restart another file without dropping frames.

    <record_chop filename="another.mov"/>

    Immediately stop recording, and start recording another file in potentially a different location without dropping frames. This allows a recording location to be changed on the fly, allowing you to span recordings across multiple drives or locations.

    -help : Displays available command-line options.
    Windows:
    • C:\ProgramData\NDI\ndi-discovery-service.v1.json

  • “NDI Discovery Service.exe” stop : Stops the service.

  • -i "source-name"

    Required option. The NDI source name to record.

    -o "file-name"

    Required option. The filename you wish to record into. Please note that if the filename already exists, a number will be appended to it to ensure that it is unique.

    -u "url"

    Optional. This is the URL of the NDI source if you wish to have recording start slightly quicker or if the source is not currently visible in the current group or network.

    <start/>

    Start recording at this moment; this is used in conjuction with the “-noautostart” command line.

    <exit/> or <quit/>

    This will cancel recording and exit the moment that the file is completely on disk.

    <record_level gain="1.2"/>

    This allows you to control the current recorded audio levels in decibels. 1.2 would apply 1.2 dB of gain to the audio signal while recording to disk.

    NDI-Recv Discovery, Monitor and Control
    ndi.videoarrow-up-right
    NDI Tools bundle

    -nothumbnail

    <record_agc enabled="true"/>

    NDI Stream Record v1.00
    Copyright (C) 2023 Vizrt NDI AB. All rights reserved.
    
    [14:20:24.138]: <record_started filename="e:\Temp 2.mov" filename_pvw="e:\Temp 2.mov.preview" frame_rate_n="60000" frame_rate_d="1001"/>
    [14:20:24.178]: <recording no_frames="0" timecode="732241356791" vu_dB="-23.999269" start_timecode="732241356791"/>
    [14:20:24.209]: <recording no_frames="0" timecode="732241690457" vu_dB="-26.976938"/> 
    [14:20:24.244]: <recording no_frames="2" timecode="732242024123" vu_dB="-20.638922"/> 
    [14:20:24.277]: <recording no_frames="4" timecode="732242357789" vu_dB="-20.638922"/> 
    [14:20:24.309]: <recording no_frames="7" timecode="732242691455" vu_dB="-17.237122"/> 
    [14:20:24.344]: <recording no_frames="9" timecode="732243025121" vu_dB="-19.268487"/> 
    ...
    [14:20:27.696]: <record_stopped no_frames="229" last_timecode="732273722393"/>
    {
        "binding": "127.0.0.1",
        "port_no": "5959"
    }
    . It is now possible to call
    NDIlib_send_create
    with a NULL parameter, in which case it will use default parameters for all values; the source name is selected using the current executable name, ensuring that there is a count that ensures sender names are unique (e.g. “My Application”, “My Application 2”, etc.)
    Supported Parameters
    Description

    p_ndi_name (const char*)

    This is the name of the NDI source to create. It is a NULL-terminated UTF-8 string. This will be the name of the NDI source on the network.

    For instance, if your network machine name is called “MyMachine” and you specify this parameter as “My Video”, the NDI source on the network would be “MyMachine (My Video)”.

    p_groups (const char*)

    This parameter represents the groups that this NDI sender should place itself into. Groups are sets of NDI sources. Any source can be part of any number of groups, and groups are comma-separated. For instance, "cameras,studio 1,10am show" would place a source in the three groups named.

    On the finding side, you can specify which groups to look for and look in multiple groups. If the group is NULL then the system default groups will be used.

    clock_video, clock_audio (bool)

    These specify whether audio and video "clock" themselves. When they are clocked, video frames added will be rate-limited to match the current framerate at which they are submitted. The same is true for audio.

    In general, if you are submitting video and audio of a single thread, you should only clock one of them (video is probably the better choice to clock off). If you are submitting audio and video of separate threads, then having both clocked can be useful.

    A simplified view of how it works is that when you submit a frame, it will keep track of the time the next frame would be required. If you submit a frame before this time, the call will wait until that time. This ensures that if you sit in a tight loop and render frames as fast as you can go, they will be clocked at the framerate that you desire.

    Note that combining clocked video and audio submission with asynchronous frame submission (

    circle-exclamation

    The total length of an NDI source name should be limited to 253 characters. The following characters are considered invalid: \ / : * ? " < > |. If any of these characters are found in the name, they will be replaced with a space. These characters are reserved according to Windows file system naming conventions, which we adhere to (Microsoft documentationarrow-up-right).

    hashtag
    Examples

    An example of creating an NDI sending instance is provided below.

    Once you have created a device, any NDI finders on the network will be able to see this source as available. You may now send audio, video, or metadata frames to the device – at any time, off any thread, and in any order.

    There are no reasonable restrictions on video, audio, or metadata frames that can be sent or received. In general, video frames yield better compression ratios as resolution increases (although the size does increase). Note that all formats can be changed frame-to-frame.

    The specific structures used to describe the different frame types are described in the section “Frame types” below. An important factor to understand is that video frames are “buffered” on an input; if you provide a video frame to the SDK when there are no current connections to it, the last video frame will automatically be sent when a new incoming connection is received. This is done without any need to recompress a frame (it is buffered in memory in compressed form).

    The following represents an example of how one might send a single 1080i59.94 white frame over an NDI sending connection.

    Because many applications provide interleaved 16-bit audio, the NDI library includes utility functions to convert PCM 16-bit formats to and from floating-point formats.

    Alternatively, there is a utility function (NDIlib_util_send_send_audio_interleaved_16s) for sending signed 16-bit audio. (Please refer to the example projects and also the header file Processing.NDI.utilities.h, which lists the functions available.) In general, we recommend using floating-point audio since clamping is not possible, and audio levels are well-defined without a need to consider audio headroom.

    Metadata is submitted in a very similar fashion. (We do not provide a code example as this is easily understood by referring to the audio and video examples.)

    To receive metadata being sent from the receiving end of a connection (e.g., which can be used to select pages, change settings, etc.), we refer you to the way the receive device works.

    The basic process involves calling NDIlib_send_capture with a time-out value. This can be used either to query whether a metadata message is available if the time-out is zero, or to efficiently wait for messages on a thread. The basic process is outlined below:

    Connection metadata, as specified in the NDI-Recv section of this documentation, is an important category of metadata that you will receive automatically as new connections to you are established. This allows an NDI receiver to provide up-stream details to a sender and can include hints as to the capabilities the receiver might offer. Examples include the resolution and framerate preferred by the receiver, its product name, etc. It is important that a sender is aware that it might be sending video data to more than one receiver at a time and, in consequence, will receive connection metadata from each one of them.

    Determining whether you are on program and/or preview output on a device such as a video mixer (i.e., ‘Tally’ information) is very similar to how metadata information is handled. You can ‘query’ it, or you can efficiently ‘wait’ and get tally notification changes. The following example will wait for one second and react to tally notifications:

    An NDI send instance is destroyed by passing it into NDIlib_send_destroy.

    Connection metadata is data that you can “register” with a sender; it will automatically be sent each time a new connection with the sender is established. The sender internally maintains a copy of any connection metadata messages and sends them automatically.

    This is useful to allow a sender to provide downstream information whenever any device might want to connect to it (for instance, letting it know what the product name or preferred video format might be). Neither senders nor receivers are required to provide this functionality and may freely ignore any connection data strings.

    Standard connection metadata strings are defined in a later section of this document. To add a metadata element, one can call NDIlib_send_add_connection_metadata. To clear all the registered elements, one can call NDIlib_send_clear_connection_metadata. An example that registers the name and details of your sender so that other sources that connect to you get information about what you are is provided below.

    Because NDI assumes that all senders must have a unique name and applies certain filtering to NDI names to make sure that they are network name-space compliant, at times, the name of a source you created may be modified slightly. To assist you in getting the exact name of any sender (to ensure you use the same one), there is a function to receive this name.

    const NDIlib_source_t* NDIlib_send_get_source_name(NDIlib_send_instance_t p_instance);

    The lifetime of the returned value is until the sender instance is destroyed.

    hashtag
    Asynchronous Sending

    It is possible to send video frames asynchronously using NDI using the call NDIlib_send_send_video_v2_async. This function will return immediately and will perform all required operations (including color conversion, any compression, and network transmission) asynchronously with the call.

    Because NDI takes full advantage of asynchronous OS behavior when available, this will normally result in improved performance (as compared to creating your own thread and submitting frames asynchronously with rendering).

    The memory that you passed to the API through the NDIlib_video_frame_v2_t pointer will continue to be used until a synchronizing API call is made. Synchronizing calls are any of the following:

    • Another call to NDIlib_send_send_video_v2_async.

    • A call to NDIlib_send_send_video_v2_async(pSend, NULL) will wait for any asynchronously scheduled frames to be completed and then return. Obviously, you can also submit the next frame, whereupon it will wait for the previous frame to finish before asynchronously submitting the current one.

    • Another call to NDIlib_send_send_video_v2.

    • A call to NDIlib_send_destroy.

    Using this in conjunction with a clocked video output results in a very efficient rendering loop where you do not need to use separate threads for timing or for frame submission. For example, the following is an efficient real-time processing system as long as rendering can always keep up with real-time:

    triangle-exclamation

    User error involving asynchronous sending is most common SDK ‘bug report’. It is very important to understand that a call to NDIlib_send_send_video_v2_async starts processing and then sends the video frame asynchronously with the calling application. If you call this and then free the pointer, your application will most likely crash in an NDI thread – because the SDK is still using the video frame that was passed to the call.

    If you re-use the buffer immediately after calling this function, your video stream will likely exhibit tearing or other glitches since you are writing to the buffer while the SDK is still compressing data it previously held. One possible solution is to “ping pong” between two buffers on alternating calls to NDIlib_send_send_video_v2_async, and then call that same function with a NULL frame pointer before releasing these buffers at the end of your application. When working in this way, you would generally render, compress, and send to the network, with each process being asynchronous to the others.

    circle-info

    If you are using the NDI Advanced SDKarrow-up-right, it is possible to assign a completion handler for asynchronous frame sending that more explicitly allows you to track buffer ownership with asynchronous sending.

    hashtag
    Timecode Synthesis

    It is possible to specify your own timecode for all data sent when sending video, audio, or metadata frames. You may also specify a value of NDIlib_send_timecode_synthesize (defined as INT64_MAX) to cause the SDK to generate the timecode for you. When you specify this, the timecode is synthesized as UTC time since the Unix Epoch (1/1/1970 00:00) with 100 ns precision.

    If you never specify a timecode at all (and instead ask for each to be synthesized), the current system clock time is used as the starting timecode (translated to UTC since the Unix Epoch), and synthetic values are generated. This keeps your streams exactly in sync as long as the frames you are sending do not deviate from the system time in any meaningful way. In practice, this means that if you never specify timecodes, they will always be generated correctly for you. Timecodes from different senders on the same machine will always be in sync with each other when working in this way. And if you have NTP installed on your local network, streams can be synchronized between multiple machines with very high precision.

    If you specify a timecode at a particular frame (audio or video), and then ask for all subsequent ones to be synthesized, the subsequent ones generated will continue this sequence. This maintains the correct relationship between the streams and samples generated, avoiding any meaningful deviation from the timecode you specified over time.

    If you specify timecodes on one stream (e.g., video) and ask for the other stream (audio) to be synthesized, the timecodes generated for the other stream exactly match the correct sample positions; they are not quantized inter-stream. This ensures that you can specify just the timecodes on a single stream and have the system generate the others for you.

    When you send metadata messages and ask for the timecode to be synthesized, it is chosen to match the closest audio or video frame timecode (so that it looks close to something you might want). If no sample looks sufficiently close, a timecode is synthesized from the last ones known and the time that has elapsed since it was sent.

    circle-exclamation

    Note that the algorithm to generate timecodes synthetically will correctly assign timestamps if frames are not submitted at the exact time.

    For instance, if you submit a video frame and then an audio frame in sequential order, they will both have the same timecode, even though the video frame may have taken a few milliseconds longer to encode.

    That said, no per-frame error is ever accumulated. So, if you are submitting audio and video and they do not align over a period of more than a few frames, the timecodes will still be correctly synthesized without accumulated error.

    hashtag
    Failsafe

    Failsafe is a capability of any NDI sender. If you specify a failsafe source on an NDI sender and the sender fails for any reason (even the machine failing completely), any receivers viewing that sender will automatically switch over to the failsafe sender. If the failed source comes back online, receivers will switch back to that source.

    You can set the fail-over source on any video input with a call to:

    hashtag
    Capabilities

    An NDI capabilities metadata message can be submitted to the NDI sender for communicating certain functionality that the downstream NDI receivers should know about upon connecting. For example, if you are providing PTZ-type functionality, letting the NDI receiver know this would done through this type of metadata message. The following is an example of the NDI capabilities message:

    <ndi_capabilities web_control="http://ndi.video/" ntk_ptz="true" ntk_exposure_v2="true" />

    You would submit this message to the NDI sender for communication to current and future NDI receivers as follows:

    Below is a table of XML attributes that can be used in this capabilities message:

    Supported Attributes
    Description

    web_control

    The URL to the local device webpage. If %IP% is present in the value, it will be replaced with the local IP of the NIC to which the NDI receiver is connected.

    ntk_ptz

    This signifies that this NDI sender is capable of processing PTZ commands sent from the NDI receiver. The NDI receiver will only assume the NDI sender can support PTZ commands if this attribute is received and set to the value “true”.

    ntk_pan_tilt

    The NDI sender supports pan and tilt control.

    hashtag
    iOS Notes

    When an iOS app is sent to the background, most of the networking functionality is put into a suspended state. Sometimes resources associated with networking are released back to the operating system while in this state.

    Apple recommends closing certain networking operations when the app is placed in the background and then restarted when put in the foreground again. Because of this, we recommend releasing an NDI sender instance within the app’s applicationDidEnterBackground method, then recreating the instance in the applicationDidBecomeActive method.

    NDIlib_send_create_t send_create; 
    send_create.p_ndi_name = "My Video"; 
    send_create.p_groups = NULL; 
    send_create.clock_video = true; 
    send_create.clock_audio = true;
    
    NDIlib_send_instance_t pSend = NDIlib_send_create(&send_create); 
    if (!pSend)
        printf("Error creating NDI sender");
    // Allocate a video frame (you would do something smarter than this!) 
    uint8_t* p_frame = (uint8_t*)malloc(1920*1080*4);
    memset(p_frame, 255, 1920*1080*4);
    
    // Now send it!
    NDIlib_video_frame_v2_t video_frame;
    video_frame.xres = 1920;
    video_frame.yres = 1080;
    video_frame.FourCC = NDIlib_FourCC_type_BGRA; video_frame.frame_rate_N = 30000;
    video_frame.frame_rate_D = 1001;
    video_frame.picture_aspect_ratio = 16.0f/9.0f; 
    video_frame.frame_format_type = NDIlib_frame_format_type_progressive; 
    video_frame.timecode = 0;
    video_frame.p_data = p_frame;
    video_frame.line_stride_in_bytes = 1920*4;
    video_frame.p_metadata = "<Hello/>";
    
    // Submit the buffer 
    NDIlib_send_send_video_v2(pSend, &video_frame);
    
    // Free video memory
    free(p_frame);
    
    // In a similar fashion, audio can be submitted for NDI audio sending, 
    // the following will submit 1920 quad-channel silent audio samples 
    // at 48 kHz
    // Allocate an audio frame (you would do something smarter than this!) 
    float* p_frame = (float*)malloc(sizeof(float)*1920*4)
    memset(p_frame, 0, sizeof(float)*1920*4);
    
    // describe the buffer
    NDIlib_audio_frame_v3_t audio_frame;
    audio_frame.sample_rate = 48000;
    audio_frame.no_channels = 4;
    audio_frame.no_samples = 1920;
    audio_frame.timecode = 0;
    audio_frame.p_data = p_frame; 
    audio_frame.channel_stride_in_bytes = sizeof(float)*1920; 
    audio_frame.p_metadata = NULL; // No metadata on this example!
    
    // Submit the buffer 
    NDIlib_send_send_audio_v3(pSend, &audio_frame);
    
    // Free the audio memory
    free(p_frame);
    // Wait for 1 second to see if there is a metadata message available 
    NDIlib_metadata_frame_t metadata;
    if (NDIlib_send_capture(pSend, &metadata, 1000) == NDIlib_frame_type_metadata)
    {
      // Do something with the metadata here
      // ...
      // Free the metadata message
    NDIlib_recv_free_metadata(pSend, &meta_data); 
    }
    // Wait for 1 second to see if there is a tally change notification. 
    NDIlib_tally_t tally_data;
    if (NDIlib_send_get_tally(pSend, &tally_data)
    {
      // The tally state changed and you can now
      // read the new state from tally_data.
    }
    // Provide a metadata registration that allows people to know what we are.
    NDIlib_metadata_frame_t NDI_product_type;
    NDI_product_type.p_data = "<ndi_product long_name=\"NDILib Send Example.\" " 
                              " short_name=\"NDILib Send\" "
                              " manufacturer=\"CoolCo, inc.\" "
                              " model_name=\"PBX-15M\" "
                              " version=\"1.000.000\" "
                              " serial=\"ABCDEFG\" "
                              " session_name=\"My Midday Show\" />";
                              
    NDIlib_send_add_connection_metadata(pSend, &NDI_product_type);
    while(!done())
    {
        render_frame();
    NDIlib_send_send_video_v2_async(pSend, &frame_data); 
    }
    
    NDIlib_send_send_video_v2_async(pSend, NULL); // Sync here
    void NDIlib_send_set_failover(NDIlib_send_instance_t p_instance,
                                  const NDIlib_source_t* p_failover_source);
    NDIlib_metadata_frame_t NDI_capabilities;
    NDI_capabilities.p_data = "<ndi_capabilities web_control=\"http://ndi.video/\" "
                                    "                  ntk_ptz=\"true\" "
                                    "                  ntk_exposure_v2=\"true\" />"; 
    NDIlib_send_add_connection_metadata(pNDI_send, &NDI_capabilities_type);
    see below
    ) allows you to write very simple loops to render and submit NDI frames.

    ntk_zoom

    The NDI sender supports zoom control.

    ntk_iris

    The NDI sender supports iris control.

    ntk_white_balance

    The NDI sender supports white balance control.

    ntk_exposure

    The NDI sender supports exposure control.

    ntk_exposure_v2

    The NDI sender supports detailed control over exposure such as iris, gain, and shutter speed.

    ntk_focus

    The NDI sender supports manual focus control.

    ntk_autofocus

    The NDI sender supports setting auto focus.

    ntk_preset_speed

    The NDI sender has preset speed support.

    Frame Types

    NDI sending and receiving use common structures to define video, audio, and metadata types. The parameters of these structures are documented below.

    hashtag
    Video Frames (NDILIB_VIDEO_FRAME_V2_T)

    Parameters
    Description
    FourCC
    Description

    When running in a YUV color space, the following standards are applied:

    Resolution
    Standard

    For the sake of compatibility with standard system components, Windows APIs expose 8-bit UYVY and RGBA video (common FourCCs used in all media applications).

    Parameters (Cont.)
    Description
    Standard
    Framerate ratio
    Framerate
    Parameters (Cont.)
    Description
    Aspect Ratio
    Calculated ad
    image_aspect_ratio
    Parameters (Cont.)
    Description
    Value
    Description
    circle-info

    To make everything as easy to use as possible, the SDK always assumes that fields are ‘top field first.’

    This is, in fact, the case for every modern format, but does create a problem for two specific older video formats as discussed below:

    hashtag
    NTSC 486 Lines

    The best way to handle this format is simply to offset the image vertically by one line (p_uyvy_data + uyvy_stride_in_bytes) and reduce the vertical resolution to 480 lines. This can all be done without modification of the data being passed in at all; simply change the data and resolution pointers.

    hashtag
    DV NTSC

    This format is a relatively rare these days, although still used from time to time. There is no entirely trivial way to handle this other than to move the image down one line and add a black line at the bottom.

    Parameters (Cont.)
    Description

    hashtag
    Audio Frames (NDILIB_AUDIO_FRAME_V3_T)

    NDI Audio is passed to the SDK in floating-point and has a dynamic range without practical limits (without clipping). To define how floating-point values map into real-world audio levels, a sinewave that is 2.0 floating-point units peak-to-peak (i.e., -1.0 to +1.0) is assumed to represent an audio level of +4 dBU, corresponding to a nominal level of 1.228 V RMS.

    Two tables are provided below that explain the relationship between NDI audio values for the SMPTE and EBU audio standards.

    hashtag
    SMPTE Audio levels - reference Level

    If you want a simple ‘recipe’ that matches SDI audio levels based on the SMPTE audio standard, you will want to have 20 dB of headroom above the SMPTE reference level at +4 dBu, which is at +0 dBVU, to correspond to a level of 1.0 in NDI floating-point audio. Conversion from floating-point to integer audio would thus be performed with:

    int smpte_sample_16bit = max(-32768, min(32767, (int)(3276.8f*smpte_sample_fp)));

    hashtag
    EBU Audio levels - reference Level

    If you want a simple ‘recipe’ that matches SDI audio levels based on the EBU audio standard, you will want to have 18 dB of headroom above the EBU reference level at 0 dBu (i.e., 14 dB above the SMPTE/NDI reference level). Conversion from floating-point to integer audio would thus be performed with:

    int ebu_sample_16bit = max(-32768, min(32767, (int)(6540.52f*ebu_sample_fp)));

    Because many applications provide interleaved 16-bit audio, the NDI library includes utility functions that will convert in and out of floating-point formats from PCM 16-bit formats.

    There is also a utility function for sending signed 16-bit audio using NDIlib_util_send_send_audio_interleaved_16s. Please refer to the example projects and the header file Processing.NDI.utilities.h, which lists the available functions.

    In general, we recommend the use of floating-point audio since clamping is not possible, and audio levels are well-defined without a need to consider audio headroom.

    The audio sample structure is defined as described below.

    Parameter
    Description

    hashtag
    Metadata Frames (NDILIB_METADATA_FRAME_T)

    Metadata is specified as NULL-terminated UTF-8 XML data. The reason for this choice is so that the format can naturally be extended by anyone using it to represent data of any type and length.

    XML is also naturally backward and forward compatible because any implementation would happily ignore tags or parameters that are not understood (which, in turn, means that devices should naturally work with each other without requiring a rigid set of data parsing and standard complex data structures).

    Parameter
    Description

    If you wish to put your own vendor specific metadata into fields, please use XML namespaces. The “NDI” XML namespace is reserved.

    circle-exclamation

    It is very important that you compose legal XML messages for sending. (On receiving metadata, it is important that you support badly formed XML in case a sender did send something incorrect.)

    If you want specific metadata flags to be standardized, please contact us.

    NDI Sender Event Monitoring

    To provide deeper control over NDI sources, the Advanced SDK supplements the standard NDI Send Advertiser and NDI Send Listener APIs with a more powerful toolset. These advanced APIs unlock comprehensive event subscription any registered sender. This extension empowers developers to not only be aware of the sender but also to listen to a sender's real-time event (per request or by default). Such capabilities are fundamental for creating sophisticated NDI ecosystems, allowing for intricate control and real-time monitoring of all NDI sending sources.

    Beyond the standard functions—NDIlib_send_advertiser_create and NDIlib_send_listener_create—available in the standard SDK, the Advanced SDK offers extended versions of this function calls:

    This is a 4:2:2 buffer in semi-planar format with full 16bpp color precision. This is formed from two buffers in memory, the first is a 16bpp luminance buffer and the second is a buffer of U,V pairs in memory. This can be considered as a 16bpp version of NV12.

    For instance, if you have an image with p_data and stride, then the planes are located as follows:

    As a matter of illustration, a completely packed image would have stride as xres*sizeof(uint16_t).

    NDIlib_FourCC_type_PA16

    This is a 4:2:2:4 buffer in semi-planar format with full 16bpp color and alpha precision. This is formed from three buffers in memory. The first is a 16bpp luminance buffer, and the second is a buffer of U,V pairs in memory. A single plane alpha channel at 16bpp follows the U,V pairs.

    For instance, if you have an image with p_data and stride, then the planes are located as follows:

    To illustrate, a completely packed image would have stride as

    xres*sizeof(uint16_t).

    NDIlib_FourCC_type_YV12

    This is a planar 4:2:0 in Y, U, V planes in memory.

    For instance, if you have an image with p_data and stride, then the planes are located as follows:

    As a matter of illustration, a completely packed image would have stride as xres*sizeof(uint8_t).

    NDIlib_FourCC_type_I420

    This is a planar 4:2:0 in Y,U,V planes in memory with the U,V planes reversed from the YV12 format.

    For instance, if you have an image with p_data and stride, then the planes are located as follows:

    To illustrate, a completely packed image would have stride as

    xres*sizeof(uint8_t).

    NDIlib_FourCC_type_NV12

    This is a semi planar 4:2:0 in Y, UV planes in memory. The luminance plane is at the lowest memory address with the UV pairs immediately following them.

    For instance, if you have an image with p_data and stride, then the planes are located as follows:

    To illustrate, a completely packed image would have stride as

    xres*sizeof(uint8_t).

    NDIlib_FourCC_type_BGRA

    A 4:4:4:4, 8-bit image of red, green, blue and alpha components, in memory order blue, green, red, alpha. This data is not pre-multiplied.

    NDIlib_FourCC_type_BGRX

    A 4:4:4, 8-bit image of red, green, blue components, in memory order blue, green, red, 255. This data is not pre-multiplied.

    This is identical to BGRA, but is provided as a hint that all alpha channel values are 255, meaning that alpha compositing may be avoided. The lack of an alpha channel is used by the SDK to improve performance when possible.

    NDIlib_FourCC_type_RGBA

    A 4:4:4:4, 8-bit image of red, green, blue and alpha components, in memory order red, green, blue, alpha. This data is not pre-multiplied.

    NDIlib_FourCC_type_RGBX

    A 4:4:4, 8-bit image of red, green, blue components, in memory order red, green, blue, 255. This data is not pre-multiplied.

    This is identical to RGBA, but is provided as a hint that all alpha channel values are 255, meaning that alpha compositing may be avoided. The lack of an alpha channel is used by the SDK to improve performance when possible.

    Full range for data type (0-255 range when running 8-bit and 0-65536 range when running 16-bit.)

    PAL 1080i50

    30000 / 1200

    25 Hz

    PAL 720p50

    60000 / 1200

    50 Hz

    NTSC 24fps

    24000 / 1001

    23.98 Hz

    16:10

    16.0/10.0

    1.6

    This is an individual field 1 from a fielded video frame. This is the second temporal, lower field (see note below).

    This is a per-frame metadata stream that should be in UTF-8 formatted XML and NULL-terminated. It is sent and received with the frame.

    timestamp (int64_t, 64-bit signed integer)

    This is a per-frame timestamp filled in by the NDI SDK using a high precision clock. It represents the time (in 100 ns intervals measured in UTC time, since the Unix Time Epoch 1/1/1970 00:00) when the frame was submitted to the SDK.

    On modern sender systems this will have ~1 μs accuracy; this can be used to synchronize streams on the same connection, between connections, and between machines. For inter-machine synchronization, it is important to use external clock locking capability with high precision (such as NTP).

    -16 dB

    +0 dB

    +4 dB

    +24 dB

    dBVU

    -∞

    -24 dB

    -20 dB

    -4 dB

    +0 dB

    +20 dB

    SMPTE dBFS

    -∞

    -44 dB

    -40 dB

    -24 dB

    -20 dB

    +0 dB

    -16 dB

    +0 dB

    +4 dB

    +18 dB

    dBVU

    -∞

    -24 dB

    -20 dB

    -4 dB

    +0 dB

    +14 dB

    EBU dBFS

    -∞

    -38 dB

    -34 dB

    -18 dB

    -14 dB

    +0 dB

    This is the timecode of this frame in 100 ns intervals. This is generally not used internally by the SDK but is passed through to applications which may interpret it as they wish. When sending data, a value of NDIlib_send_timecode_synthesize can be specified (and should be the default), the operation of this value is documented in the sending section of this documentation.

    NDIlib_send_timecode_synthesize will yield UTC time in 100 ns intervals since the Unix Time Epoch 1/1/1970 00:00. When interpreting this timecode, a receiving application may choose to localize the time of day based on time zone offset, which can optionally be communicated by the sender in connection metadata.

    Since the timecode is stored in UTC within NDI, communicating timecode time of day for non-UTC time zones requires a translation.

    FourCC (NDIlib_FourCC_audio_type_e)

    This is the sample format for this buffer. There is currently one supported format: NDIlib_FourCC_type_FLTP. This format stands for floating-point audio.

    p_data (uint8_t*)

    If FourCC is NDIlib_FourCC_type_FLTP, then this is the floating-point audio data in planar format, with each audio channel stored together with a stride between channels specified by channel_stride_in_bytes.

    channel_stride_in_bytes (int)

    This is the number of bytes that are used to step from one audio channel to another.

    p_metadata (const char*)

    This is a per-frame metadata stream that should be in UTF-8 formatted XML and NULL-terminated. It is sent and received with the frame.

    timestamp (int64_t, 64-bit signed integer)

    This is a per-frame timestamp filled in by the NDI SDK using a high-precision clock. It represents the time (in 100 ns intervals measured in UTC time since the Unix Time Epoch 1/1/1970 00:00) when the frame was submitted to the SDK.

    On modern sender systems, this will have ~1 μs accuracy and can be used to synchronize streams on the same connection, between connections, and between machines.

    For inter-machine synchronization, it is important that some external clock locking capability with high precision is used, such as NTP.

    xres, yres (int)

    This is the resolution of the frame expressed in pixels. Note that, because data is internally all considered in 4:2:2 formats, image width values should be divisible by two.

    FourCC

    (NDIlib_FourCC_video_type_e)

    This is the pixel format for this buffer. The supported formats are listed in the table below.

    NDIlib_FourCC_type_UYVY

    This is a buffer in the “UYVY” FourCC and represents a 4:2:2 image in YUV color space. There is a Y sample at every pixel, and U and V sampled at every second pixel horizontally on each line. A macro-pixel contains 2 pixels in 1 DWORD. The ordering of these pixels is U0, Y0, V0, Y1.

    Please see the notes below regarding the expected YUV color space for different resolutions.

    Note that when using UYVY video, the color space is maintained end-to-end through the pipeline, which is consistent with how almost all video is created and displayed.

    NDIlib_FourCC_type_UYVA

    This is a buffer that represents a 4:2:2:4 image in YUV color space. There is a Y sample at every pixels with U,V sampled at every second pixel horizontally. There are two planes in memory, the first being the UYVY color plane, and the second the alpha plane that immediately follows the first.

    For instance, if you have an image with p_data and stride, then the planes are located as follows:

    SD resolutions

    BT.601

    HD resolutions

    xres>720 || yres>576

    Rec.709

    UHD resolutions xres>1920 || yres>1080

    Rec.2020

    frame_rate_N, frame_rate_D (int)

    This is the framerate of the current frame. The framerate is specified as a numerator and denominator, such that the following is valid:

    frame_rate = (float)frame_rate_N / (float)frame_rate_D

    Some examples of common framerates are presented in the table below.

    NTSC 1080i59.94

    30000 / 1001

    29.97 Hz

    NTSC 720p59.94

    60000 / 1001

    59.94 Hz

    picture_aspect_ratio (float)

    The SDK defines picture aspect ratio (as opposed to pixel aspect ratios). Some common aspect ratios are presented in the table below. When the aspect ratio is 0.0 it is interpreted as xres/yres, or square pixel; for most modern video types this is a default that can be used.

    4:3

    4.0/3.0

    1.333...

    16:9

    16.0/9.0

    1.667...

    frame_format_type (NDIlib_frame_format_type_e)

    This is used to determine the frame type. Possible values are listed in the next table.

    NDIlib_frame_format_type_progressive

    This is a progressive video frame

    NDIlib_frame_format_type_interleaved

    This is a frame of video that is comprised of two fields. The upper field comes first, and the lower comes second (see note below)

    NDIlib_frame_format_type_field_0

    This is an individual field 0 from a fielded video frame. This is the first temporal, upper field (see note below).

    timecode (int64_t, 64-bit signed integer)

    This is the timecode of this frame in 100 ns intervals. This is generally not used internally by the SDK but is passed through to applications, which may interpret it as they wish. When sending data, a value of NDIlib_send_timecode_synthesize can be specified (and should be the default). The operation of this value is documented in the sending section of this documentation.

    p_data (const uint8_t*)

    This is the video data itself laid out linearly in memory in the FourCC format defined above. The number of bytes defined between lines is specified in line_stride_in_bytes. No specific alignment requirements are needed, although larger data alignments might result in higher performance (and the internal SDK codecs will take advantage of this where needed).

    line_stride_in_bytes (int)

    This is the inter-line stride of the video data, in bytes.

    NDI

    0.0

    0.063

    0.1

    0.63

    1.0

    10.0

    dBu

    -∞

    NDI

    0.0

    0.063

    0.1

    0.63

    1.0

    5.01

    dBu

    -∞

    sample_rate (int)

    This is the current audio sample rate. For instance, this might be 44100, 48000 or 96000. It can, however, be any value.

    no_channels (int)

    This is the number of discrete audio channels. 1 represents MONO audio, 2 represents STEREO, and so on. There is no reasonable limit on the number of allowed audio channels.

    no_samples (int)

    This is the number of audio samples in this buffer. Any number will be handled correctly by the NDI SDK. However, when sending audio and video together, please bear in mind that many audio devices work better with audio buffers of the same approximate length as the video framerate.

    We encourage sending audio buffers that are approximately half the length of the video frames and that receiving devices support buffer lengths as broadly as they reasonably can.

    length (int)

    This is the length of the metadata message in bytes. It includes the NULL-terminating character. If this is zero, then the length will be derived from the string length automatically.

    p_data (char*)

    This is the XML message data.

    timecode (int64_t, 64-bit signed integer)

    This is the timecode of this frame in 100 ns intervals. It is generally not used internally by the SDK but is passed through to applications who may interpret it as they wish.

    When sending data, a value of NDIlib_send_timecode_synthesize can be specified (and should be the default); the operation of this value is documented in the sending section of this documentation.

    NDIlib_FourCC_type_P216

    Alpha channel

    NDIlib_frame_format_type_field_1

    p_metadata (const char*)

    -20 dB

    -20 dB

    timecode (int64_t, 64-bit signed integer)

    NDIlib_send_advertiser_create_ex
  • NDIlib_send_listener_create_ex

  • These extended functions accept configuration settings as JSON strings, providing greater flexibility for managing network configurations of both the sender advertiser and listener.

    hashtag
    Subscribing to Sender Events

    To subscribe to receive monitoring events from a specified sender, use the following function,

    void NDIlib_send_listener_subscribe_events(NDIlib_send_listener_instance_t p_instance, const char* p_sender_uuid);

    This function requires the following parameters:

    • p_instance: The sender listener instance (NDIlib_send_listener_instance_t).

    • p_uuid: The unique identifier of the sender.

    The sender’s UUID is part of the NDIlib_sender_t structure, which is generated by the SDK. You can retrieve the list of senders using the NDIlib_send_listener_get_senders function, which will provide the necessary UUID for each sender.

    hashtag
    Unsubscribing from Sender Events

    To unsubscribe from receiving events from a specific sender, use the following function,

    NDIlib_send_listener_unsubscribe_events(NDIlib_send_listener_instance_t p_instance, const char* p_sender_uuid);

    This function requires the following parameters:

    • p_instance: The sender listener instance (NDIlib_send_listener_instance_t).

    • p_uuid: The unique identifier of the sender.

    Example Code:

    The following example demonstrates how to create a sender listener, retrieve the list of advertised senders, subscribe to events, and unsubscribe when finished:

    hashtag
    Sender Monitoring Events

    The NDIlib_send_listener_get_events function allows you to fetch the list of monitoring events from the sender that you have previously subscribed to using the NDIlib_send_listener_subscribe_events function. It returns an array of NDIlib_send_listener_event structures containing the event details.

    Parameters:

    • p_instance (NDIlib_send_listener_instance_t): The instance of the sender listener.

    • p_num_events (uint32_t*): A pointer to the variable that will receive the number of events returned by the function.

    • timeout_in_ms (uint32_t): The timeout value in milliseconds, determining how long the function will wait for events. A value of 0 returns immediately with any current pending events, and -1 waits indefinitely until an event is received and .

    This function returns a pointer to an array of NDIlib_send_listener_event structures containing event details. If no events are received within the specified timeout period, the function returns NULL. The returned events should be freed using the NDIlib_send_listener_free_events function.

    Example Code:

    The following table lists the sender monitoring events currently supported in the first release. These events provide dynamic information about an NDI sender’s state, source, and media properties.

    Event Name
    Description
    Type
    Example Event Values

    source-name

    Name of the NDI source.

    string

    “Camera 2”

    source-url

    Comma-delimited list of valid URLs for the NDI sender. It would be a list due to having multiple network interfaces being available on the system.

    These monitoring events allow tracking of both transient and persistent properties of an NDI Sender. Additional properties will be supported in future SDK versions.

        uint8_t *p_uyvy = (uint8_t*)p_data; 
        uint8_t *p_alpha = p_uyvy + stride*yres;
    // Create an instance of the sender listener. 
    NDIlib_send_listener_instance_t pNDI_sender_listener = NDIlib_send_listener_create_ex(nullptr, p_ndi_config); 
    if (!pNDI_sender_listener) { 
        // Handle error 
    } 
    
    // Get the list of advertised senders. 
    uint32_t num_senders = 0; 
    const NDIlib_sender_t* p_senders = NDIlib_send_listener_get_senders(pNDI_send_listener, &num_senders); 
    
    // Display the found senders. 
    printf("Network senders (%u found).\n", num_senders); 
    for (uint32_t i = 0; i < num_senders; i++) { 
    printf("%u. %s\n", i + 1, p_senders[i].p_name); 
    
    // If the sender is not currently subscribed, subscribe to it. 
    if (!p_sender[i].events_subscribed) { 
            NDIlib_send_listener_subscribe_events(pNDI_send_listener, p_senders[i].p_uuid); 
        } 
    
    // Perform operations with the subscribed sender... 
    … 
    // Unsubscribe from the sender after processing. 
       NDIlib_send_listener_unsubscribe_events(pNDI_send_listener, p_senders[i].p_uuid); 
    } 
    const NDIlib_send_listener_event*
    NDIlib_send_listener_get_events(NDIlib_send_listener_instance_t p_instance, uint32_t* p_num_events, uint32_t timeout_in_ms); 
    uint32_t num_events; 
    const NDIlib_send_listener_event* events = NDIlib_send_listener_get_events(p_instance, &num_events, 1000); 
    
    if (events != NULL) { 
        for (uint32_t i = 0; i < num_events; ++i) { 
            printf("Event UUID: %s\n", events[i].p_uuid); 
            printf("Event Name: %s\n", events[i].p_name); 
            printf("Event Value: %s\n", events[i].p_value); 
        } 
    
    // Free the events after processing 
    NDIlib_send_listener_free_events(events); 
    } else { 
        printf("No events received within the timeout period.\n"); 
    } 

    string

    “ndi://192.168.1.11/Camera_2”

    connection-state

    Indicator as to whether the NDI sender has any connected NDI receivers or not. Values can be one of the following:

    • connected

    • disconnected

    string

    “connected”, “disconnected”

    connected-receivers

    The number of connected NDI receivers to this NDI sender.

    int

    “42”

    metadata-frames-sent

    Number of metadata frames sent by the NDI sender. This would be an aggregate across each NDI receiver that is actively connected.

    int64

    “1”

    metadata-bytes-sent

    Number of bytes sent for metadata frames. This would be an aggregate across each NDI receiver that is actively connected.

    int64

    “2048”

    audio-present

    Has audio been sent through this NDI sender?

    bool

    true, false

    audio-codec

    The audio codec in use. Values can be one of the following:

    • pcm

    • aac

    • opus

    string

    “pcm”,”aac”,”opus”

    audio-channels

    The number of audio channels within the audio stream.

    int

    “8”

    audio-sample-rate

    The sample rate of the audio stream.

    int

    “44100”, “48000”

    audio-frames-sent

    Number of audio frames sent by the NDI sender. This would be an aggregate across each NDI receiver that is actively connected.

    int64

    “1976”

    audio-bytes-sent

    Number of bytes sent for audio frames. This would be an aggregate across each NDI receiver that is actively connected.

    int64

    “300001”

    video-present

    Has video been sent through this NDI sender?

     bool

    true, false

    video-codec

    The video codec in use. Values can be one of the following:

    • shq0

    • shq2

    • shq7

    • h264

    • h265

    string

    “shq0”

    video-resolution

    The resolution of the video frames, in “WxH” format, where W is the width and H is the height.

    string

    “1920x1080”,“1280x720”, “3840x2160”

    video-frame-rate

    The frame rate of the video stream, in “N/D” format, where N is the numerator and D is the denominator.

    string

    “30/1”, “60/1”, “30000/1001”

    video-frame-type

    The type of fielding format in use by the video stream. Values can be one of the following:

    • progressive

    • interlaced

    string

    “progressive”, “interlaced”

    video-has-alpha

    Does the video stream contain an alpha channel?

    bool

    true, false

    video-color-primaries

    Color primaries of the video stream. Values can be one of the following:

    • bt_601

    • bt_709

    • bt_2020

    • bt_2100

    string

    “bt_601”, “bt_709”, “bt_2020”, “bt_2100”

    video-transfer-function

    Transfer function of the video stream. Values can be one of the following:

    • bt_601

    • bt_709

    • bt_2020

    • bt_2100_hlg

    • bt_2100_pq

    string

    “bt_601”, “bt_709”, “bt_2020”, “bt_2100_hlg”, “bt_2100_pq”

    video-matrix-coefficients

    Matrix coefficients of the video stream. Values can be one of the following:

    • bt_601

    • bt_709

    • bt_2020

    • bt_2100

    string

    “bt_601”, “bt_709”, “bt_2020”, “bt_2100”

    video-frames-sent

    Number of video frames sent by the NDI sender. This would be an aggregate across each NDI receiver that is actively connected.

    int64

    “600”

    video-bytes-sent

    Number of bytes sent for video frames. This would be an aggregate across each NDI receiver that is actively connected.

    int64

    “450001”

    tally-on-program

    Is this NDI sender on program?

    bool

    true, false

    tally-on-preview

    Is this NDI sender on preview?

    bool

    true, false

    sdk-version

    Returns the NDI version for the sender.

    string

    6.3.0.0

        uint16_t *p_y = (uint16_t*)p_data;
        uint16_t *p_uv = (uint16_t*)(p_data + stride*yres);
        uint16_t *p_y = (uint16_t*)p_data; 
        uint16_t *p_uv = p_y + stride*yres; 
        uint16_t *p_alpha = p_uv + stride*yres;
        uint8_t *p_y = (uint8_t*)p_data;
        uint8_t *p_v = p_y + stride*yres; 
        uint8_t *p_u = p_v + (stride/2)*(yres/2);
        uint8_t *p_y = (uint8_t*)p_data;
        uint8_t *p_v = p_y + stride*yres; 
        uint8_t *p_u = p_v + (stride/2)*(yres/2);
          uint8_t *p_y = (uint8_t*)p_data;
          uint8_t *p_uv = p_y + stride*yres;

    NDI-RECV

    The NDI Receive SDK is how frames are received over the network. It is important to be aware that it can connect to sources and remain “connected” to them even when they are no longer available on the network; it will automatically reconnect if the source becomes available again.

    hashtag
    Parameters

    As with the other APIs, the starting point is to use the NDIlib_recv_create_v3 function. This function may be initialized with NULL , and default settings are used. This takes parameters defined by NDIlib_recv_create_v3_t, as follows:

    Supported Parameters
    Description

    The following table lists the optional values that can be used to specify the color format to be returned.

    Optional color_format values
    Frames without alpha
    Frames with alpha

    color_format notes

    If you specify the color option NDIlib_recv_color_format_fastest, the SDK will provide buffers in the format that it processes internally without performing any conversions before they are passed to you. This results in the best possible performance. This option also typically runs with lower latency than other options since it supports single-field format types.

    The allow_video_fields option is assumed to be true in this mode. On most platforms, this will return an 8-bit UYVY video buffer when there is no alpha channel and an 8-bit UYVY+A buffer when there is. These formats are described in the description of the video layout.

    If you specify the color option NDIlib_recv_color_format_best, the SDK will provide you buffers in the format closest to the native precision of the video codec being used. In many cases, this is both high-performance and high-quality and results in the best quality.

    Supported Parameters (cont.)
    Description

    Once you have filled out this structure, calling NDIlib_recv_create_v3 will create an instance for you. A full example is provided with the SDK that illustrates finding a network source and creating a receiver to view it (we will not reproduce that code here).

    If you create a receiver with NULL as the settings, or if you wish to change the remote source that you are connected to, you may call NDIlib_recv_connect at any time with a NDIlib_source_t pointer. If the source pointer is NULL it will disconnect you from any sources to which you are connected.

    Once you have a receiving instance you can query it for video, audio, or metadata frames by calling NDIlib_recv_capture_v3. This function takes a pointer to the header for audio (NDIlib_audio_frame_v3_t), video (NDIlib_video_frame_v2_t), and metadata (NDIlib_metadata_frame_t), any of which can be NULL. It can safely be called across many threads at once, allowing you to have one thread receiving video while another receives audio.

    The NDIlib_recv_capture_v3 function takes a timeout value specified in milliseconds. If a frame is available when you call NDIlib_recv_capture_v3, it will be returned without any internal waiting or locking of any kind. If the timeout is zero, it will return immediately with a frame if there is one. If the timeout is not zero, it will wait for a frame up to the timeout duration specified and return if it gets one (if there is already a frame waiting when the call is made it returns that frame immediately). If a frame of the type requested has been received before the timeout occurs, the function will return the data type received. Frames returned to you by this function must be freed.

    The following code illustrates how one might receive audio and/or video based on what is available; it will wait one second before returning if no data was received.

    You are able, if you wish, to take the received video, audio, or metadata frames and free them on another thread to ensure there is no chance of dropping frames while receiving them. A short queue is maintained on the receiver to allow you to process incoming data in the fashion most convenient for your application. If you always process buffers faster than in real-time, this queue will always be empty, and you will be running at the lowest possible latency.

    NDIlib_recv_capture_v3 may return the value NDIlib_frame_type_status_change, to indicate that the device’s properties have changed. Because connecting to a video source might take a few seconds, some of the properties of that device are not known immediately and might even change on the fly. For instance, when connecting to a PTZ camera, it might not be known for a few seconds that it supports the PTZ command set.

    When this does become known, the value NDIlib_frame_type_status_change is returned to indicate that you should recheck device properties. This value is currently sent when a source changes PTZ type, recording capabilities, or web user interface control.

    If you wish to determine whether any audio, video, or metadata frames have been dropped, you can call NDIlib_recv_get_performance, which will supply the total frame count and the number of frames that have been dropped because they could not be de-queued fast enough.

    If you wish to determine the current queue depths on audio, video, or metadata (to poll whether receiving a frame would immediately give a result), you can call NDIlib_recv_get_queue.

    NDIlib_recv_get_no_connections will return the number of connections that are currently active and can also be used to detect whether the video source you are connected to is currently online or not. Additional functions provided by the receive SDK allow metadata to be passed upstream to connected sources via NDIlib_recv_send_metadata. Much like the sending of metadata frames in the NDI Send SDK, this is passed as a NDIlib_metadata_frame_t structure that is to be sent.

    Tally information is handled via NDIlib_recv_set_tally. This will take a NDIlib_tally_t structure that can be used to define the program and preview visibility status. The tally status is retained within the receiver so that, even if a connection is lost, the tally state is correctly set when it is subsequently restored.

    Connection metadata is an important concept that allows you to “register” certain metadata messages so that each time a new connection is established, the up-stream source (normally an NDI-SEND user) receives those strings. Note that there are many reasons that connections might be lost and established at run time.

    For instance, if an NDI Sender goes offline, the connection is lost; if it comes back online at a later time, the connection would be re-established, and the connection metadata would be resent. Some standard connection strings are specified for connection metadata, as outlined in the next section.

    Connection metadata strings are added with NDIlib_recv_add_connection_metadata that takes an NDIlib_metadata_frame_t structure. To clear all connection metadata strings, allowing them to be replaced, call NDIlib_recv_clear_connection_metadata.

    An example that illustrates how you can provide your product name to anyone who ever connects to you is provided below.

    circle-info

    When using the , it is possible to assign custom memory allocators for receiving that will allow you to provide user-controlled buffers that are decompressed. This might sometimes improve performance or allow you to receive frames into GPU-accessible buffers.

    hashtag
    Receiver User Interfaces

    A sender might provide an interface that allows configuration. For instance, an NDI converter device might offer an interface that allows its settings to be changed; or a PTZ camera might provide an interface that provides access to specific settings and mode values. These interfaces are provided via a web URL that you can host.

    For example, a converter device might have an NDI Advanced SDK web page that is served at a URL such as http://192.168.1.156/control/index.html. In order to get this address, you simply call the function:

    const char* NDIlib_recv_get_web_control(NDIlib_recv_instance_t p_instance);

    This will return a string representing the URL, or NULL if there is no current URL associated with the sender in question. Because connections might take a few seconds, this string might not be available immediately after having called connect. To avoid the need to poll this setting, note that NDIlib_recv_capture_v3 returns a value of NDIlib_frame_type_status_change when this setting is known (or when it has changed).

    The string returned is owned by your application until you call NDIlib_recv_free_string.

    You can then store this URL and provide it to an end user as the options for that device. For instance, a PTZ camera or an NDI conversion box might allow its settings to be configured using a hosted web interface.

    For sources indicating they support the ability to be configured, the NDI Studio Monitor tool this capability, as shown in the bottom-right corner of the image below.

    When you click this gear gadget, the application opens the web page specified by the sender.

    hashtag
    Receiver PTZ Control

    NDI standardizes the control of PTZ cameras. An NDI receiver will automatically sense whether the device it is connected to is a PTZ camera and whether it may be controlled automatically.

    When controlling a camera via NDI, all configuration of the camera is completely transparent to the NDI client, which will respond to a uniform set of standard commands with well-defined parameter ranges. For instance, the NDI Studio Monitor tool uses these commands to display on-screen PTZ controls when the current source is reported to be a camera that supports control.

    To determine whether the connection that you are on would respond to PTZ messages, you may simply ask the receiver whether this property is supported using the following call:

    bool NDIlib_recv_ptz_is_supported(NDIlib_recv_instance_t p_instance);

    This will return true when the video source is a PTZ system, and false otherwise. Note that connections are not instantaneous, so you might need to wait a few seconds after connection before the source indicates that it supports PTZ control. To avoid the need to poll this setting, note that NDIlib_recv_capture_v3 returns a value of NDIlib_frame_type_status_change when this setting is known (or when it has changed).

    hashtag
    PTZ Control

    There are standard API functions to execute the standard set of PTZ commands. This list is not designed to be exhaustive and may be expanded in the future.

    It is generally recommended that PTZ cameras provide a web interface to give access to the full set of capabilities of the camera and that the host application control the basic messages listed below.

    hashtag
    Zoom Level

    bool NDIlib_recv_ptz_zoom(NDIlib_recv_instance_t p_instance, const float zoom_value);

    Set the camera zoom level. The zoom value ranges from 0.0 to 1.0.

    hashtag
    Zoom Speed

    bool NDIlib_recv_ptz_zoom_speed(NDIlib_recv_instance_t p_instance, const float zoom_speed);

    Control the zoom level as a speed value. The zoom speed value is in the range [-1.0, +1.0] with zero indicating no motion.

    hashtag
    Pan and Tilt

    bool NDIlib_recv_ptz_pan_tilt_speed(NDIlib_recv_instance_t p_instance, const float pan_speed, const float tilt_speed);

    This will tell the camera to move with a specific speed toward a direction. The speed is specified in a range [-1.0, 1.0], with 0.0 meaning no motion.

    bool NDIlib_recv_ptz_pan_tilt(NDIlib_recv_instance_t p_instance, const float pan_value, const float tilt_value);

    This will set the absolute values for pan and tilt. The range of these values is [-1.0, +1.0], with 0.0 representing center.

    hashtag
    Presets

    bool NDIlib_recv_ptz_store_preset(NDIlib_recv_instance_t p_instance, const int preset_no);

    Store the current camera position as a preset. The preset number is in the range 0 to 99.

    bool NDIlib_recv_ptz_recall_preset(NDIlib_recv_instance_t p_instance, const int preset_no, const float speed);

    Recall a PTZ preset. The preset number is in the range 0 to 99. The speed value is in the range 0.0 to 1.0, and controls how fast it will move to the preset.

    hashtag
    Focus

    Focus on cameras can either be in auto-focus mode or in manual focus mode. The following are examples of these commands:

    bool NDIlib_recv_ptz_auto_focus(NDIlib_recv_instance_t p_instance);

    bool NDIlib_recv_ptz_focus(NDIlib_recv_instance_t p_instance, const float focus_value);

    If the mode is auto, then there are no other settings. If the mode is manual, then the value is the focus distance, specified in the range 0.0 to 1.0.

    If you wish to control the focus by speed instead of absolute value, you may do this as follows:

    bool NDIlib_recv_ptz_focus_speed(NDIlib_recv_instance_t p_instance, const float focus_speed);

    The focus speed is in the range -1.0 to +1.0, with 0.0 indicating no change in focus value.

    White Balance

    White balance can be in a variety of modes, including the following:

    bool NDIlib_recv_ptz_white_balance_auto(NDIlib_recv_instance_t p_instance);

    This will place the camera in auto-white balance mode.

    bool NDIlib_recv_ptz_white_balance_indoor(NDIlib_recv_instance_t p_instance);

    This will place the camera in auto-white balance mode, but with a preference for indoor settings.

    bool NDIlib_recv_ptz_white_balance_outdoor(NDIlib_recv_instance_t p_instance);

    This will place the camera in auto-white balance mode, but with a preference for outdoor settings.

    bool NDIlib_recv_ptz_white_balance_manual(NDIlib_recv_instance_t p_instance, const float red, const float blue);

    This allows for manual white balancing, with the red and blue values in the range 0.0 to 1.0.

    bool NDIlib_recv_ptz_white_balance_oneshot(NDIlib_recv_instance_t p_instance);

    This allows you to set up the white balance automatically using the current center of the camera position. It will then store that value as the white-balance setting.

    Exposure Control

    Exposure can either be automatic or manual.

    bool NDIlib_recv_ptz_exposure_auto(NDIlib_recv_instance_t p_instance);

    This will place the camera in auto-exposure mode.

    bool NDIlib_recv_ptz_exposure_manual_v2(NDIlib_recv_instance_t p_instance, const float iris, const float gain, const float shutter_speed);

    hashtag
    Receivers and Tally Messages

    Video receivers can specify whether the source is visible on a video switcher’s program or preview row. This is communicated up-stream to the source’s sender, which then indicates its state (see the section on the sender SDK within this document). The sender takes its state and echoes it to all receivers as a metadata message of the form:

    <ndi_tally_echo on_program="true" on_preview="false"/>

    This message is very useful, allowing every receiver to ‘know’ whether its source is on program output.

    To illustrate, consider a sender named “My Source A” sending to two destinations, “Switcher” and “Multi-viewer”. When “Switcher” places “My Source A” on program out, a tally message is sent from “Switcher” to “My Source A”. Thus, the source ‘knows’ it is visible on program output. At this point, it will echo its tally state to “Multi-viewer” (and “Switcher”) so that the receiver is aware that “My Source A” is on program out. This functionality is used in the NDI tools Studio Monitor application to display an indicator when the source monitored has its tally state set.

    hashtag
    Frame Synchronization

    When using video, it is important to realize that different clocks are often used by different parts of the signal chain.

    Within NDI, the sender can send at the clock rate it wants, and the receiver will receive it at that rate. In many cases, however, the sender and receiver are extremely unlikely to share the exact same clock rate. Bear in mind that computer clocks rely on crystals which – while notionally rated for the same frequency – are seldom truly identical. For example, your sending computer might have an audio clock rated to operate at 48000 Hz. However, it might well actually run at 48001 Hz, or perhaps 47998 Hz.

    Similar variances also affect receivers. While the differences appear miniscule, they can accumulate to cause significant audio sync drift over time. A receiver may receive more samples than it plays back, or audible glitches can occur because too few audio samples are sent in a given time span. Naturally, the same problem affects video sources.

    It is very common to address these timing discrepancies by having a "frame buffer" and displaying the most recently received video frame. Unfortunately, the deviations in clock timing prevent this from being a perfect solution. Frequently, for example, the video will appear to ‘jitter’ when the sending and receiving clocks are almost aligned (which is actually the most common case).

    A "time base corrector" (TBC) or frame-synchronizer for the video clock provides another mechanism to handle these issues. This approach uses hysteresis to determine the best time to either drop or insert a video frame to achieve smooth video playback (audio should be dynamically sampled with a high-order resampling filter to adaptively track clocking differences).

    It’s quite difficult to develop something that is correct for all of the diverse scenarios that can arise, so the NDI SDK provides an implementation to help you develop real-time audio/video applications without assuming responsibility for the significant complexity involved.

    Another way to view what this component of the SDK does is to think of it as transforming ‘push’ sources (i.e., NDI sources in which the data is pushed from the sender to the receiver) into ‘pull’ sources, wherein the host application pulls the data down-stream. The frame sync automatically tracks all clocks to achieve the best video and audio performance while doing so.

    In addition to time-base correction operations, NDI’s frame sync will also automatically detect and correct for timing jitter that might occur. This internally handles timing anomalies such as those caused by network, sender, or receiver side timing errors related to CPU limitations, network bandwidth fluctuations, etc.

    A very common application of the frame-synchronizer is to display a video on a screen that is timed to the GPU v-sync, in which case you should convert the incoming time-base to the time-base of the GPU. The following table lists some common scenarios in which you might want to use frame synchronization:

    Scenario
    Recommendation

    To create a frame synchronizer object, you will call the function below (that is based on an already instantiated NDI receiver from which it will get frames). Once this receiver has been bound to a frame sync, you should use it in order to recover video frames.

    You can continue to use the underlying receiver for other operations, such as tally, PTZ, metadata, etc. Remember, it remains your responsibility to destroy the receiver – even when a frame-sync is using it (you should always destroy the receiver after the framesync has been destroyed).

    NDIlib_framesync_instance_t NDIlib_framesync_create(NDIlib_recv_instance_t p_receiver);

    The frame-sync is destroyed with the corresponding call:

    void NDIlib_framesync_destroy(NDIlib_framesync_instance_t p_instance);

    In order to recover audio, the following function will pull audio samples from the frame-sync queue. This function will always return data immediately, inserting silence if no current audio data is present. You should call this at the rate that you want audio, and it will automatically use dynamic audio sampling to conform the incoming audio signal to the rate at which you are calling.

    circle-info

    Note that you have no obligation to ensure that your requested sample rate, channel count, and number of samples match the incoming signal and that all combinations of conversions are supported.

    Audio resampling is done with high-order audio filters. Timecode and per-frame metadata are inserted into the best possible audio samples.

    Also, if you specify the desired sample rate as zero, it will fill in the buffer (and audio data descriptor) with the original audio sample rate. If you specify the channel count as zero, it will fill in the buffer (and audio data descriptor) with the original audio channel count.

    The buffer returned is freed using the corresponding function:

    time-basedThis function will pull video samples from the frame-sync queue. It will always immediately return a video sample by using time-based correction. You can specify the desired field type, which is then used to return the best possible frame.

    Note that:

    • Field-based frame sync means that the frame synchronizer attempts to match the fielded input phase with the frame requests to provide the most correct possible field ordering on output.

    • The same frame can be returned multiple times if duplication is needed to match the timing criteria.

    It is assumed that progressive video sources can i) correctly display either a field 0 or field 1, ii) that fielded sources can correctly display progressive sources, and iii) that the display of field 1 on a field 0 (or vice versa) should be avoided at all costs.

    If no video frame has ever been received, this will return NDIlib_video_frame_v2_t as an empty (all zero) structure. This allows you to determine that there has not yet been any video and act accordingly (for instance, you might want to display a constant frame output in a particular video format or black).

    The buffer returned is freed using the corresponding function:

    NDIlib_recv_color_format_RGBX_RGBA

    RGBX

    RGBA

    NDIlib_recv_color_format_UYVY_RGBA

    UYVY

    RGBA

    NDIlib_recv_color_format_fastest

    Normally UYVY. See notes below.

    Normally UYVA. See notes below.

    NDIlib_recv_color_format_best

    Varies. See notes below.

    Varies. See notes below.

    Like the NDIlib_recv_color_format_fastest, this format will always deliver individual fields, implicitly assuming the allow_video_fields option as true.

    On most platforms, when there is no alpha channel, this will return either a 16-bpp Y+Cb,Cr (P216 FourCC) buffer when the underlying codec is native NDI, or an 8-bpp UYVY buffer when the native codec is an 8-bit codec like H.264. When there is an alpha channel, this will normally return a 16-bpp Y+Cb,Cr+A (PA16 FourCC) buffer.

    You should support the NDIlib_video_frame_v2_t properties as widely as you possibly can in this mode since there are very few restrictions on what you might be passed.

    Yes – you want all input audio clocks to be brought into sync with your output audio clock. You would create a frame-synchronizer for each audio source and – when driving the output – call each one, asking for the correct number of samples and sample rate for your output.

    Recording a single channel

    No – you should record the signal in the raw form without any re-clocking.

    Recording multiple channels

    Maybe – If you want to sync some input channels to match a master clock so that they can be ISO-edited, you might want a frame-sync for all sources except one (allowing them all to be synchronized with a single channel).

    source_to_connect_to

    This is the source name that should be connected to. This is in the exact format returned by NDIlib_find_get_sources.

    Note that you may specify the source as a NULL source if you wish to create a receiver that you desire to connect at a later point with NDIlib_recv_connect.

    p_ndi_name

    This is a name that is used for the receiver and will be used in future versions of the SDK to allow discovery of both senders and receivers on the network. This can be specified as NULL and a unique name based on the application executable name will be used.

    color_format

    This parameter determines what color formats you are passed when a frame is received. In general, there are two color formats used in any scenario: one that exists when the source has an alpha channel and another when it does not.

    NDIlib_recv_color_format_BGRX_BGRA

    BGRX

    BGRA

    NDIlib_recv_color_format_UYVY_BGRA

    UYVY

    BGRA

    bandwidth

    This allows you to specify whether this connection is in high or low bandwidth mode. It is an enumeration because other alternatives may be available in the future. For most uses, you should specify NDIlib_recv_bandwidth_highest, which will result in the same stream that is being sent from the up-stream source to you.

    You may specify NDIlib_recv_bandwidth_lowest, which will provide you with a medium-quality stream that takes significantly reduced bandwidth.

    allow_video_fields

    If your application does not like receiving fielded video data, you can specify false to this value, and all video received will be de-interlaced before it is passed to you.

    The default value should be considered true for most applications. The implied value is true when color_format is NDIlib_recv_color_format_fastest.

    p_ndi_name

    This is the name of the NDI receiver to create. It is a NULL-terminated UTF-8 string. Give your receiver a meaningful, descriptive, and unique name. This will be the name of the NDI receiver on the network. For instance, if your network machine name is called “MyMachine” and you specify this parameter as “Video Viewer”, then the NDI receiver on the network would be “MyMachine (Video Viewer)”.

    Video playback on a screen or multiviewer

    Yes – you want the clock to be synced with vertical refresh. On a multiviewer, you would have a frame-sync for every video source, then call all of them on each v-sync and redraw all sources at that time.

    Audio playback through sound card

    Yes – the clock should be synced with your sound card clock.

    Video mixing of sources

    Yes – all video input clocks need to be synced to your output video clock. You can take each of the video inputs and frame-synchronize them together.

    NDI Advanced SDKarrow-up-right

    Audio mixing

    NDIlib_video_frame_v2_t video_frame;
    NDIlib_audio_frame_v3_t audio_frame; 
    NDIlib_metadata_frame_t metadata_frame;
    
    switch (NDIlib_recv_capture_v3(pRecv, &video_frame, &audio_frame, &metadata_frame, 1000)) 
    {
    
        // We received video.
        case NDIlib_frame_type_video:
            // Process video here
            // Free the video. 
            NDIlib_recv_free_video_v2(pRecv, &video_frame); 
            break;
            
        // We received audio.
        case NDIlib_frame_type_audio:
            // Process audio here
            // Free the audio. 
            NDIlib_recv_free_audio_v3(pRecv, &audio_frame);
            break;
        
        // We received a metadata packet 
        case NDIlib_frame_type_metadata:
            // Do what you want with the metadata message here. 
            // Free the message 
            NDIlib_recv_free_metadata(pRecv, &metadata_frame); 
            break;
        
        // No audio or video has been received in the time-period. 
        case NDIlib_frame_type_none:
            break;
        
        // The device has changed status in some way (see notes below) 
        case NDIlib_frame_type_status_change:
            break;
    }    
    // Provide a metadata registration that allows people to know what we are. 
    NDIlib_metadata_frame_t NDI_product_type;
    NDI_product_type.p_data =  "<ndi_product long_name=\"NDILib Receive Example.\" " 
                               "             short_name=\"NDILib Receive\" "
                               "             manufacturer=\"CoolCo, inc.\" "
                               "             version=\"1.000.000\" "
                               "             model_name=\"PBX-42Q\" "
                               "             session_name=\"My Midday Show\" " 
                               "             serial=\"ABCDEFG\" />";
                               
    NDIlib_recv_add_connection_metadata(pRecv, &NDI_product_type);
    const char* p_url = NDIlib_recv_get_web_control(pRecv); 
    if (p_url)
    {
        // You now have a URL that you can embed in your user interface if you want! 
        // Do what you want with it here and when done, call: 
        NDIlib_recv_free_string(pRecv, p_url);
    } 
    else 
    {
        // This device does not currently support a configuration user interface. 
    }
    void NDIlib_framesync_capture_audio(
        NDIlib_framesync_instance_t p_instance, // The frame sync instance 
        NDIlib_audio_frame_v2_t* p_audio_data, // The destination audio buffer 
        int sample_rate, // Your desired sample rate. 0 for “use source”.
        int no_channels, // Your desired channel count. 0 for “use source”. 
        int no_samples); // The number of audio samples that you wish to get.
    void NDIlib_framesync_free_audio(NDIlib_framesync_instance_t p_instance,        
                                     NDIlib_audio_frame_v2_t* p_audio_data);
    void NDIlib_framesync_capture_video(
        NDIlib_framesync_instance_t p_instance, // The frame-sync instance 
        NDIlib_video_frame_v2_t* p_video_data, // The destination video frame 
        NDIlib_frame_format_type_e field_type); // The frame type that you prefer
    void NDIlib_framesync_free_video(NDIlib_framesync_instance_t p_instance, 
                                     NDIlib_video_frame_v2_t* p_video_data);