Insert Custom KLV and Private Data in MPEG-TS with FFmpeg

Multiplexing custom private data, such as KLV (Key-Length-Value) metadata, into an MPEG-TS stream is a critical requirement for geospatial, military, and custom telemetry applications. This article provides a direct, technical guide on how to use FFmpeg to inject custom binary payloads and KLV metadata streams into an MPEG-TS container, detailing the exact command-line arguments, mapping parameters, and stream configurations required.

Preparing the Input Files

To insert private data or KLV into an MPEG-TS stream, you need two primary inputs: 1. The Video/Audio Source: Your primary media file (e.g., input.mp4 or an active RTSP stream). 2. The Private Data Payload: A raw binary file (e.g., metadata.bin) containing your pre-formatted KLV packets or custom binary data.

Injecting Raw Private Data (PES Stream Type 0x06)

To inject raw binary data as a private data stream (often identified in the MPEG-TS Program Map Table as Stream Type 0x06), use the raw data demuxer in FFmpeg to ingest the binary file.

Run the following command:

ffmpeg -i input.mp4 -f data -i metadata.bin \
-map 0:v -map 0:a -map 1:d \
-c:v copy -c:a copy -c:d copy \
-f mpegts \
-streamid 2:0x103 \
output.ts

Command Breakdown:

Injecting SMPTE 336M KLV Metadata (PES Stream Type 0x15)

If your metadata complies with the SMPTE 336M KLV standard, you want the MPEG-TS muxer to register it with Stream Type 0x15 (Metadata carried in PES packets). FFmpeg supports this via the klv data codec.

Run the following command:

ffmpeg -i input.mp4 -f data -i klv_data.bin \
-map 0:v -map 1:d \
-c:v copy -c:d klv \
-f mpegts \
output.ts

Command Breakdown:

Synchronizing Data with Video Timestamps

By default, mapping a static binary file to an MPEG-TS stream will write the data packets at the very beginning of the stream. For real-time telemetry or synchronized KLV, the input data packets must contain presentation timestamps (PTS).

If you are streaming live data (for example, via a UDP socket), you can bind the live data feed directly into FFmpeg:

ffmpeg -i input.mp4 -f data -i udp://127.0.0.1:9000 \
-map 0:v -map 1:d \
-c:v copy -c:d copy \
-f mpegts output.ts

This ensures that as data packets arrive at the UDP port, FFmpeg multiplexes them into the output TS container interleaved with the video frames.