A Python tool to embed telemetry data from DJI drone SRT files into MP4 video files.
Features:
- Extract GPS coordinates, altitude, camera settings and other telemetry data from SRT files
- Embed metadata directly into MP4 video files using FFmpeg
- Support for multiple DJI drone models (Mini 3/4 Pro, Air 3, Avata 2, Mavic 3 Enterprise)
- Export telemetry data to GPX and CSV formats
- Professional CLI with comprehensive validation and diagnostics
- Privacy-safe GPS redaction options
- No video re-encoding for fast processing
README
DJI Drone Metadata Embedder
A Python tool to embed telemetry data from DJI drone SRT files into MP4 video files.
This tool extracts GPS coordinates, altitude, camera settings and other telemetry data from SRT files and embeds
them as metadata in the corresponding video files.
This is a tool for transparency and accountability. Drone telemetry is
dual-use, and this project deliberately focuses on the open side of that:
verifying and documenting footage, georeferencing it for mapping, and making it
interoperable with open GIS workflows. The uses we build for include
open-source verification and journalism, human-rights and conflict
documentation, search-and-rescue and disaster response, humanitarian damage
assessment, environmental monitoring, agriculture, and infrastructure
inspection.
Feature and documentation decisions favor provenance, verification,
georeferencing, and standards interoperability. We do not build targeting or
other offensive capabilities.
Already installed? Upgrade with winget upgrade CallMarcus.DJIMetadataEmbedder.
> Note: winget installs the portable dji-embed.exe only. Install FFmpeg and ExifTool separately (winget install Gyan.FFmpeg OliverBetz.ExifTool), or use the bootstrap script above, which bundles them.
docker run --rm -v "$PWD":/data callmarcus/dji-embed -i *.MP4
Advanced
Build from source with uv sync --extra dev (or pip install -e .)
Use the provided Dockerfile for custom images
Review CI scripts under .github/workflows
Features
Batch Processing: Process entire directories of DJI drone footage automatically
GPS Metadata Embedding: Embed GPS coordinates as standard metadata tags
Subtitle Track Preservation: Keep telemetry data as subtitle track for overlay viewing
Multiple Format Support: Handles different DJI SRT telemetry formats
Telemetry Export: Export flight data to JSON, GPX, CSV, GeoJSON, KML, or a standalone HTML map (see docs/geospatial.md)
Photo Map: dji-embed photomap DIR plots GPS-tagged still photos (JPG/JPEG/DNG) on a clustered HTML map (or KML/GeoJSON) with EXIF thumbnail popups — requires ExifTool
Camera Footprint Polygons: convert geojson/kml … --footprint adds nadir ground-footprint rectangles to GeoJSON/KML output (gimbal-aware on formats that carry attitude; suppressed under --redact). See docs/geospatial.md.
CoT Export: dji-embed convert cot FLIGHT.SRT writes Cursor-on-Target XML for ATAK/TAK (route + timed track). See docs/fmv-interop.md.
Footage verification:dji-embed verify-sun clip.SRT reports the sun's azimuth/elevation over a clip for shadow cross-checking; CSV export gains datetime_utc / sun_azimuth / sun_elevation columns.
DAT Flight Log Support: Merge .DAT flight logs into metadata
Cross-Platform: Works on Windows, macOS, and Linux
Progress Bar: See processing status while videos are being embedded
Supported DJI Models
Fully Tested & Documented (with sample fixtures):
DJI Mini 3/4 Pro - Square bracket format [latitude: xx.xxx] [longitude: xx.xxx]
DJI Mini 5 Pro - HTML-style bracket format with decimal aperture ([fnum: 1.8])
DJI Air 3 - HTML-style format with extended telemetry data
DJI Air 3S - HTML-style bracket format with decimal focal_len and HLG color mode ([color_md: hlg]); MP4 also carries embedded djmd/dbgi data streams
DJI Avata 360 - HTML-style bracket format with stabilization (pp_*) fields; footage ships as .OSV (360 video) + .LRF proxy
DJI Neo 2 - HTML-style bracket format with stabilization (pp_*) fields; MP4 also carries embedded djmd/dbgi data streams
DJI Avata 2 - Legacy GPS format GPS(lat,lon,alt) with BAROMETER data
DJI Mavic 3 Enterprise - Extended format with RTK precision data
DJI Matrice 300 (legacy-with-unit) - GPS(lat,lon,alt M) with BAROMETER: colon notation
DJI Phantom 4 RTK / P4P (compact single-line) - F/N, SS N, ISO N, EV N, GPS (lat, lon, alt), HOME (...), D, H, H.S, V.S, F.PRY, G.PRY
Community Supported:
DJI Air 2S, Mavic 3, and other models using similar SRT formats
Don't see your model? We're happy to add support in exchange for sample SRT files we can parse the telemetry format from. Open an issue and attach one or two raw .SRT files from your drone (a short clip is plenty), and we'll add a parser for it. See the Contributing Guide for details.
Sidecar-less models (Air 3S, Mini 5 Pro, …): telemetry is read straight from
the MP4's embedded djmd/dbgi track via ExifTool — no .SRT needed —
for dji-embed convert FILE.MP4 and dji-embed verify-sun FILE.MP4.
Requires a recent ExifTool (Air 3S ≥ 13.39, Mini 5 Pro ≥ 13.52); see
docs/MP4_TIMED_METADATA.md.
Requirements
Python 3.10 or higher
FFmpeg
ExifTool (optional, for additional metadata embedding)
Usage
If the command python is not recognized, use py instead.
Basic Usage
Process a single directory:
dji-embed embed /path/to/drone/footage
Commands
dji-embed [OPTIONS] COMMAND [ARGS]...
Commands:
embed Embed telemetry from SRT files into MP4 videos
validate Validate SRT/MP4 pairs and report drift
convert Convert SRT telemetry to GPX, CSV, GeoJSON, KML, HTML, or CoT
photomap Map GPS-tagged still photos to an HTML/KML/GeoJSON map
check Check media files for embedded metadata
doctor Show system information and verify dependencies
ui Launch the local web UI in your browser
verify-sun Summarise the sun's position over a clip for shadow cross-checking
Global Options:
--version Show the version and exit
-h, --help Show this message and exit
Web UI (optional)
Prefer a browser over the terminal? Install the [ui] extra and launch the
local UI — it runs entirely on 127.0.0.1 and uses your installed browser,
so there is no separate signed app to trust.
pip install 'dji-drone-metadata-embedder[ui]'
dji-embed ui # opens http://127.0.0.1:
dji-embed ui --no-browser # print the URL instead of opening
dji-embed ui --port 8765 # pin to a fixed port
Every tab (Doctor / Embed / Validate / Convert / Check) is a thin wrapper
over the matching CLI command. The Map tab renders a processed clip's
flight path on an interactive map (Leaflet + OpenStreetMap) with an altitude
profile and a play-the-flight scrubber — only the basemap tiles load from the
network; the flight data and all other assets stay local, and redaction is
applied server-side so exact coordinates never reach the browser when set.
Access is gated by a per-session token that is injected into the opened URL;
requests without the token return 403. Chromium-based browsers will offer
"Install app" for a standalone window.
Embed Command Options
dji-embed embed [OPTIONS] DIRECTORY
Arguments:
DIRECTORY Directory containing MP4 and SRT files
Options:
-o, --output DIRECTORY Output directory (ignored if --overwrite)
--overwrite Overwrite original video files in place
(destination = input folder)
--exiftool Also use ExifTool for GPS metadata
--dat PATH DAT flight log to merge
--dat-auto Auto-detect DAT logs matching videos
--audio-sidecar Auto-detect a same-basename .m4a audio sidecar
(e.g. DJI Neo 2) and mux it in (no re-encode)
--redact [none|drop|fuzz] Redact GPS coordinates (default: none)
--container [mp4|mkv] Output container; 'mkv' preserves DJI djmd/dbgi
data streams (default: mp4)
--extract-home Extract the drone's HOME / launch point into the
JSON sidecar. **The HOME point is the operator's
launch location** — it is off by default, never
written to the MP4, and always honours `--redact`
(`drop` removes it, `fuzz` coarsens to ~100 m).
-v, --verbose Verbose output
-q, --quiet Suppress progress output
By default, processing shows a progress bar for each file.
Use --verbose for detailed output or --quiet to reduce messages.
GPX timestamps are written in UTC. DJI SRT times are local with no timezone, so
the offset is auto-detected from the file's modification time. Override it when
the mtime is unreliable (e.g. copied files):
check uses ffprobe for QuickTime tags and exiftool for EXIF data
when available. Pass --verbose for debug output or --quiet to only
show warnings and errors.
CLI Reference
All Commands
dji-embed embed - Process Videos
Embed telemetry from SRT files into MP4 videos.
dji-embed embed [OPTIONS] DIRECTORY
Arguments:
DIRECTORY Directory containing MP4 and SRT files
Options:
-o, --output DIRECTORY Output directory (ignored if --overwrite)
--overwrite Overwrite original video files in place
(destination = input folder)
--exiftool Also use ExifTool for GPS metadata
--dat PATH DAT flight log to merge
--dat-auto Auto-detect DAT logs matching videos
--audio-sidecar Auto-detect a same-basename .m4a audio sidecar
(e.g. DJI Neo 2) and mux it in (no re-encode)
--redact [none|drop|fuzz] Redact GPS coordinates (default: none)
--container [mp4|mkv] Output container; 'mkv' preserves DJI djmd/dbgi
data streams (default: mp4)
--extract-home Extract the HOME / launch point into the JSON
sidecar; off by default, never written to the
MP4, always honours --redact
-v, --verbose Verbose output
-q, --quiet Suppress progress output
dji-embed check - Check Metadata
Check media files for existing embedded metadata.
dji-embed check [OPTIONS] [PATHS]...
Arguments:
PATHS... Files or directories to check
Options:
-v, --verbose Verbose output
-q, --quiet Suppress info output
dji-embed convert - Export Formats
Convert SRT telemetry to GPX, CSV, GeoJSON, KML, CoT, or a standalone HTML map.
dji-embed convert [OPTIONS] {gpx|csv|geojson|kml|html|cot} INPUT
Arguments:
{gpx|csv|geojson|kml|html|cot} Output format
INPUT SRT file or directory to convert
Options:
-o, --output PATH Output file path
-b, --batch Batch process directory
--tz-offset OFFSET UTC offset for GPX/CoT timestamps, e.g. '+05:30' or
'-8' ('auto' detects from file mtime; default: auto)
--redact [none|drop|fuzz] GPS redaction (default: none). drop/fuzz cover the
track for geojson/kml/html/cot and the HOME marker
in all formats; for gpx/csv only the HOME marker is
redacted (the track there is unredacted)
--interval FLOAT cot only: seconds between sampled points (default: 1.0)
--cot-type CODE cot only: CoT type/affiliation code (default: a-n-A)
--footprint geojson/kml only: add camera footprint polygons
(requires --redact none)
--footprint-interval FLOAT geojson/kml only: seconds between footprints (default: 2.0)
--model NAME footprint FOV-table entry, e.g. air3, mini4pro
--extract-home Opt-in: extract the HOME / launch point (operator
location) into gpx/csv/geojson output. Off by
default; subject to --redact
-v, --verbose Verbose output
-q, --quiet Suppress info output
HTML map example — produces a self-contained flight.html you can open in any browser:
dji-embed convert html DJI_0001.SRT # -> DJI_0001.html
dji-embed convert html DJI_0001.SRT -o flight.html
Leaflet and the basemap tiles load from the internet; the flight data itself is embedded, so the file is portable but needs a connection to render the map.
Camera footprint example — overlay per-interval ground-coverage polygons in GeoJSON/KML for down-looking footage (suppressed under --redact; see docs/geospatial.md):
Map GPS-tagged still photos (JPG/JPEG/DNG) as an HTML, KML, or GeoJSON map.
dji-embed photomap [OPTIONS] DIRECTORY
Arguments:
DIRECTORY Directory containing JPG/JPEG/DNG photos
Options:
-o, --output FILE Output file; used as the base name when
--format all
-f, --format [html|kml|geojson|all]
Map output format (default: html)
-r, --recursive Scan subdirectories too
--title TEXT Map title (default: directory name)
-v, --verbose Verbose output
-q, --quiet Suppress info output
Requires ExifTool (dji-embed doctor checks it). Photos without GPS data are
skipped and counted in a summary; -v lists the skipped filenames.
Notes:
With -r, pins are labelled by their path relative to DIRECTORY, so
per-session folders that reuse DJI's restarting DJI_0001.JPG names stay
distinct on the map.
Popup previews use the small EXIF thumbnail, falling back to a size-capped
embedded preview for DNGs that carry no thumbnail.
Photos with no EXIF altitude are clamped to the ground in KML (Google Earth)
instead of being buried at 0 m below terrain.
dji-embed photomap /path/to/photos # -> photos/photomap.html
dji-embed photomap /path/to/photos -f all # -> photos/photomap.{html,kml,geojson}
dji-embed photomap /path/to/photos -r --title "Churches of Finland" # recurse + custom title
Leaflet and the OpenStreetMap basemap tiles load from the internet; the photo
thumbnails themselves are embedded, so the HTML file is portable but needs a
connection to render the map. A photo map publishes your shooting locations —
share it deliberately.
dji-embed doctor - System Diagnostics
Show system information and verify all dependencies.
dji-embed doctor
No arguments or options required.