Repository navigation
Warn in process of a GPX track far longer than the video it is assumed to start with - #861
Merged
Merged
Conversation
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.
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.
It said that a GPX works with interval sampling only, which has not been true since distance sampling honours --geotag_source, and that the start time of a video is always read from its GPS or its creation time, which distance sampling does not do. It now says how each kind of video is placed along a GPX, that --video_start_time applies to every video in a command, so one GPX serves several videos run one at a time, how --video_duration_ratio paces a timelapse without a GPS clock, and what to pass instead of --interpolation_use_gpx_start_time for a GPS logger left running. The examples sample one video, and the --interpolation_use_gpx_start_time one drops the interval sampling options it no longer needs.
Interval sampling mapped every video stream of a video to one output, and ffmpeg numbers the frames of all of them in one sequence. A GoPro MAX .360 video has two video streams, so its frames came out interleaved, and frame i, taken at (i - 1) // 2 intervals, was stamped (i - 1) intervals into the video. Half of them were stamped past its end. On a 5-minute .360 video sampled every second, the frames that could be geotagged were placed a median of 73 m from where they were taken, and the other half failed. Interval sampling now samples the video stream with the highest resolution, as distance sampling does. A video with a single video stream, which is nearly every video, is sampled as before and its samples keep their names.
When a video's GPS is rejected as noise, the GPX is still synced by the clock of its unfiltered points, unless that clock is more than a day from the GPX: GoPro stamps a placeholder date (2015-10-22 and similar) until it acquires GPS time. Judged against the GPX, though, the clock took the blame for a GPX that does not belong to the video. A GoPro HERO8 clip whose noisy clock is real, given a GPX from another day, had that track placed from its first frame, and process exited 0, while the same GPX on a video with good GPS is rejected for missing it. A noisy clock that starts within a day of the mvhd creation time of the video is now taken as real, and places the GPX as for any video with GPS, so a GPX that misses the video raises MapillaryOutsideGPXTrackError. A day absorbs a creation time written in local time (GoPro) and whether it marks the start or the end of the recording. A clock is still a placeholder only when it is more than a day from the GPX too: some cameras write a creation time that means nothing next to a real GPS clock (a GoPro HERO10 recorded in 2022 reports 2016-01-01), and a GPX that agrees with the clock keeps it, as before. Without a readable creation time, nothing changes. The creation time is read by the same function that decides the CAMM GPS epoch.
A GPX is synced to a video by the video's GPS clock, which was anchored at its first timestamp. That one can be off the rest: the first GPS block of a GoPro timelapse can be stamped 3 s early, the PanoX V2 can record a stale first fix 2 s old, and GoPro stamps a placeholder date until it acquires GPS time. The whole GPX then lands that much early or late. The clock is now anchored, still at the video time of its first timestamp, at the median of all its timestamps mapped back to that time at the clock's rate. Syncing the tracks of 17 sample videos back to them, the median error drops from 0.63 to 0.02 s and from 0.81 to 0.02 s on two GoPro MAX videos, from 2.2 to 0.02 s on the PanoX V2, and to 0.011 s or less on the GoPro timelapses. No median gets worse by more than 4 ms. A noisy GoPro video whose clock starts on the placeholder date is now synced by its clock, not from the start of the video.
Distance sampling keeps frames up to 1 ms of video past either end of the GPS track, and extrapolates their timestamps. In a timelapse, 1 ms of video spans as many ms of GPS time as the video is faster than real time, so such a frame was stamped up to that far past the end of a GPX track. The geotagging stage allows a frame only 1 ms past it, so the frame failed, video_process exited with an error, and video_process_and_upload uploaded nothing. On a 30x GoPro MAX timelapse whose GPX ends with its last frame, the frame came out 23 ms past the end. Those frames are now stamped at the first or last timestamp of the track.
process uploaded a video geotagged from a GPX with the whole GPX track. Its points before the start of the video were dropped when the CAMM track was built, which left the frames before the first point inside the video without a position. Its points after the end of the video were uploaded as they were, although a GPX of a longer trip can run on for an hour past a clip of a few minutes. None of those points is the position of a frame of the video. When the GPS clock of the video placed the track, so that it is known where the video ends along it, GPXVideoExtractor now clips it to the video, from 0 to the mvhd duration, with a point interpolated at either end that the track runs past. Only process asks for that: sampling reads the track only within the video. A track that is only assumed to start with the video, or said to by --interpolation_use_gpx_start_time, is left as it is. It may be the track of a timelapse without a GPS clock, which runs on past the end of the video at the pace of the GPS clock, and nothing says where the video ends along it.
The previous commit clips a GPX track whenever a clock gives its pace along the video, so that where the video ends along it is known. Since the GPS clock's rate is kept for --interpolation_use_gpx_start_time (mapillary#853), that includes a track the option starts with the video: it is clipped as any other, and a GPS logger left running past the end of the video uploads only the part of the track that the video covers. Say so in the docstrings, which said a clock had to place the track, and test it among the tracks a clock paces.
…d to start with For a video without a GPS clock, process assumes that the GPX track starts with the video. Sampling refuses a track that runs on for longer than the whole video, as the video could then start anywhere along it, and asks for --video_start_time. process went on silently: every clip of a drive geotagged from one GPX of the whole drive was placed on its first minutes, and uploaded with the rest of the track. process now warns of such a track, and says how to place the video. It only warns, as the track of a timelapse without a GPS clock runs on past the end of the video too.
caglarpir
force-pushed
the
warn-long-gpx-in-process
branch
from
October 22, 2026 09:04
6d1257e to
ac4de53
Compare
This was referenced Oct 22, 2026
caglarpir
added a commit
that referenced
this pull request
Oct 24, 2026
The README geotags a video stitched by Insta360 Studio by the original it was stitched from, through an exiftool_runtime pattern. The track read from the original is placed from the start of the stitched video, as a GPX track without a clock to sync it by is assumed to start with the video. Of a timelapse it lasts far longer than the video: an Insta360 ONE X original holds 110 seconds of GPS for a stitched timelapse of 1.77 seconds. process geotagged such a video with exit 0 and no word, where it warns of a GPX track that lasts more than twice as long as the video assumed to start with it (#861). Run the same check on a track read from a file that the pattern names other than the video, and warn the same way: "The GPS track in ... lasts 1.8 minutes and the video ... only 1.77 seconds, so the video could start anywhere along the track, and is assumed to start with it. Unless the video is a timelapse of the whole track, check that the exiftool_runtime pattern names the file that the video was made from". Only warn, as for a GPX track, since the track of a timelapse runs on past its end. The GPX warning is the one it was. Checked on Insta360 ONE X, X3 and X5 videos with their originals: the ONE X timelapse and an X5 video, whose original holds 13 minutes of GPS for 1.3 minutes of stitched video, warn, in process and video_process; X3 videos and timelapses whose originals match them do not. The descriptions do not change. Nor do the warnings and descriptions of exiftool_runtime without a pattern or with %f, on videos, images and a folder of both, nor those of GPX tracks.
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
For a video without a GPS clock,
processassumes that the GPX track starts with the video. Sampling refuses a track that runs on for longer than the whole video, as the video could then start anywhere along it, and asks for--video_start_time.processwent on silently: every clip of a drive geotagged from one GPX of the whole drive was placed on the first minutes of the drive, and uploaded with the rest of the track.Fix
processwarns of a track assumed to start with the video that lasts more than twice as long as the video, the same limit at which sampling refuses one. The warning says to trim the GPX to the video, or to sample the video withvideo_processand--video_start_time.It only warns, and the video is geotagged as before: the track of a timelapse without a GPS clock runs on past the end of the video too. A track placed by the GPS clock of the video, or said to start with it by
--interpolation_use_gpx_start_time, gets no warning.Verification
processandvideo_processgive the same descriptions and byte-identical frames as without this PR on the test data.Merge notes
test_process_still_assumes_the_track_starts_with_the_videochecked thatprocessgets no timelapse advice by looking for the word "timelapse", which this warning contains. It now looks for--video_duration_ratio, whichprocessdoesn't have.--interpolation_offset_timeplace such a video along the track. Once both land, the warning could name it as a third way, and could skip a track that the offset placed.