Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions mapillary_tools/geotag/video_extractors/gpx.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,16 @@ def extract(self) -> types.VideoMetadata:
points=gpx_points,
)

clock: VideoClock | None = None
if self.sync_mode is not SyncMode.REBASE:
clock = self._read_video_clock(native_video_metadata.points)

if clock is not None and gpx_points:
clock = self._read_video_clock(native_video_metadata.points)

if clock is not None and gpx_points and self.sync_mode is SyncMode.REBASE:
# The GPX is placed to start with the video, and runs on at the rate
# of the video's GPS clock, which in a timelapse packs several GPS
# seconds into each second of video
clock = VideoClock(
video_time=0.0, unix_time=gpx_points[0].time, rate=clock.rate
)
elif clock is not None and gpx_points:
offset = gpx_points[0].time - clock.to_unix_time(0)
if abs(offset) > _IMPLAUSIBLE_OFFSET_SECONDS:
if noisy and self.sync_mode is SyncMode.SYNC:
Expand Down Expand Up @@ -265,8 +270,9 @@ def _check_coverage(
Without the duration of the video, the video is known only up to its
last GPS point, and a track that starts after it may still overlap the
video. Then a gap only warns, unless it is too large for any clock or
time zone mistake to explain. A track assumed to start with the video
has no clock to say that it misses the video, so it only warns.
time zone mistake to explain. A track assumed to start with the video,
or said to by --interpolation_use_gpx_start_time, has no clock to say
that it misses the video, so it only warns.
"""
if not gpx_points or gpx_unix_times is None:
return
Expand Down Expand Up @@ -307,8 +313,10 @@ def _check_coverage(
"time zone of the GPX timestamps"
)

if clock is not None and (
video_duration is not None or _IMPLAUSIBLE_OFFSET_SECONDS < gap
if (
clock is not None
and self.sync_mode is not SyncMode.REBASE
and (video_duration is not None or _IMPLAUSIBLE_OFFSET_SECONDS < gap)
):
raise exceptions.MapillaryOutsideGPXTrackError(
message,
Expand Down
35 changes: 32 additions & 3 deletions tests/unit/test_gpx_video_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
SourceType,
VideoSyncOption,
)
from mapillary_tools.geotag.video_extractors.gpx import GPXVideoExtractor
from mapillary_tools.geotag.video_extractors.gpx import GPXVideoExtractor, SyncMode
from mapillary_tools.mp4 import construct_mp4_parser as cparser, simple_mp4_builder


Expand Down Expand Up @@ -321,12 +321,12 @@ class TestTimelapse:
# 11 seconds of video spanning 165 seconds of GPS time
RATE = 15.0

def _extract(self, tmp_path, gpx_start: float, gpx_seconds: float):
def _extract(self, tmp_path, gpx_start: float, gpx_seconds: float, **kwargs):
video_path = _write_camm_mp4(
tmp_path / "timelapse.mp4", _video_track(self.RATE), duration=11.0
)
gpx_path = _write_gpx(tmp_path / "track.gpx", gpx_start, gpx_seconds)
return GPXVideoExtractor(video_path, gpx_path).extract()
return GPXVideoExtractor(video_path, gpx_path, **kwargs).extract()

def test_gpx_of_the_whole_recording_is_silent(self, tmp_path, caplog):
"""At 1x, the track would run on 154 seconds past the video's end."""
Expand All @@ -349,6 +349,35 @@ def test_gap_is_reported_in_gps_time(self, tmp_path):
self._extract(tmp_path, recording_end + 3600, 60)
assert "by 1.0 hours." in str(info.value)

def test_gpx_start_time_keeps_the_rate(self, tmp_path, caplog):
"""
--interpolation_use_gpx_start_time starts the track with the video,
whatever the clock says, and the clock still sets its pace
"""
with caplog.at_level(logging.WARNING):
metadata = self._extract(
tmp_path, A_UNIX_TIME + 3600, 11 * self.RATE, sync_mode=SyncMode.REBASE
)
assert not _warnings(caplog)
assert metadata.points[0].time == 0
assert metadata.points[-1].time == pytest.approx(11.0, abs=1e-3)

def test_gpx_start_time_only_warns_of_a_miss(self, tmp_path, caplog):
"""
Nor does the clock say that a track started with the video misses it,
even when the interpolation offset moves it off the video.
"""
with caplog.at_level(logging.WARNING):
self._extract(
tmp_path,
A_UNIX_TIME,
60,
sync_mode=SyncMode.REBASE,
video_sync=VideoSyncOption(offset_time=3600),
)
[warning] = _warnings(caplog)
assert "misses the video" in warning


class TestVideoWithoutGPSClock:
"""
Expand Down
Loading