diff --git a/mapillary_tools/exiftool_read_video.py b/mapillary_tools/exiftool_read_video.py index 66d0d0ad..4257abca 100644 --- a/mapillary_tools/exiftool_read_video.py +++ b/mapillary_tools/exiftool_read_video.py @@ -156,7 +156,12 @@ def _aggregate_epoch_times( or [] ) ] - if len(gps_epoch_times) != expected_length: + if len(gps_epoch_times) == 1 and expected_length > 1: + # Some cameras (e.g. GoPro MAX) store a single GPSDateTime per sample + # shared across all the GPS coordinates in that sample. Broadcast the + # single epoch time to every coordinate to match the native parser. + gps_epoch_times = gps_epoch_times * expected_length + elif len(gps_epoch_times) != expected_length: LOG.warning( "Found different number of GPS epoch times %d and coordinates %d", len(gps_epoch_times), diff --git a/tests/unit/test_exiftool_read_video.py b/tests/unit/test_exiftool_read_video.py index b5890b42..fe8c88a0 100644 --- a/tests/unit/test_exiftool_read_video.py +++ b/tests/unit/test_exiftool_read_video.py @@ -516,6 +516,33 @@ def test_ground_speed_tag(self): assert len(track) == 1 assert track[0].ground_speed == pytest.approx(52.7561) + def test_single_gps_time_tag_is_broadcast_to_all_points(self): + # Some cameras (e.g. GoPro MAX) store a single GPSDateTime per sample + # shared across all the GPS coordinates in that sample. The single epoch + # time should be broadcast to every coordinate. + texts = { + expand_tag("QuickTime:GPSLongitude"): ["28.0", "29.0"], + expand_tag("QuickTime:GPSLatitude"): ["37.0", "38.0"], + expand_tag("QuickTime:GPSDateTime"): [ + "2019:09:02 10:00:00Z", + "2019:09:02 10:00:01Z", + ], + expand_tag("QuickTime:GPSTimeStamp"): [ + "2019:09:02 10:00:10Z", + ], + } + track = _aggregate_gps_track( + texts, + time_tag="QuickTime:GPSDateTime", + lon_tag="QuickTime:GPSLongitude", + lat_tag="QuickTime:GPSLatitude", + gps_time_tag="QuickTime:GPSTimeStamp", + ) + assert len(track) == 2 + # 2019:09:02 10:00:10Z broadcast to both points + for p in track: + assert p.epoch_time == pytest.approx(1567418410.0) + def test_gps_time_tag_length_mismatch_falls_back_to_none(self): texts = { expand_tag("QuickTime:GPSLongitude"): ["28.0", "29.0"], @@ -526,6 +553,8 @@ def test_gps_time_tag_length_mismatch_falls_back_to_none(self): ], expand_tag("QuickTime:GPSTimeStamp"): [ "2019:09:02 10:00:10Z", + "2019:09:02 10:00:11Z", + "2019:09:02 10:00:12Z", ], } track = _aggregate_gps_track( @@ -536,7 +565,7 @@ def test_gps_time_tag_length_mismatch_falls_back_to_none(self): gps_time_tag="QuickTime:GPSTimeStamp", ) assert len(track) == 2 - # Mismatch in gps_time_tag length: epoch_time falls back to None + # Genuine mismatch (3 vs 2) in gps_time_tag length: epoch_time falls back to None for p in track: assert p.epoch_time is None