From 18262b2a742567984130f38e94d19b82ff4e005c Mon Sep 17 00:00:00 2001 From: Tao Peng Date: Tue, 1 Apr 2025 10:52:28 -0700 Subject: [PATCH 1/2] fix: handle non-gopro cameras using gpmd --- mapillary_tools/geotag/geotag_from_generic.py | 4 ++-- mapillary_tools/gpmf/gpmf_parser.py | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/mapillary_tools/geotag/geotag_from_generic.py b/mapillary_tools/geotag/geotag_from_generic.py index 90930a2c2..6d9f7e89b 100644 --- a/mapillary_tools/geotag/geotag_from_generic.py +++ b/mapillary_tools/geotag/geotag_from_generic.py @@ -34,7 +34,7 @@ class GeotagImagesFromGeneric(abc.ABC, T.Generic[TImageExtractor]): """ def __init__( - self, image_paths: T.Sequence[Path], num_processes: int | None + self, image_paths: T.Sequence[Path], num_processes: int | None = None ) -> None: self.image_paths = image_paths self.num_processes = num_processes @@ -109,7 +109,7 @@ class GeotagVideosFromGeneric(abc.ABC, T.Generic[TVideoExtractor]): """ def __init__( - self, video_paths: T.Sequence[Path], num_processes: int | None + self, video_paths: T.Sequence[Path], num_processes: int | None = None ) -> None: self.video_paths = video_paths self.num_processes = num_processes diff --git a/mapillary_tools/gpmf/gpmf_parser.py b/mapillary_tools/gpmf/gpmf_parser.py index 21abd5f98..dd0857acc 100644 --- a/mapillary_tools/gpmf/gpmf_parser.py +++ b/mapillary_tools/gpmf/gpmf_parser.py @@ -166,7 +166,7 @@ def extract_gopro_info( gyros_by_dvid = None magns_by_dvid = None - _load_telemetry_from_samples( + device_found = _load_telemetry_from_samples( fp, gpmd_samples, points_by_dvid=points_by_dvid, @@ -175,6 +175,10 @@ def extract_gopro_info( magns_by_dvid=magns_by_dvid, dvnm_by_dvid=dvnm_by_dvid, ) + # If no device found, it's likely some other cameras using + # the "gpmd" container format, e.g. VANTRUE N2S 4K Dashcam + if not device_found: + return None gopro_info = GoProInfo() @@ -595,13 +599,19 @@ def _load_telemetry_from_samples( gyros_by_dvid: dict[int, list[telemetry.GyroscopeData]] | None = None, magns_by_dvid: dict[int, list[telemetry.MagnetometerData]] | None = None, dvnm_by_dvid: dict[int, bytes] | None = None, -) -> None: +) -> bool: + device_found: bool = False + for sample, sample_data in _iterate_read_sample_data(fp, samples): - gpmf_sample_data = T.cast(T.Dict, GPMFSampleData.parse(sample_data)) + try: + gpmf_sample_data = T.cast(T.Dict, GPMFSampleData.parse(sample_data)) + except C.ConstructError: + continue # iterate devices devices = (klv for klv in gpmf_sample_data if klv["key"] == b"DEVC") for device in devices: + device_found = True device_id = _find_first_device_id(device["data"]) if dvnm_by_dvid is not None: @@ -667,6 +677,8 @@ def _load_telemetry_from_samples( for idx, (z, x, y, *_) in enumerate(sample_magns) ) + return device_found + def _is_gpmd_description(description: T.Dict) -> bool: return description["format"] == b"gpmd" From 66f24fb79c73d07b11983df78bef5f9984e48dcc Mon Sep 17 00:00:00 2001 From: Tao Peng Date: Tue, 1 Apr 2025 10:54:56 -0700 Subject: [PATCH 2/2] fix --- mapillary_tools/gpmf/gpmf_parser.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mapillary_tools/gpmf/gpmf_parser.py b/mapillary_tools/gpmf/gpmf_parser.py index dd0857acc..f3ff4ed4d 100644 --- a/mapillary_tools/gpmf/gpmf_parser.py +++ b/mapillary_tools/gpmf/gpmf_parser.py @@ -219,7 +219,11 @@ def extract_camera_model(fp: T.BinaryIO) -> str: if _contains_gpmd_description(track): gpmd_samples = _filter_gpmd_samples(track) dvnm_by_dvid: dict[int, bytes] = {} - _load_telemetry_from_samples(fp, gpmd_samples, dvnm_by_dvid=dvnm_by_dvid) + device_found = _load_telemetry_from_samples( + fp, gpmd_samples, dvnm_by_dvid=dvnm_by_dvid + ) + if not device_found: + return "" return _extract_camera_model_from_devices(dvnm_by_dvid) return ""