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
12 changes: 11 additions & 1 deletion mapillary_tools/camm/camm_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,11 @@ class CAMMInfo:
model: str = ""


def extract_camm_info(fp: T.BinaryIO, telemetry_only: bool = False) -> CAMMInfo | None:
def extract_camm_info(
fp: T.BinaryIO,
telemetry_only: bool = False,
first_gps_only: bool = False,
) -> CAMMInfo | None:
moov = MovieBoxParser.parse_stream(fp)

make, model = "", ""
Expand Down Expand Up @@ -122,6 +126,12 @@ def extract_camm_info(fp: T.BinaryIO, telemetry_only: bool = False) -> CAMMInfo
gps.append(measurement)
elif isinstance(measurement, geo.Point):
mini_gps.append(measurement)
if (
first_gps_only
and isinstance(measurement, geo.Point)
and geo.point_has_usable_gps_clock(measurement)
):
break

_normalize_gps_epochs(gps, make, moov)

Expand Down
40 changes: 40 additions & 0 deletions mapillary_tools/geo.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,46 @@
WGS84_b = 6356752.314245
WGS84_b_SQ = WGS84_b**2

# GPS9 days-since-2000-01-01. 8000 is a round lid above the indoor
# default clock seen on Hero 11 (GX010081) and MAX 2 (GS010131):
# both start at day 7736 (2021-03-07); MAX 2 then sits on 7742
# (2021-03-13, time-of-day already right) before jumping to a real
# date. 8000 d = 2021-11-26, still before Hero 11 launch (2022-09-14).
GPS9_EPOCH = datetime.datetime(2000, 1, 1, tzinfo=datetime.timezone.utc)
GPS9_MIN_DAYS = 8000


def gps_datetime_is_valid(epoch: float) -> bool:
"""True if the GPS clock is usable for back-calculating video t=0.

Empirically (Hero 11 GX010081 and MAX 2 GS010131: started indoors,
walked outside until the GPS indicator lit, walked back inside):
both cameras open on GPS9 day 7736 (2021-03-07). MAX 2 then parks
on day 7742 (2021-03-13) with a plausible time-of-day before the
calendar jumps. A usable date appears next; fix and DOP come later.
Back indoors, fix and DOP drop out while the time keeps running —
the camera then synthesizes it.

``8000`` is a round threshold above those indoor defaults
(2000-01-01 + 8000 d = 2021-11-26) and still before Hero 11
launched (2022-09-14). Usable samples also need a time-of-day
that sits on a 10 ms grid (real GPS does; the indoor placeholder
often does not). Fix quality and DOP are ignored.
"""
try:
dt = datetime.datetime.fromtimestamp(epoch, tz=datetime.timezone.utc)
except (OSError, OverflowError, ValueError):
return False
if (dt - GPS9_EPOCH).days < GPS9_MIN_DAYS:
return False
msec = ((dt.hour * 60 + dt.minute) * 60 + dt.second) * 1000 + dt.microsecond // 1000
return 100 * int(round(msec / 100.0)) == 10 * int(round(msec / 10.0))


def point_has_usable_gps_clock(point: Point) -> bool:
epoch = point.get_unix_time()
return epoch is not None and gps_datetime_is_valid(epoch)


@dataclasses.dataclass(order=True)
class Point:
Expand Down
Loading