MISB ST0601 / STANAG 4609 mux, demux & live streaming library for Python.
| Module | What it does |
|---|---|
| mux | Turn DJI drone footage + telemetry into STANAG 4609 videos with embedded KLV |
| demux | Extract and decode KLV telemetry from any STANAG-compliant video file |
| stream | Read KLV in real-time from live UDP/RTP/RTSP streams |
| vmti | Parse MISB ST 0903 VMTI target tracking metadata |
pip install pymisbDonations — If this project is useful for you, consider buying me a beer!
from pymisb.common import build_klv_packets
from pymisb.mux import mux_with_ffmpeg
packets = build_klv_packets("telemetry.csv")
mux_with_ffmpeg("drone.mp4", packets, "output.ts")from pymisb.demux import extract_klv, decode_packets
klv_data = extract_klv("output.ts")
packets = decode_packets(klv_data)
for pkt in packets:
meta = pkt.MetadataList()
print(meta[13]) # Sensor Latitudefrom pymisb.stream import open_stream
with open_stream("udp://@:5000") as reader:
for pkt in reader:
meta = pkt.MetadataList()
print(meta[13]) # Sensor Latitude in real-timefrom pymisb.vmti import parse_vmti, extract_vmti
targets = parse_vmti(extract_vmti("video.ts"))
for t in targets:
print(t["target_centroid_lat"], t["target_classification"])pymisb/
├── constants.py Shared constants (keys, versions, FOV, etc.)
├── common/
│ ├── encoder.py MISB ST0601 KLV packet builder
│ ├── dji.py DJI CSV + binary .txt flight record parsers
│ └── ts.py Path defaults and KLV stream writer
├── mux/
│ └── engine.py MPEG-TS muxing (PES/PCR/KLV injection + FFmpeg)
├── demux/
│ └── engine.py KLV extraction and decoding from files
├── stream/
│ └── engine.py Real-time KLV from UDP/RTP/RTSP streams
├── vmti/
│ └── engine.py MISB ST 0903 VMTI target metadata
└── klvdata/ Vendored MISB ST0601/0903 KLV decoder
- Python 3.12+ (3.12, 3.13)
- FFmpeg on the PATH (for muxing, demuxing, and streaming)
pip install pymisbgit clone https://github.com/All4Gis/pymisb.git
cd pymisb
pip install .git clone https://github.com/All4Gis/pymisb.git
cd pymisb
pip install -e ".[test]"python -c "from pymisb.constants import UAS_LS_KEY; print('OK')"
pymisb-mux --help
pymisb-demux --help# From DJI CSV telemetry
pymisb-mux --video drone.mp4 --csv telemetry.csv
pymisb-mux --video drone.mp4 --csv telemetry.csv --out output.ts
# From DJI binary .txt flight record
pymisb-mux --video drone.mp4 --dji-txt DJIFlightRecord.txt
# KLV only (no video muxing)
pymisb-mux --csv telemetry.csv --out output.ts --klv-only
# Or via module
python -m pymisb.mux --video drone.mp4 --csv telemetry.csv# Dump all KLV packets
pymisb-demux output.ts
# Playback at the video's real rate
pymisb-demux output.ts --play
# Accelerated playback x4
pymisb-demux output.ts --play --speed 4
# Show every ST0601 tag
pymisb-demux output.ts --all
# Tag tree of the first packet
pymisb-demux output.ts --structure# Read KLV from a live UDP stream
pymisb-stream udp://@:5000
# RTSP camera
pymisb-stream rtsp://camera.local/stream --all
# Or via module
python -m pymisb.stream udp://@:5000# Decode VMTI targets from a video
pymisb-vmti video.ts
# Show all target fields
pymisb-vmti video.ts --allfrom pymisb.common import (
build_st0601_packet, # Build a single ST0601 KLV packet
build_klv_packets, # Parse DJI CSV -> list of KLV packets
build_klv_packets_from_txt, # Parse DJI .txt -> list of KLV packets
default_output, # Generate default output path
write_klv_stream, # Write packets as raw KLV file
)from pymisb.mux import (
mux_with_ffmpeg, # Full mux pipeline (FFmpeg + KLV injection)
inject_klv_into_ts, # Low-level: inject KLV into existing TS
)from pymisb.demux import (
extract_klv, # Extract raw KLV bytes from TS via FFmpeg
decode_packets, # Decode raw KLV into parsed ST0601 packets
)from pymisb.stream import open_stream
# Iterator mode — yields packets as they arrive
with open_stream("udp://@:5000") as reader:
for pkt in reader:
meta = pkt.MetadataList()
print(meta[13])
# Callback mode
def on_packet(pkt):
print(pkt.MetadataList()[13])
reader = open_stream("rtsp://camera.local/stream")
reader.start(callback=on_packet)
reader.stop()from pymisb.vmti import parse_vmti, extract_vmti, decode_vmti_stream
# From a TS file
targets = parse_vmti(extract_vmti("video.ts"))
for t in targets:
print(t["target_centroid_lat"], t["target_classification"])
# From raw bytes
targets = decode_vmti_stream(vmti_bytes)from pymisb.constants import (
UAS_LS_KEY, # 16-byte UAS Datalink Local Set universal key
KLV_HEADER_KEY, # Shifted key for DJI non-standard headers
ST0601_VERSION, # MISB ST0601 version (Tag 65)
HFOV_DEG, VFOV_DEG, # Camera field of view (degrees)
EARTH_MEAN_RADIUS, # WGS-84 radius in meters
)Edit pymisb/constants.py to adjust:
HFOV_DEG/VFOV_DEG— camera field of view (affects sensor footprint)ST0601_VERSION— advertised Local Set version (Tag 65)
| Standard | Name | Status |
|---|---|---|
| MISB ST 0601 | UAS Datalink Local Set | Full (encode + decode) |
| MISB ST 0903 | VMTI (Video Moving Target Indicator) | Decode |
| MISB ST 0102 | Security Metadata | Decode (via klvdata) |
| MISB EG 0104 | UAV Basic Universal Metadata | Decode (via klvdata) |
| STANAG 4609 | NATO video standard | Full (mux + demux) |
# Install with test dependencies
pip install -e ".[test]"
# Run all tests
pytest tests/ -v
# Run specific test file
pytest tests/test_misb_common.py -v
# Run specific test
pytest tests/test_misb_common.py::TestBuildSt0601Packet -v
# With coverage
pip install pytest-cov
pytest tests/ --cov=pymisb --cov-report=term-missing| Test file | Coverage |
|---|---|
tests/test_misb_common.py |
ST0601 encoder, DJI parsers, BER/BCC, geometry |
tests/test_misb_mux.py |
MPEG-TS primitives (PES, PTS, PCR, packetization) |
tests/test_klvdata.py |
Vendored klvdata decoder (ST0601 tags, BER-TLV, integration) |
CI runs on every push across Python 3.12-3.13 on Linux, macOS, and Windows.
# Build
pip install build
python -m build
# Publish to PyPI
pip install twine
twine upload dist/*
# Or TestPyPI first
twine upload --repository testpypi dist/*
pip install --index-url https://test.pypi.org/simple/ pymisbThis project is licensed under the MIT License.
The vendored klvdata decoder in pymisb/klvdata/ is derived from
paretech/klvdata (MIT). See
THIRD_PARTY_LICENSES.md for full attribution.
"From raw drone footage to geospatial intelligence — one KLV packet at a time."
Made with passion by Fran Raga franka1986@gmail.com - June 2026.
If this saved you a few hours, give the repo a star and fly safe. Happy coding!