Firmware Engineering — NDI Over IP

We Added NDI to Cameras
That Were Never Supposed to Have It.

The ValueHD UV510A and V71UV are $50–$150 PTZ cameras on eBay. They ship with no NDI support whatsoever. We modified their firmware to add full NDI—including working discovery server registration and a proper NDI settings panel in the web admin. Here’s how, and why it wasn’t easy.

NDI cameras for $100.
Not $1,200.

A production-grade NDI PTZ camera from a name-brand vendor runs $800–$2,000. The UV510A and V71UV are the same category of camera—Chinese-manufactured, 1080p, optical zoom, pan-tilt-zoom with IP control—and they show up on eBay used for $50–$150. The only thing separating them from their expensive counterparts was software.

With custom firmware, these cameras appear on the network as fully functional NDI sources. They register with an NDI discovery server, announce themselves to NewTek’s device discovery, and stream low-latency video over IP to any NDI-compatible switcher, encoder, or production software. The result is a camera that performs like a $1,200 piece of gear and costs what you’d pay for lunch.

We run these in production at TigerVision. Not as a cost-cutting experiment—as cameras we rely on in a live broadcast.

Camera Specs — As Modified
Models UV510A, V71UV
Resolution 1080p30 / 1080p60
NDI Version NDI 4 / NDI HX
Discovery Server Working ✓
Web Admin NDI Panel Working ✓
Street Price (eBay) $50–$150

What “Working NDI” Means Here

Camera announces itself via NDI discovery
Registers with a configured discovery server
Stream visible in OBS, vMix, Tricaster, NDI Studio Monitor
NDI name, group, and server configurable in web admin
Persists across reboots

What firmware modification actually looks like

PTZ cameras in this price range run embedded Linux on an ARM or MIPS SoC—typically something in the HiSilicon Hi3516 / Hi3519 family. The firmware image is a flat binary that packages a compressed kernel, a SquashFS root filesystem, and a writable JFFS2 or UBI partition for persistent config. Getting into it means treating the binary like a puzzle: find the partition offsets, extract each segment, mount the filesystem, modify it, and repack everything without corrupting the boot sequence or the checksum the bootloader uses to verify the image before it flashes.

That’s the overview. The specifics are where it gets genuinely painful.

Step 1

Firmware Extraction & Filesystem Unpacking

The firmware update file is not a standard container format. It’s a vendor-specific binary blob with a header that encodes offsets, sizes, and a CRC32 or MD5 for each segment. We used binwalk to identify compression signatures and partition boundaries, then extracted the SquashFS volume and mounted it via a loopback device. From there the root filesystem is fully readable—busybox userland, an nginx or lighttpd web server serving the camera’s admin panel, and a collection of proprietary binaries that handle encoding, PTZ motor control, and stream output.

Step 2

NDI Runtime for ARM Embedded Linux

NDI is a licensed SDK. The libraries and runtime binaries are architecture-specific, and “embedded Linux on a camera SoC” is not a tier that NewTek/Vizrt officially ships for. Getting the right ARM EABI build, stripping it down to what the camera actually needs, and resolving the dependency chain against the camera’s stripped-down libc is a compatibility exercise in patience. Library version mismatches cause silent failures—the NDI process starts, reports no error, and produces no output. Strace across a UART serial connection is how you find out why.

Step 3

Tapping the Video Pipeline

The camera’s existing output stack—RTSP, H.264 over ONVIF, RTMP—uses the SoC’s hardware encoder through a vendor kernel module via a proprietary ioctl interface. NDI needs uncompressed or minimally compressed frames. Getting access to the video pipeline without breaking the existing outputs means either finding an intercept point in the encoder chain or pulling from the ISP output before H.264 compression. On both cameras, the viable intercept is post-ISP, pre-encoder—which requires reverse engineering the vendor’s media framework enough to open a secondary consumer on the same frame buffer. None of this is documented.

Step 4

Web Admin Integration

A camera that streams NDI but has no UI for configuring it is a half-finished job. We added a proper NDI settings page to the web admin: camera name (what appears in NDI discovery), group assignment, discovery server IP, and enable/disable toggle. These settings write to the persistent config partition so they survive a power cycle. The web admin itself is a mix of CGI scripts and static HTML served by a minimal embedded web server—adding a page means matching that structure exactly, including the way the existing pages call into the config daemon to read and write settings.

Decompiling PTZOptics firmware
and bypassing registration

The UV510A required building NDI support from scratch on a platform that had never seen it. The V71UV presented a different kind of problem: a working NDI implementation already existed—in PTZOptics’ firmware for their branded cameras, which share a hardware platform with the V71UV. The NDI module was there. It just refused to run.

PTZOptics sells NDI cameras at a significant premium over the underlying hardware cost. To protect that margin, their NDI module performs a registration check before enabling the output stream. On a genuine PTZOptics camera, the camera’s serial number is tied to a license in their activation system. On a V71UV with PTZOptics firmware flashed, the check fails silently and NDI never comes up. The binary runs. No errors in the log. No NDI source on the network. Nothing.

The NDI module was a stripped ARM shared library with no symbols, no debug info, and an obfuscated registration routine that made outbound calls to PTZOptics’ activation servers before deciding whether to enable the encoder. Ghidra turned it into C pseudocode that was technically readable but practically incomprehensible until you knew what you were looking for.

How We Got Past It

1

Disassembly with Ghidra

The PTZOptics NDI module is a compiled ARM shared object. No source. No symbols beyond the exported NDI function names. We loaded it into Ghidra with the ARM Cortex-A little-endian processor definition and let it run auto-analysis. The decompiler output is C-like pseudocode—close enough to reason about, far enough from readable that you spend more time naming variables than reading code. The registration routine wasn’t labeled as such; it appeared as a function called during module initialization that conditionally set a flag checked before the encoder would produce any output frames.

2

Tracing the Activation Flow

The module made outbound HTTPS calls using a hardcoded hostname. We intercepted those calls with a local DNS override pointing the activation hostname at a controlled server, which let us see the exact request structure: a camera serial number and model identifier sent in a POST, with the response body containing an encrypted token. The module decrypts the token, extracts a capability flag, and stores it in a memory-mapped region that the encoder checks before producing any output. Without a valid token, the flag is never set.

3

The Patch

Back in Ghidra, we located the conditional branch instruction that gates on the capability flag. A targeted patch in the ARM binary—replacing a branch-if-zero with a no-op or unconditional branch depending on the exact instruction variant—makes the check always pass. The patch is applied to the extracted binary before repacking the firmware image. The module still makes its network calls on startup; they fail, it doesn’t care, and NDI comes up anyway. The result is a V71UV that streams full NDI with all the web admin controls intact.

Why the V71UV specifically

Many Chinese PTZ cameras share production lines. The V71UV and certain PTZOptics models come off the same or nearly identical hardware. PTZOptics licenses firmware to the OEM and resells the camera with their software stack and brand at a significant markup. The V71UV is that same camera sold without the PTZOptics relationship—same SoC, same board, same sensor, different label. The firmware transplant works because the hardware is functionally identical. The registration bypass works because the check is purely a software gate, not tied to any hardware identifier unique to PTZOptics-branded units.

Running live, every game night

These aren’t prototype cameras sitting on a bench. They run at TigerVision games alongside our manned cameras and production trailer, feeding NDI into our switching stack.

Discovery Server Support

The cameras register with a configured NDI discovery server at boot. On networks where mDNS is blocked or unreliable—which describes most school network environments—this is the only reliable way to get NDI working. Discovery server IP is configurable from the web admin without touching the camera again.

Full Web Admin Control

NDI source name, group, and discovery server are all configurable through the camera’s web interface. Settings persist across power cycles. No SSH, no config files, no serial console access required to operate the camera in the field.

Existing Outputs Intact

RTSP, ONVIF, and HTTP MJPEG streams continue to work alongside NDI. The cameras are still fully controllable via PTZ-over-IP and VISCA. NDI is additive—it doesn’t replace or break what was already there.

Live Broadcast Production
How we put events on air →
TigerVision Case Study
The broadcast where these cameras run →
Live Sports Streaming Cost
What production actually costs at each level →

Questions about NDI infrastructure or broadcast production?

We’ve done this the hard way so you don’t have to. Talk to us about what you’re trying to build.

Get in Touch See Our Production Work