Repository navigation
Sync a GPX to a video without a GPS clock at --video_duration_ratio - #856
Merged
caglarpir merged 5 commits intoOct 22, 2026
Merged
Conversation
caglarpir
force-pushed
the
video-duration-ratio-for-gpx
branch
from
October 21, 2026 09:33
cca910e to
e2daccb
Compare
Interval sampling stamped each frame with the start time of the video plus its time in the video. A timelapse packs several seconds of capture into each second of video, so its frames were stamped that many times too close together. Geotagged from a GPX by those stamps, they all landed near the start of the track. Geotagged from the video's own track, they moved so far per second that the speed check could reject them: a 30x timelapse of a drive read as over 1,000 km/h. Interval sampling now reads the rate from the video's GPS clock, as GPX sync does, and stamps the frames at it. The start time is mapped back from the first GPS timestamps at the same rate. --video_duration_ratio, which used to apply to every video, now paces only the videos without a GPS clock, so that a ratio given for those leaves the other videos in the batch alone. Each video whose clock overrides a given ratio says so in a warning. The samples are then geotagged from the video's own track (the gopro, camm and blackvue sources) by their time since the first sample, while the track is timed in video seconds. It is now timed in GPS seconds, at the rate of its clock. That also fixes distance samples of a timelapse, which were already stamped with their capture times.
caglarpir
force-pushed
the
video-duration-ratio-for-gpx
branch
from
October 21, 2026 09:44
e2daccb to
7790ea2
Compare
This was referenced Oct 21, 2026
caglarpir
force-pushed
the
video-duration-ratio-for-gpx
branch
from
October 21, 2026 11:49
7790ea2 to
d824d72
Compare
caglarpir
force-pushed
the
video-duration-ratio-for-gpx
branch
from
October 21, 2026 12:03
d824d72 to
4f69382
Compare
The previous commit timed the GPS points of a timelapse at one rate from
its first timestamp. Distance samples are stamped with the GPS time of
their video time instead, and the first timestamp of a GoPro MAX
timelapse can be about 3 s early: in one, the camera moved 6 m at 8 m/s
in the 3.9 s to the next one. On two such timelapses (30x and 15x), the
frames that geotagged were placed a median of 36 m and 5 m from where
the sampler picked them, and the last 2 and 1 frames were stamped past
the end of the track:
The image time is 1.801 seconds beyond the GPX end point
Time the track by the timestamps, interpolated between them and
extrapolated beyond them at the clock's rate. Stamp interval samples of
a timelapse the same way, from the GPS time at video time 0, as distance
samples are.
On those two timelapses, distance samples now all geotag where they
were picked. Interval samples (0.5 s) stay where they were with
--geotag_source gopro, and with a GPX of the same track they move from
a median of 0.6 m and 0.04 m (4.4 m and 1.4 m at most) to within 1 cm.
Videos without a timelapse clock are unchanged.
--interpolation_use_gpx_start_time places the GPX from the start of the video instead of by the video's GPS clock. It skipped reading the clock altogether, and with it the clock's rate, so a timelapse got its GPX laid out at 1x: a 5 s, 30x timelapse got 157 s of GPX, and distance sampling picked 5 frames along its first 12 m instead of 148 along the 1.4 km route. The clock is now read in that mode too, and placed at the start of the GPX, so that only its rate is used. A video that is not a timelapse has a rate of 1, and is placed as before. The coverage check still sees such a track as one that no clock placed: the clock gave it only its pace.
A timelapse packs several seconds of capture into each second of video. With a GPS clock of its own, a GPX is synced at the clock's rate. Without one, nothing in the video tells the rate, and the GPX was laid out at 1x, so the frames got only the start of the track: an Insta360 ONE X timelapse, 1.8 s of video with a 110 s GPX, gave 1 frame. --video_duration_ratio, the seconds of real time per second of video, used to apply to interval sampling only, and was marked deprecated. It now paces the GPX of a video without a GPS clock in distance sampling too, whether the GPX is placed by --video_start_time, by --interpolation_use_gpx_start_time or by assuming that it starts with the video. The GPS clock of a video, if it has one, still wins, and says so in a warning when it overrides a ratio. The ratio is required where a track runs on long after the video and nothing else accounts for it. Without a start time, a track more than twice as long as the video was already refused; it is now measured against the time the video spans at the ratio, and the error names the ratio. With --interpolation_use_gpx_start_time, such a track is now refused as well, in interval sampling too: the video is a timelapse, or the track was left running after it or covers more than this video. For a track of less than a day, which may be a GPS logger left running, the error gives the start of the track to pass as --video_start_time instead, which places the video the same way. A longer track is a log of several trips, which that would put the video on the first of: the error asks for the time the video started. With --video_start_time nothing is required, so that one GPX can serve many videos, each placed by its start time. The ratio divides GPS time now, so one that is not positive is rejected. process is unchanged.
The previous commit checks a GPX that --interpolation_use_gpx_start_time
says started with a video without a GPS clock. Interval sampling reads
the clock from the video's telemetry, which is empty when its GPS is
rejected as noise. GPX sync reads the clock from that GPS all the same,
and syncs the GPX at that clock's pace, as in process and in distance
sampling. So a 1.24 s GoPro MAX 2 clip with noisy GPS and a 12x clock,
which main samples with its 12 s GPX, was refused:
The GPX track in GS018205.360.gpx lasts 12 seconds and the video only
1.24 seconds, so it runs on long after the video ends.
Skip the check when GPX sync reads a clock from the video. The clip
samples as on main again.
caglarpir
force-pushed
the
video-duration-ratio-for-gpx
branch
from
October 22, 2026 09:04
726482b to
049fc4c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A timelapse packs several seconds of capture into each second of video. Without a GPS clock of its own, nothing in the video tells how many, and its GPX is laid out at 1x, so the frames get only the start of the track. An Insta360 ONE X timelapse stitched by Insta360 Studio (1.8 s of video, 110 s GPX) gives 1 frame with
--interpolation_use_gpx_start_time, the option the current error suggests.Changes
--video_duration_ratio(real seconds per video second) used to apply to interval sampling only, and was marked deprecated. It now also paces the GPX of a video without a GPS clock in distance sampling, however the GPX is placed: by--video_start_time, by--interpolation_use_gpx_start_time, or by assuming it starts with the video. A video's own GPS clock still wins, and logs a warning when it overrides a given ratio.--interpolation_use_gpx_start_time, such a track is now refused too (MapillaryGPXVideoStartUnknownError), in interval sampling as well. Interval sampling checks it only for a video that GPX sync reads no GPS clock from: GPS rejected as noise still has one, which the GPX is synced at the pace of. The error suggests the ratio for a timelapse. For a track of less than a day, which may be a GPS logger left running after the video, it prints the start of the track to pass as--video_start_timeinstead, which places the video the same way. A longer track is a log of several trips, so the error only asks for the time the video started: for a dashcam clip with a 208-day GPX, the start of the track would put it on a drive 9 months earlier.--video_start_time, nothing is required, so one GPX can serve many videos.ZeroDivisionError).processis unchanged.Behaviour change
--interpolation_use_gpx_start_timewith a GPX more than twice as long as a video without a GPS clock used to be accepted, with the frames along the start of the track. That includes a GPS logger left running after the video. It is now refused, and the error prints the--video_start_timeto use instead: for the 5.76 ssample-5s.mp4with a 60 s GPX, pasting it gives the same 18 frames that main gives. The integration test for the README's example now uses a GPX that ends with the video, and a new one checks the refusal.Verification
The ONE X timelapse with its GPX:
--interpolation_use_gpx_start_time--video_duration_ratio 60--video_start_time,--video_duration_ratio 60--interpolation_use_gpx_start_time--video_duration_ratio 60A 1.24 s GoPro MAX 2 clip whose GPS is rejected as noise, with a 12x GPS clock and a 12 s GPX, sampled by interval with
--interpolation_use_gpx_start_time: the same 2 frames as main.Normal-speed videos (GoPro HERO7 and HERO8, BlackVue, Insta360 Pro) give output identical to main. Unit: 937 passed, 18 skipped, 1 xfailed. Integration: 70 passed. Doctests,
mypy,ruff check,ruff format --checkandusort diffare clean.With #851:
VideoSyncOptionkeepsstart_timeandduration_ratio, and the interval check readsuse_gpx_start_timefrom each GPX source'sinterpolation, passing it on toGPXVideoExtractor.