Skip to main content

gps-video-sync

Align action-camera telemetry with an IGC flight track. The tool calculates a video-to-UTC offset, checks clock drift, and plots the alignment. It uses camera GPS time when available and falls back to motion matching.

My GoPro clock often has the wrong date or time. I use this tool to align the video with the GPS track after recording.

Install

Requires Python 3.10 or later. Tests cover Python 3.10 to 3.15.

pip install gps-video-sync
pip install "gps-video-sync[verify]"

From a source checkout, run pip install . or pip install ".[verify]".

The verify extra installs Matplotlib for plots. Frame extraction also needs ffmpeg on PATH. GoPro MP4 and LRV extraction needs no external program.

Align recordings

Match one or more recordings against one flight track:

gps-video-sync sync takeoff.MP4 ridge.MP4 landing.MP4 --track flight.igc --json sync.json

Recordings can have gaps, overlap, or come from different cameras. You can give them in any order. Unrelated recordings keep their independent results.

The tool detects continuous chapters from sensor-clock junctions and exact cumulative sample counters inside the files. Names do not establish continuity. Confirmed chapters share one alignment, so a short chapter can use motion or GPS evidence from its neighbours. Each chapter keeps its own result and local timeline. Adjacent chapter boundaries are exactly equal, including clock drift. A subset of a continuous recording can give a different alignment.

The tool first matches each file independently. A branch, a failed group solve, a new GPS time step, or a contradiction with an accepted independent mapping keeps the independent results. Missing continuity evidence also keeps files independent. Each result has a shot object with single, joined, or ambiguous status. Only joined means that a shared alignment was applied.

The output uses schema 2.0.0 with a videos list, even for one input. The list has one entry per input, in input order. Each entry has its own status, offset, drift, and confidence data. A failed or ambiguous recording does not stop the others.

Give each recording only once. A repeated path, including a symbolic link to the same file, fails at each later position. An input with the same recording identity and timeline as an earlier ok or ambiguous result also fails as a duplicate. For example, two exports of the same telemetry are duplicates.

To inspect one recording or check its saved alignment:

gps-video-sync info ridge.MP4
gps-video-sync telemetry ridge.MP4 --out ridge.npz
gps-video-sync verify ridge.MP4 --track flight.igc \
  --result sync.json --output ridge.png --frames 10 120

info, telemetry, and verify each accept exactly one recording. Their times are local to that file and start at zero. --frames values must be 0 or more and less than the recording duration. verify selects the entry in the saved result that has the same recording identity and local timeline. It draws a plot only for an ok result. Run gps-video-sync COMMAND --help for all options.

Exit codes for sync and verify:

  • 0: all matches are ok.
  • 2: at least one match is ambiguous and no match is failed. An ambiguous result has no usable offset.
  • 1: at least one match is failed, or an input or run error occurs. Invalid command-line arguments also give 1.

sync writes all per-file results before it returns a failure exit code.

Results, info output, telemetry exports, and cache files contain absolute recording paths. Paths can show user names and directory names. Exports and cache files can also contain camera GPS times and serial numbers. Results contain recording dates and times. Remove this data before you share these files.

Use the Python API

from gps_video_sync import match_videos, read_track, read_video, synchronize

track = read_track("flight.igc")
results = match_videos(track, ["takeoff.MP4", "ridge.MP4", "landing.MP4"])
for result in results:
    print(result.video, result.status, result.offset_seconds)

telemetry = read_video("ridge.MP4", hz=10)
result = synchronize(track, telemetry)

match_videos returns one result per input, in input order. It applies shared alignment only to confirmed continuous chapters. A file error gives a failed result for that file only. read_video reads one recording. synchronize matches one recording and also accepts array-based Telemetry.

To match exported telemetry, use source="npz" in the API or --source npz in the CLI. NPZ exports from telemetry --out keep the original recording identity, duration, media offset, and optional continuity evidence. Telemetry.slice clears continuity evidence. In a batch result, input_file identifies the NPZ archive.

The result maps video seconds to UTC seconds from midnight of the track date:

utc_seconds = video_seconds * clockRate + offset_seconds

Supported cameras

The bundled test recordings are from a GoPro HERO11 Black. They test motion alignment but contain no GPS data. GPS extraction and alignment have synthetic tests only. GoPro documents compatible metadata for the other models below, but this package has no recordings from them. Their extraction, alignment, and frame verification are untested.

The reader needs a timed GPMF track with sample format gpmd in the original video. It uses these fields:

  • GPS9 supplies UTC and fix status for GPS alignment. The older GPS5 format needs GPSU for UTC and GPSF for fix status. The reader accepts only valid 3D fixes. GPS9 takes priority when both formats occur in a packet.
  • GYRO and ACCL supply the motion features. Motion alignment works without camera GPS, within the limits below.
  • The reader also extracts GRAV, CORI, and IORI when present. Alignment does not need these fields. The matcher estimates gravity from ACCL.
Camera GPS metadata for UTC alignment GYRO + ACCL GRAV + CORI + IORI Compatibility / test status
HERO5 Black GPS5 + GPSU + GPSF Yes Not documented GPS and motion expected; untested
HERO5 Session None Yes Not documented Motion only expected; untested
HERO6 Black GPS5 + GPSU + GPSF Yes Not documented GPS and motion expected; untested
HERO7 Black GPS5 + GPSU + GPSF Yes Not documented GPS and motion expected; untested
HERO8 Black GPS5 + GPSU + GPSF Yes Yes GPS and motion expected; untested
HERO9 Black GPS5 + GPSU + GPSF Yes Yes GPS and motion expected; untested
HERO10 Black GPS5 + GPSU + GPSF Yes Yes GPS and motion expected; untested
HERO10 Black Bones None Yes Yes Motion only expected; untested
HERO11 Black GPS9, plus legacy GPS5 Yes Yes Motion tested with bundled recordings; GPS untested
HERO12 Black None Yes Yes Motion only expected; untested
HERO13 Black GPS9 Yes Yes GPS and motion expected; untested
Fusion Not documented in the cited table Yes Not documented Motion metadata compatible; 360 workflow untested
MAX GPS5 + GPSU + GPSF Yes Yes Metadata compatible; 360 workflow untested
MAX2 GPS9 Yes Yes Metadata compatible; 360 workflow untested
MISSION 1 family GPS9 Yes Yes Metadata compatible per GoPro; untested

Use original, normal-speed recordings. Enable GPS on cameras that have it and wait for a satellite lock before you record. Some clips can still lack usable fixes. Edited, transcoded, or stitched exports can omit the metadata track. Check each recording with gps-video-sync info.

The 360 camera rows cover sensor metadata only. Stitching, projection, and frame extraction from native 360 files are untested.

The table does not cover Silver, White, Mini, or entry-level HERO models, HERO4 and earlier cameras, external GPS accessories, or special recording modes. A model number or GPS chip alone does not establish compatibility.

Sources:

Firmware and recording mode can change the available streams. The reader checks for metadata keys, not camera model names.

Limits

GoPro extraction allows at most 1,000,000 resampled samples per recording. Lower --hz if the recording duration in seconds multiplied by --hz exceeds this limit.

Motion matching needs at least 90 seconds of usable overlap. The overlap must also cover at least 65% of the shorter feature sequence. Each independent file or confirmed continuous group needs enough varying motion. Repeated turns, data gaps, or low motion can produce ambiguous or false matches. Check the plot and distinctive events before you use an alignment. Short clips cannot establish clock stability.

See the API and format reference for data contracts, plugins, telemetry formats, and matching limits.

Run the tests

pip install -e '.[dev,verify]'
python -m pytest
python scripts/check_independent_videos.py
python scripts/check_continuous_videos.py

Run the tests from a repository checkout. Release archives exclude tests and fixtures. The bundled fixtures contain flight coordinates, times, and media.

  • Extraction and alignment tests need no external program.
  • Parity tests use the ffprobe marker and need ffprobe 9 or later.
  • Frame tests need ffmpeg and Matplotlib.
  • To skip integration tests, run python -m pytest -m 'not integration'.

scripts/check_continuous_videos.py needs the verify extra and ffmpeg. It runs the API and the CLI on the bundled recordings with cold and warm caches. It checks exact boundaries, reordered inputs, subsets, weak chapters, non-unit drift, gaps, overlaps, counters, contradictory fits, and failures. It also checks cache rebuilds, NPZ and JSON exports, crops, saved-result selection, plots, and frames against direct FFmpeg seeks.

scripts/check_independent_videos.py checks independent motion crops and GPS recordings with gaps, overlaps, shuffled inputs, and isolated failures. It also checks exports and file-local frame extraction on the bundled videos.

License

MIT.

Metadata

Release files for gps-video-sync 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gps-video-sync 1.0.0
File Size Uploaded Provenance
gps_video_sync-1.0.0.tar.gz 43.2 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for gps-video-sync 1.0.0
File Interpreter ABI Platform
gps_video_sync-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 81.8 kB

Release files / gps_video_sync-1.0.0.tar.gz

Download URL gps_video_sync-1.0.0.tar.gz
Size 43.2 kB
Tags Source
SHA-256 checksum
How to use checksums
d5da9612eef44a56be954a54b332b5265e2a87fba0d377c54c490b36c1a8d896
BLAKE2b-256 checksum
How to use checksums
372d52483848ef669e44c9266c10ed054962dfa278a6de55a4512b1f497d2a5a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Release files / gps_video_sync-1.0.0-py3-none-any.whl

Download URL gps_video_sync-1.0.0-py3-none-any.whl
Size 38.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8163f148161928f16d295d69d42b170508b189c12f35f46941621b3ee70d94b2
BLAKE2b-256 checksum
How to use checksums
1ce4d3e765f9ee83e00340d647ba06dbed697063f477934c712054924eccc288
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

Security for gps-video-sync 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for gps_video_sync-1.0.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page