mapillary-tools 0.11.1__tar.gz → 0.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/PKG-INFO +4 -4
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/README.md +1 -1
- mapillary_tools-0.12.0/mapillary_tools/__init__.py +1 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/api_v4.py +7 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/exif_read.py +3 -3
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/exif_write.py +8 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/exiftool_read.py +2 -2
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/ffmpeg.py +21 -3
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/gpmf_parser.py +128 -75
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/process_sequence_properties.py +5 -3
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/sample_video.py +17 -15
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/types.py +5 -10
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/upload_api_v4.py +7 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/extract_video_data.py +6 -4
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools.egg-info/PKG-INFO +5 -5
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools.egg-info/requires.txt +2 -2
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/requirements.txt +2 -2
- mapillary_tools-0.11.1/mapillary_tools/__init__.py +0 -1
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/LICENSE +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/MANIFEST.in +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/authenticate.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/__init__.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/__main__.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/authenticate.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/process.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/process_and_upload.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/sample_video.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/upload.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/upload_blackvue.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/upload_camm.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/upload_zip.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/video_process.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/video_process_and_upload.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/zip.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/config.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/constants.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/exceptions.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/exiftool_read_video.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geo.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/__init__.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/blackvue_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/camm_builder.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/camm_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/construct_mp4_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_from_generic.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_images_from_exif.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_images_from_exiftool.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_images_from_exiftool_both_image_and_video.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_images_from_gpx.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_images_from_gpx_file.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_images_from_nmea_file.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_images_from_video.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_videos_from_exiftool_video.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_videos_from_video.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/gpmf_gps_filter.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/gps_filter.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/io_utils.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/mp4_sample_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/simple_mp4_builder.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/simple_mp4_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/utils.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/history.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/ipc.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/process_geotag_properties.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/process_import_meta_properties.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/upload.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/uploader.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/utils.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/cli_options.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/extractors/base_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/extractors/blackvue_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/extractors/camm_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/extractors/exiftool_runtime_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/extractors/exiftool_xml_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/extractors/generic_video_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/extractors/gopro_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/extractors/gpx_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/extractors/nmea_parser.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/video_data_extraction/video_data_parser_factory.py +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools.egg-info/SOURCES.txt +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools.egg-info/dependency_links.txt +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools.egg-info/entry_points.txt +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools.egg-info/top_level.txt +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/schema/image_description_schema.json +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/setup.cfg +0 -0
- {mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: mapillary_tools
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Mapillary Image/Video Import Pipeline
|
|
5
5
|
Home-page: https://github.com/mapillary/mapillary_tools
|
|
6
6
|
Author: Mapillary
|
|
@@ -13,8 +13,8 @@ Requires-Dist: construct<3.0.0,>=2.10.0
|
|
|
13
13
|
Requires-Dist: exifread==2.3.2
|
|
14
14
|
Requires-Dist: piexif==1.1.3
|
|
15
15
|
Requires-Dist: gpxpy<1.6.0,>=1.5.0
|
|
16
|
-
Requires-Dist: pynmea2
|
|
17
|
-
Requires-Dist: requests<3.0.0,>=2.20.0
|
|
16
|
+
Requires-Dist: pynmea2<2.0.0,>=1.12.0
|
|
17
|
+
Requires-Dist: requests[socks]<3.0.0,>=2.20.0
|
|
18
18
|
Requires-Dist: tqdm<5.0,>=4.0
|
|
19
19
|
Requires-Dist: typing_extensions
|
|
20
20
|
Requires-Dist: jsonschema~=4.17.3
|
|
@@ -130,7 +130,7 @@ A command line program such as Termux is required. Installation can be done with
|
|
|
130
130
|
commands will install Python 3, pip3, git, and all required libraries for mapillary_tools on Termux:
|
|
131
131
|
|
|
132
132
|
```sh
|
|
133
|
-
pkg install python git build-essential libgeos openssl libjpeg-turbo
|
|
133
|
+
pkg install python git build-essential libgeos openssl libjpeg-turbo libexpat libexpat-static
|
|
134
134
|
pip install --upgrade pip wheel
|
|
135
135
|
pip install --upgrade mapillary_tools
|
|
136
136
|
```
|
|
@@ -108,7 +108,7 @@ A command line program such as Termux is required. Installation can be done with
|
|
|
108
108
|
commands will install Python 3, pip3, git, and all required libraries for mapillary_tools on Termux:
|
|
109
109
|
|
|
110
110
|
```sh
|
|
111
|
-
pkg install python git build-essential libgeos openssl libjpeg-turbo
|
|
111
|
+
pkg install python git build-essential libgeos openssl libjpeg-turbo libexpat libexpat-static
|
|
112
112
|
pip install --upgrade pip wheel
|
|
113
113
|
pip install --upgrade mapillary_tools
|
|
114
114
|
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VERSION = "0.12.0"
|
|
@@ -9,6 +9,10 @@ MAPILLARY_CLIENT_TOKEN = os.getenv(
|
|
|
9
9
|
MAPILLARY_GRAPH_API_ENDPOINT = os.getenv(
|
|
10
10
|
"MAPILLARY_GRAPH_API_ENDPOINT", "https://graph.mapillary.com"
|
|
11
11
|
)
|
|
12
|
+
# https://requests.readthedocs.io/en/latest/user/advanced/#ssl-cert-verification
|
|
13
|
+
MAPILLARY__DISABLE_VERIFYING_SSL = (
|
|
14
|
+
os.getenv("MAPILLARY__DISABLE_VERIFYING_SSL") == "TRUE"
|
|
15
|
+
)
|
|
12
16
|
REQUESTS_TIMEOUT = 60 # 1 minutes
|
|
13
17
|
|
|
14
18
|
|
|
@@ -18,6 +22,7 @@ def get_upload_token(email: str, password: str) -> requests.Response:
|
|
|
18
22
|
params={"access_token": MAPILLARY_CLIENT_TOKEN},
|
|
19
23
|
json={"email": email, "password": password, "locale": "en_US"},
|
|
20
24
|
timeout=REQUESTS_TIMEOUT,
|
|
25
|
+
verify=not MAPILLARY__DISABLE_VERIFYING_SSL,
|
|
21
26
|
)
|
|
22
27
|
resp.raise_for_status()
|
|
23
28
|
return resp
|
|
@@ -35,6 +40,7 @@ def fetch_organization(
|
|
|
35
40
|
"Authorization": f"OAuth {user_access_token}",
|
|
36
41
|
},
|
|
37
42
|
timeout=REQUESTS_TIMEOUT,
|
|
43
|
+
verify=not MAPILLARY__DISABLE_VERIFYING_SSL,
|
|
38
44
|
)
|
|
39
45
|
resp.raise_for_status()
|
|
40
46
|
return resp
|
|
@@ -56,6 +62,7 @@ def logging(action_type: ActionType, properties: T.Dict) -> requests.Response:
|
|
|
56
62
|
"Authorization": f"OAuth {MAPILLARY_CLIENT_TOKEN}",
|
|
57
63
|
},
|
|
58
64
|
timeout=REQUESTS_TIMEOUT,
|
|
65
|
+
verify=not MAPILLARY__DISABLE_VERIFYING_SSL,
|
|
59
66
|
)
|
|
60
67
|
resp.raise_for_status()
|
|
61
68
|
return resp
|
|
@@ -399,7 +399,7 @@ class ExifReadFromXMP(ExifReadABC):
|
|
|
399
399
|
|
|
400
400
|
def extract_capture_time(self) -> T.Optional[datetime.datetime]:
|
|
401
401
|
dt = self.extract_gps_datetime()
|
|
402
|
-
if dt is not None:
|
|
402
|
+
if dt is not None and dt.date() != datetime.date(1970, 1, 1):
|
|
403
403
|
return dt
|
|
404
404
|
|
|
405
405
|
dt = self.extract_exif_datetime()
|
|
@@ -554,7 +554,7 @@ class ExifReadFromEXIF(ExifReadABC):
|
|
|
554
554
|
return None
|
|
555
555
|
|
|
556
556
|
dt = strptime_alternative_formats(gpsdate, ["%Y:%m:%d", "%Y-%m-%d"])
|
|
557
|
-
if dt is None:
|
|
557
|
+
if dt is None or dt == datetime.date(1970, 1, 1):
|
|
558
558
|
return None
|
|
559
559
|
|
|
560
560
|
gpstimestamp = self.tags.get("GPS GPSTimeStamp")
|
|
@@ -632,7 +632,7 @@ class ExifReadFromEXIF(ExifReadABC):
|
|
|
632
632
|
gps_dt = self.extract_gps_datetime()
|
|
633
633
|
except (ValueError, TypeError, ZeroDivisionError):
|
|
634
634
|
gps_dt = None
|
|
635
|
-
if gps_dt is not None:
|
|
635
|
+
if gps_dt is not None and gps_dt.date() != datetime.date(1970, 1, 1):
|
|
636
636
|
return gps_dt
|
|
637
637
|
|
|
638
638
|
dt = self.extract_exif_datetime()
|
|
@@ -182,6 +182,14 @@ class ExifEdit:
|
|
|
182
182
|
# retry later
|
|
183
183
|
else:
|
|
184
184
|
raise exc
|
|
185
|
+
except Exception as exc:
|
|
186
|
+
zeroth_ifd = self._ef.get("0th", {})
|
|
187
|
+
# workaround: https://github.com/mapillary/mapillary_tools/issues/662
|
|
188
|
+
if piexif.ImageIFD.AsShotNeutral in zeroth_ifd:
|
|
189
|
+
del zeroth_ifd[piexif.ImageIFD.AsShotNeutral]
|
|
190
|
+
assert piexif.ImageIFD.AsShotNeutral not in zeroth_ifd
|
|
191
|
+
else:
|
|
192
|
+
raise exc
|
|
185
193
|
else:
|
|
186
194
|
break
|
|
187
195
|
|
|
@@ -266,14 +266,14 @@ class ExifToolRead(exif_read.ExifReadABC):
|
|
|
266
266
|
dt = self.extract_gps_datetime()
|
|
267
267
|
except (ValueError, TypeError, ZeroDivisionError):
|
|
268
268
|
dt = None
|
|
269
|
-
if dt is not None:
|
|
269
|
+
if dt is not None and dt.date() != datetime.date(1970, 1, 1):
|
|
270
270
|
return dt
|
|
271
271
|
|
|
272
272
|
try:
|
|
273
273
|
dt = self.extract_gps_datetime_from_xmp()
|
|
274
274
|
except (ValueError, TypeError, ZeroDivisionError):
|
|
275
275
|
dt = None
|
|
276
|
-
if dt is not None:
|
|
276
|
+
if dt is not None and dt.date() != datetime.date(1970, 1, 1):
|
|
277
277
|
return dt
|
|
278
278
|
|
|
279
279
|
dt = self.extract_exif_datetime()
|
|
@@ -195,6 +195,18 @@ class FFMPEG:
|
|
|
195
195
|
|
|
196
196
|
self._run_ffmpeg(cmd)
|
|
197
197
|
|
|
198
|
+
def generate_binary_search(self, sorted_frame_indices: T.Sequence[int]) -> str:
|
|
199
|
+
length = len(sorted_frame_indices)
|
|
200
|
+
|
|
201
|
+
if length == 0:
|
|
202
|
+
return "0"
|
|
203
|
+
|
|
204
|
+
if length == 1:
|
|
205
|
+
return f"eq(n\\,{ sorted_frame_indices[0] })"
|
|
206
|
+
|
|
207
|
+
middle = length // 2
|
|
208
|
+
return f"if(lt(n\\,{ sorted_frame_indices[middle] })\\,{ self.generate_binary_search(sorted_frame_indices[:middle]) }\\,{ self.generate_binary_search(sorted_frame_indices[middle:]) })"
|
|
209
|
+
|
|
198
210
|
def extract_specified_frames(
|
|
199
211
|
self,
|
|
200
212
|
video_path: Path,
|
|
@@ -226,7 +238,7 @@ class FFMPEG:
|
|
|
226
238
|
# the maximum command line length for the CreateProcess function is 32767 characters
|
|
227
239
|
# https://devblogs.microsoft.com/oldnewthing/20031210-00/?p=41553
|
|
228
240
|
|
|
229
|
-
eqs =
|
|
241
|
+
eqs = self.generate_binary_search(sorted(frame_indices))
|
|
230
242
|
|
|
231
243
|
# https://github.com/mapillary/mapillary_tools/issues/503
|
|
232
244
|
if sys.platform in ["win32"]:
|
|
@@ -252,12 +264,18 @@ class FFMPEG:
|
|
|
252
264
|
*[
|
|
253
265
|
*["-filter_script:v", select_file.name],
|
|
254
266
|
# Each frame is passed with its timestamp from the demuxer to the muxer
|
|
255
|
-
# vsync is deprecated but -fps_mode is not avaliable on some versions ;(
|
|
256
267
|
*["-vsync", "0"],
|
|
268
|
+
# vsync is deprecated by fps_mode,
|
|
269
|
+
# but fps_mode is not avaliable on some older versions ;(
|
|
257
270
|
# *[f"-fps_mode:{stream_specifier}", "passthrough"],
|
|
258
271
|
# Set the number of video frames to output
|
|
259
272
|
*[f"-frames:{stream_specifier}", str(len(frame_indices))],
|
|
260
|
-
|
|
273
|
+
# Disabled because it doesn't always name the sample images as expected
|
|
274
|
+
# For example "select(n\,1)" we expected the first sample to be IMG_001.JPG
|
|
275
|
+
# but it could be IMG_005.JPG
|
|
276
|
+
# https://www.ffmpeg.org/ffmpeg-formats.html#Options-21
|
|
277
|
+
# If set to 1, expand the filename with pts from pkt->pts. Default value is 0.
|
|
278
|
+
# *["-frame_pts", "1"],
|
|
261
279
|
],
|
|
262
280
|
# video quality level (or the alias -q:v)
|
|
263
281
|
*[f"-qscale:{stream_specifier}", "2"],
|
|
@@ -15,15 +15,16 @@ A GPS GPMF sample has the following structure:
|
|
|
15
15
|
- DVID: Auto generated unique-ID for managing a large number of connect devices
|
|
16
16
|
- STRM: Metadata streams are each nested with STRM
|
|
17
17
|
- GPS5: latitude, longitude, altitude (WGS 84), 2D ground speed, and 3D speed
|
|
18
|
+
- GPS9: lat, long, alt, 2D speed, 3D speed, days since 2000, secs since midnight (ms precision), DOP, fix (0, 2D or 3D)
|
|
18
19
|
- GPSA: not documented in the spec
|
|
19
20
|
- GPSF: Within the GPS stream: 0 - no lock, 2 or 3 - 2D or 3D Lock.
|
|
20
21
|
- GPSP: GPS Precision - Dilution of Precision (DOP x100). Under 500 is good.
|
|
21
22
|
- GPSU: UTC time and data from GPS. The time is read from from another clock so it is not in use.
|
|
22
|
-
- SCAL: Scaling factor (divisor) for GPS5
|
|
23
|
+
- SCAL: Scaling factor (divisor) for GPS5 and GPS9
|
|
23
24
|
|
|
24
25
|
NOTE:
|
|
25
26
|
- There might be multiple DEVC streams.
|
|
26
|
-
- Only GPS5 and SCAL are required. The others are optional.
|
|
27
|
+
- Only GPS5, GPS9, and SCAL are required. The others are optional.
|
|
27
28
|
- GPSU is not in use. We use the video clock to make sure frames and GPS are in sync.
|
|
28
29
|
- We should skip samples with GPSF==0 or GPSP > 500
|
|
29
30
|
"""
|
|
@@ -40,6 +41,66 @@ class KLVDict(T.TypedDict):
|
|
|
40
41
|
GPMFSampleData: C.GreedyRange
|
|
41
42
|
|
|
42
43
|
|
|
44
|
+
# type char: (construct type, size in bytes)
|
|
45
|
+
_type_mapping = {
|
|
46
|
+
# b single byte signed integer int8_t -128 to 127
|
|
47
|
+
b"b": (C.Int8sb, 1),
|
|
48
|
+
# B single byte unsigned integer uint8_t 0 to 255
|
|
49
|
+
b"B": (C.Int8ub, 1),
|
|
50
|
+
# c single byte 'c' style ASCII character string char Optionally NULL terminated - size/repeat sets the length
|
|
51
|
+
b"c": (C.Bytes(1), 1),
|
|
52
|
+
# d 64-bit double precision (IEEE 754) double
|
|
53
|
+
b"d": (C.Float64b, 8),
|
|
54
|
+
# f 32-bit float (IEEE 754) float
|
|
55
|
+
b"f": (C.Float32b, 4),
|
|
56
|
+
# F 32-bit four character key -- FourCC char fourcc[4]
|
|
57
|
+
b"F": (C.Bytes(4), 4),
|
|
58
|
+
# G 128-bit ID (like UUID) uint8_t guid[16]
|
|
59
|
+
b"G": (C.Bytes(16), 16),
|
|
60
|
+
# j 64-bit signed long number int64_t
|
|
61
|
+
b"j": (C.Int64sb, 8),
|
|
62
|
+
# J 64-bit unsigned long number uint64_t
|
|
63
|
+
b"J": (C.Int64ub, 8),
|
|
64
|
+
# l 32-bit signed integer int32_t
|
|
65
|
+
b"l": (C.Int32sb, 4),
|
|
66
|
+
# L 32-bit unsigned integer uint32_t
|
|
67
|
+
b"L": (C.Int32ub, 4),
|
|
68
|
+
# q 32-bit Q Number Q15.16 uint32_t 16-bit integer (A) with 16-bit fixed point (B) for A.B value (range -32768.0 to 32767.99998)
|
|
69
|
+
b"q": (C.Int32ub, 4),
|
|
70
|
+
# Q 64-bit Q Number Q31.32 uint64_t 32-bit integer (A) with 32-bit fixed point (B) for A.B value.
|
|
71
|
+
b"Q": (C.Int64ub, 8),
|
|
72
|
+
# s 16-bit signed integer int16_t -32768 to 32768
|
|
73
|
+
b"s": (C.Int16sb, 2),
|
|
74
|
+
# S 16-bit unsigned integer uint16_t 0 to 65536
|
|
75
|
+
b"S": (C.Int16ub, 2),
|
|
76
|
+
# U UTC Date and Time string char utcdate[16] Date + UTC Time format yymmddhhmmss.sss - (years 20xx covered)
|
|
77
|
+
b"U": (C.Bytes(16), 16),
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
_klv_data_switch = C.Switch(
|
|
82
|
+
C.this.type,
|
|
83
|
+
{
|
|
84
|
+
**{
|
|
85
|
+
type_char: C.Array(
|
|
86
|
+
C.this.repeat, C.Array(C.this.structure_size // size, ctype)
|
|
87
|
+
)
|
|
88
|
+
for type_char, (ctype, size) in _type_mapping.items()
|
|
89
|
+
},
|
|
90
|
+
# c single byte 'c' style ASCII character string char Optionally NULL terminated - size/repeat sets the length
|
|
91
|
+
b"c": C.Array(
|
|
92
|
+
C.this.repeat, C.Bytes(C.this.structure_size)
|
|
93
|
+
), # overwrite the one in _type_mapping to make sure it returns bytes instead of a list of bytes
|
|
94
|
+
# null Nested metadata uint32_t The data within is GPMF structured KLV data
|
|
95
|
+
b"\x00": C.FixedSized(
|
|
96
|
+
(C.this.repeat * C.this.structure_size),
|
|
97
|
+
C.LazyBound(lambda: GPMFSampleData),
|
|
98
|
+
),
|
|
99
|
+
},
|
|
100
|
+
C.Array(C.this.repeat, C.Bytes(C.this.structure_size)),
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
43
104
|
KLV = C.Struct(
|
|
44
105
|
# FourCC
|
|
45
106
|
"key" / C.Bytes(4),
|
|
@@ -52,77 +113,7 @@ KLV = C.Struct(
|
|
|
52
113
|
# this is the Repeat field. Struct Size and the Repeat allow for up to
|
|
53
114
|
# 16.7MB of data in a single KLV GPMF payload.
|
|
54
115
|
"repeat" / C.Int16ub,
|
|
55
|
-
"data"
|
|
56
|
-
/ C.Switch(
|
|
57
|
-
C.this.type,
|
|
58
|
-
{
|
|
59
|
-
# b single byte signed integer int8_t -128 to 127
|
|
60
|
-
b"b": C.Array(C.this.repeat, C.Array(C.this.structure_size, C.Int8sb)),
|
|
61
|
-
# B single byte unsigned integer uint8_t 0 to 255
|
|
62
|
-
b"B": C.Array(C.this.repeat, C.Array(C.this.structure_size, C.Int8ub)),
|
|
63
|
-
# c single byte 'c' style ASCII character string char Optionally NULL terminated - size/repeat sets the length
|
|
64
|
-
b"c": C.Array(C.this.repeat, C.Bytes(C.this.structure_size)),
|
|
65
|
-
# d 64-bit double precision (IEEE 754) double
|
|
66
|
-
b"d": C.Array(
|
|
67
|
-
C.this.repeat, C.Array(C.this.structure_size // 8, C.Float64b)
|
|
68
|
-
),
|
|
69
|
-
# f 32-bit float (IEEE 754) float
|
|
70
|
-
b"f": C.Array(
|
|
71
|
-
C.this.repeat, C.Array(C.this.structure_size // 4, C.Float32b)
|
|
72
|
-
),
|
|
73
|
-
# F 32-bit four character key -- FourCC char fourcc[4]
|
|
74
|
-
b"F": C.Array(
|
|
75
|
-
C.this.repeat, C.Array(C.this.structure_size // 4, C.Bytes(4))
|
|
76
|
-
),
|
|
77
|
-
# G 128-bit ID (like UUID) uint8_t guid[16]
|
|
78
|
-
b"G": C.Array(
|
|
79
|
-
C.this.repeat, C.Array(C.this.structure_size // 16, C.Bytes(16))
|
|
80
|
-
),
|
|
81
|
-
# j 64-bit signed unsigned number int64_t
|
|
82
|
-
b"j": C.Array(
|
|
83
|
-
C.this.repeat, C.Array(C.this.structure_size // 8, C.Int64sb)
|
|
84
|
-
),
|
|
85
|
-
# J 64-bit unsigned unsigned number uint64_t
|
|
86
|
-
b"J": C.Array(
|
|
87
|
-
C.this.repeat, C.Array(C.this.structure_size // 8, C.Int64ub)
|
|
88
|
-
),
|
|
89
|
-
# l 32-bit signed integer int32_t
|
|
90
|
-
b"l": C.Array(
|
|
91
|
-
C.this.repeat, C.Array(C.this.structure_size // 4, C.Int32sb)
|
|
92
|
-
),
|
|
93
|
-
# L 32-bit unsigned integer uint32_t
|
|
94
|
-
b"L": C.Array(
|
|
95
|
-
C.this.repeat, C.Array(C.this.structure_size // 4, C.Int32ub)
|
|
96
|
-
),
|
|
97
|
-
# q 32-bit Q Number Q15.16 uint32_t 16-bit integer (A) with 16-bit fixed point (B) for A.B value (range -32768.0 to 32767.99998)
|
|
98
|
-
b"q": C.Array(
|
|
99
|
-
C.this.repeat, C.Array(C.this.structure_size // 4, C.Int32ub)
|
|
100
|
-
),
|
|
101
|
-
# Q 64-bit Q Number Q31.32 uint64_t 32-bit integer (A) with 32-bit fixed point (B) for A.B value.
|
|
102
|
-
b"Q": C.Array(
|
|
103
|
-
C.this.repeat, C.Array(C.this.structure_size // 8, C.Int64ub)
|
|
104
|
-
),
|
|
105
|
-
# s 16-bit signed integer int16_t -32768 to 32768
|
|
106
|
-
b"s": C.Array(
|
|
107
|
-
C.this.repeat, C.Array(C.this.structure_size // 2, C.Int16sb)
|
|
108
|
-
),
|
|
109
|
-
# S 16-bit unsigned integer uint16_t 0 to 65536
|
|
110
|
-
b"S": C.Array(
|
|
111
|
-
C.this.repeat, C.Array(C.this.structure_size // 2, C.Int16ub)
|
|
112
|
-
),
|
|
113
|
-
# U UTC Date and Time string char utcdate[16] Date + UTC Time format yymmddhhmmss.sss - (years 20xx covered)
|
|
114
|
-
b"U": C.Array(
|
|
115
|
-
C.this.repeat, C.Array(C.this.structure_size // 16, C.Bytes(16))
|
|
116
|
-
),
|
|
117
|
-
# ? data structure is complex TYPE Structure is defined with a preceding TYPE
|
|
118
|
-
# null Nested metadata uint32_t The data within is GPMF structured KLV data
|
|
119
|
-
b"\x00": C.FixedSized(
|
|
120
|
-
(C.this.repeat * C.this.structure_size),
|
|
121
|
-
C.LazyBound(lambda: GPMFSampleData),
|
|
122
|
-
),
|
|
123
|
-
},
|
|
124
|
-
C.Array(C.this.repeat, C.Bytes(C.this.structure_size)),
|
|
125
|
-
),
|
|
116
|
+
"data" / _klv_data_switch,
|
|
126
117
|
C.IfThenElse(
|
|
127
118
|
(C.this.repeat * C.this.structure_size) % 4 == 0,
|
|
128
119
|
C.Padding(0),
|
|
@@ -170,7 +161,7 @@ GPMFSampleData = C.GreedyRange(KLV)
|
|
|
170
161
|
# [378081666, -1224280064, 9621, 1492, 138],
|
|
171
162
|
# [378081662, -1224280049, 9592, 1476, 150],
|
|
172
163
|
# ]
|
|
173
|
-
def
|
|
164
|
+
def gps5_from_stream(
|
|
174
165
|
stream: T.Sequence[KLVDict],
|
|
175
166
|
) -> T.Generator[geo.PointWithFix, None, None]:
|
|
176
167
|
indexed: T.Dict[bytes, T.List[T.List[T.Any]]] = {
|
|
@@ -217,6 +208,64 @@ def gps_from_stream(
|
|
|
217
208
|
)
|
|
218
209
|
|
|
219
210
|
|
|
211
|
+
def gps9_from_stream(
|
|
212
|
+
stream: T.Sequence[KLVDict],
|
|
213
|
+
) -> T.Generator[geo.PointWithFix, None, None]:
|
|
214
|
+
indexed: T.Dict[bytes, T.List[T.List[T.Any]]] = {
|
|
215
|
+
klv["key"]: klv["data"] for klv in stream
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
gps9 = indexed.get(b"GPS9")
|
|
219
|
+
if gps9 is None:
|
|
220
|
+
return
|
|
221
|
+
|
|
222
|
+
scal = indexed.get(b"SCAL")
|
|
223
|
+
if scal is None:
|
|
224
|
+
return
|
|
225
|
+
scal_values = [s[0] for s in scal]
|
|
226
|
+
if any(s == 0 for s in scal_values):
|
|
227
|
+
return
|
|
228
|
+
|
|
229
|
+
type = indexed.get(b"TYPE")
|
|
230
|
+
if type is None:
|
|
231
|
+
return
|
|
232
|
+
gps_value_types = type[0]
|
|
233
|
+
|
|
234
|
+
try:
|
|
235
|
+
sample_parser = C.Sequence(
|
|
236
|
+
*[_type_mapping[t.to_bytes()][0] for t in gps_value_types]
|
|
237
|
+
)
|
|
238
|
+
except Exception as ex:
|
|
239
|
+
raise ValueError(f"Error parsing the complex type {gps_value_types}: {ex}")
|
|
240
|
+
|
|
241
|
+
for sample_data_bytes in gps9:
|
|
242
|
+
sample_data = sample_parser.parse(sample_data_bytes)
|
|
243
|
+
|
|
244
|
+
(
|
|
245
|
+
lat,
|
|
246
|
+
lon,
|
|
247
|
+
alt,
|
|
248
|
+
speed_2d,
|
|
249
|
+
_speed_3d,
|
|
250
|
+
_days_since_2000,
|
|
251
|
+
_secs_since_midnight,
|
|
252
|
+
dop,
|
|
253
|
+
gps_fix,
|
|
254
|
+
) = [v / s for v, s in zip(sample_data, scal_values)]
|
|
255
|
+
|
|
256
|
+
yield geo.PointWithFix(
|
|
257
|
+
# will figure out the actual timestamp later
|
|
258
|
+
time=0,
|
|
259
|
+
lat=lat,
|
|
260
|
+
lon=lon,
|
|
261
|
+
alt=alt,
|
|
262
|
+
gps_fix=geo.GPSFix(gps_fix),
|
|
263
|
+
gps_precision=dop * 100,
|
|
264
|
+
gps_ground_speed=speed_2d,
|
|
265
|
+
angle=None,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
220
269
|
def _find_first_device_id(stream: T.Sequence[KLVDict]) -> int:
|
|
221
270
|
device_id = None
|
|
222
271
|
|
|
@@ -238,7 +287,11 @@ def _find_first_gps_stream(stream: T.Sequence[KLVDict]) -> T.List[geo.PointWithF
|
|
|
238
287
|
|
|
239
288
|
for klv in stream:
|
|
240
289
|
if klv["key"] == b"STRM":
|
|
241
|
-
sample_points = list(
|
|
290
|
+
sample_points = list(gps9_from_stream(klv["data"]))
|
|
291
|
+
if sample_points:
|
|
292
|
+
break
|
|
293
|
+
|
|
294
|
+
sample_points = list(gps5_from_stream(klv["data"]))
|
|
242
295
|
if sample_points:
|
|
243
296
|
break
|
|
244
297
|
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/process_sequence_properties.py
RENAMED
|
@@ -195,9 +195,11 @@ def _interpolate_subsecs_for_sorting(sequence: PointSequence) -> None:
|
|
|
195
195
|
|
|
196
196
|
t = sequence[gidx].time
|
|
197
197
|
nt = min(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
198
|
+
(
|
|
199
|
+
sequence[gidx + len(group)].time
|
|
200
|
+
if gidx + len(group) < len(sequence)
|
|
201
|
+
else math.floor(t + 1.0)
|
|
202
|
+
),
|
|
201
203
|
math.floor(t + 1.0),
|
|
202
204
|
)
|
|
203
205
|
assert t <= nt, f"expect sorted but got {t} > {nt}"
|
|
@@ -320,35 +320,37 @@ def _sample_single_video_by_distance(
|
|
|
320
320
|
sample_points_by_frame_idx = _sample_video_stream_by_distance(
|
|
321
321
|
video_metadata.points, video_track_parser, sample_distance
|
|
322
322
|
)
|
|
323
|
+
sorted_sample_indices = sorted(sample_points_by_frame_idx.keys())
|
|
323
324
|
|
|
324
325
|
with wip_dir_context(wip_sample_dir(sample_dir), sample_dir) as wip_dir:
|
|
325
326
|
ffmpeg.extract_specified_frames(
|
|
326
327
|
video_path,
|
|
327
328
|
wip_dir,
|
|
328
|
-
frame_indices=set(
|
|
329
|
+
frame_indices=set(sorted_sample_indices),
|
|
329
330
|
stream_idx=video_stream_idx,
|
|
330
331
|
)
|
|
331
332
|
|
|
332
333
|
frame_samples = ffmpeglib.sort_selected_samples(
|
|
333
334
|
wip_dir, video_path, [video_stream_idx]
|
|
334
335
|
)
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
"
|
|
346
|
-
frame_idx_0based,
|
|
347
|
-
video_stream_idx,
|
|
336
|
+
if len(frame_samples) != len(sorted_sample_indices):
|
|
337
|
+
raise exceptions.MapillaryVideoError(
|
|
338
|
+
f"Expect {len(sorted_sample_indices)} samples but extracted {len(frame_samples)} samples"
|
|
339
|
+
)
|
|
340
|
+
for idx, (frame_idx_1based, sample_paths) in enumerate(frame_samples):
|
|
341
|
+
assert (
|
|
342
|
+
len(sample_paths) == 1
|
|
343
|
+
), "Expect 1 sample path at {frame_idx_1based} but got {sample_paths}"
|
|
344
|
+
if idx + 1 != frame_idx_1based:
|
|
345
|
+
raise exceptions.MapillaryVideoError(
|
|
346
|
+
f"Expect {sample_paths[0]} to be {idx + 1}th sample but got {frame_idx_1based}"
|
|
348
347
|
)
|
|
348
|
+
|
|
349
|
+
for (_, sample_paths), sample_idx in zip(frame_samples, sorted_sample_indices):
|
|
350
|
+
if sample_paths[0] is None:
|
|
349
351
|
continue
|
|
350
352
|
|
|
351
|
-
video_sample, interp =
|
|
353
|
+
video_sample, interp = sample_points_by_frame_idx[sample_idx]
|
|
352
354
|
assert (
|
|
353
355
|
interp.time == video_sample.composition_time_offset
|
|
354
356
|
), f"interpolated time {interp.time} should match the video sample time {video_sample.composition_time_offset}"
|
|
@@ -456,18 +456,15 @@ def map_capture_time_to_datetime(time: str) -> datetime.datetime:
|
|
|
456
456
|
|
|
457
457
|
|
|
458
458
|
@T.overload
|
|
459
|
-
def as_desc(metadata: ImageMetadata) -> ImageDescription:
|
|
460
|
-
...
|
|
459
|
+
def as_desc(metadata: ImageMetadata) -> ImageDescription: ...
|
|
461
460
|
|
|
462
461
|
|
|
463
462
|
@T.overload
|
|
464
|
-
def as_desc(metadata: ErrorMetadata) -> ImageDescriptionError:
|
|
465
|
-
...
|
|
463
|
+
def as_desc(metadata: ErrorMetadata) -> ImageDescriptionError: ...
|
|
466
464
|
|
|
467
465
|
|
|
468
466
|
@T.overload
|
|
469
|
-
def as_desc(metadata: VideoMetadata) -> VideoDescription:
|
|
470
|
-
...
|
|
467
|
+
def as_desc(metadata: VideoMetadata) -> VideoDescription: ...
|
|
471
468
|
|
|
472
469
|
|
|
473
470
|
def as_desc(metadata):
|
|
@@ -524,13 +521,11 @@ def _as_image_desc(metadata: ImageMetadata) -> ImageDescription:
|
|
|
524
521
|
|
|
525
522
|
|
|
526
523
|
@T.overload
|
|
527
|
-
def from_desc(metadata: ImageDescription) -> ImageMetadata:
|
|
528
|
-
...
|
|
524
|
+
def from_desc(metadata: ImageDescription) -> ImageMetadata: ...
|
|
529
525
|
|
|
530
526
|
|
|
531
527
|
@T.overload
|
|
532
|
-
def from_desc(metadata: VideoDescription) -> VideoMetadata:
|
|
533
|
-
...
|
|
528
|
+
def from_desc(metadata: VideoDescription) -> VideoMetadata: ...
|
|
534
529
|
|
|
535
530
|
|
|
536
531
|
def from_desc(desc):
|
|
@@ -15,6 +15,10 @@ MAPILLARY_UPLOAD_ENDPOINT = os.getenv(
|
|
|
15
15
|
MAPILLARY_GRAPH_API_ENDPOINT = os.getenv(
|
|
16
16
|
"MAPILLARY_GRAPH_API_ENDPOINT", "https://graph.mapillary.com"
|
|
17
17
|
)
|
|
18
|
+
# https://requests.readthedocs.io/en/latest/user/advanced/#ssl-cert-verification
|
|
19
|
+
MAPILLARY__DISABLE_VERIFYING_SSL = (
|
|
20
|
+
os.getenv("MAPILLARY__DISABLE_VERIFYING_SSL") == "TRUE"
|
|
21
|
+
)
|
|
18
22
|
DEFAULT_CHUNK_SIZE = 1024 * 1024 * 16 # 16MB
|
|
19
23
|
# According to the docs, UPLOAD_REQUESTS_TIMEOUT can be a tuple of
|
|
20
24
|
# (connection_timeout, read_timeout): https://requests.readthedocs.io/en/latest/user/advanced/#timeouts
|
|
@@ -97,6 +101,7 @@ class UploadService:
|
|
|
97
101
|
url,
|
|
98
102
|
headers=headers,
|
|
99
103
|
timeout=REQUESTS_TIMEOUT,
|
|
104
|
+
verify=not MAPILLARY__DISABLE_VERIFYING_SSL,
|
|
100
105
|
)
|
|
101
106
|
LOG.debug("HTTP response %s: %s", resp.status_code, resp.content)
|
|
102
107
|
resp.raise_for_status()
|
|
@@ -139,6 +144,7 @@ class UploadService:
|
|
|
139
144
|
headers=headers,
|
|
140
145
|
data=chunk,
|
|
141
146
|
timeout=UPLOAD_REQUESTS_TIMEOUT,
|
|
147
|
+
verify=not MAPILLARY__DISABLE_VERIFYING_SSL,
|
|
142
148
|
)
|
|
143
149
|
LOG.debug(
|
|
144
150
|
"HTTP response %s: %s", resp.status_code, _truncate_end(resp.content)
|
|
@@ -185,6 +191,7 @@ class UploadService:
|
|
|
185
191
|
headers=headers,
|
|
186
192
|
json=data,
|
|
187
193
|
timeout=REQUESTS_TIMEOUT,
|
|
194
|
+
verify=not MAPILLARY__DISABLE_VERIFYING_SSL,
|
|
188
195
|
)
|
|
189
196
|
LOG.debug("HTTP response %s: %s", resp.status_code, _truncate_end(resp.content))
|
|
190
197
|
|
|
@@ -104,10 +104,12 @@ class VideoDataExtractor:
|
|
|
104
104
|
else:
|
|
105
105
|
return ErrorMetadata(
|
|
106
106
|
filename=file,
|
|
107
|
-
error=
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
error=(
|
|
108
|
+
ex
|
|
109
|
+
if ex
|
|
110
|
+
else exceptions.MapillaryVideoGPSNotFoundError(
|
|
111
|
+
"No GPS data found from the video"
|
|
112
|
+
)
|
|
111
113
|
),
|
|
112
114
|
filetype=FileType.VIDEO,
|
|
113
115
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
|
-
Name:
|
|
3
|
-
Version: 0.
|
|
2
|
+
Name: mapillary_tools
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Mapillary Image/Video Import Pipeline
|
|
5
5
|
Home-page: https://github.com/mapillary/mapillary_tools
|
|
6
6
|
Author: Mapillary
|
|
@@ -13,8 +13,8 @@ Requires-Dist: construct<3.0.0,>=2.10.0
|
|
|
13
13
|
Requires-Dist: exifread==2.3.2
|
|
14
14
|
Requires-Dist: piexif==1.1.3
|
|
15
15
|
Requires-Dist: gpxpy<1.6.0,>=1.5.0
|
|
16
|
-
Requires-Dist: pynmea2
|
|
17
|
-
Requires-Dist: requests<3.0.0,>=2.20.0
|
|
16
|
+
Requires-Dist: pynmea2<2.0.0,>=1.12.0
|
|
17
|
+
Requires-Dist: requests[socks]<3.0.0,>=2.20.0
|
|
18
18
|
Requires-Dist: tqdm<5.0,>=4.0
|
|
19
19
|
Requires-Dist: typing_extensions
|
|
20
20
|
Requires-Dist: jsonschema~=4.17.3
|
|
@@ -130,7 +130,7 @@ A command line program such as Termux is required. Installation can be done with
|
|
|
130
130
|
commands will install Python 3, pip3, git, and all required libraries for mapillary_tools on Termux:
|
|
131
131
|
|
|
132
132
|
```sh
|
|
133
|
-
pkg install python git build-essential libgeos openssl libjpeg-turbo
|
|
133
|
+
pkg install python git build-essential libgeos openssl libjpeg-turbo libexpat libexpat-static
|
|
134
134
|
pip install --upgrade pip wheel
|
|
135
135
|
pip install --upgrade mapillary_tools
|
|
136
136
|
```
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
VERSION = "0.11.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/process_and_upload.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/commands/upload_blackvue.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/construct_mp4_parser.py
RENAMED
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_from_generic.py
RENAMED
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_images_from_exif.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_images_from_gpx.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_images_from_video.py
RENAMED
|
File without changes
|
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/geotag_videos_from_video.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/mp4_sample_parser.py
RENAMED
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/simple_mp4_builder.py
RENAMED
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/geotag/simple_mp4_parser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/process_geotag_properties.py
RENAMED
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools/process_import_meta_properties.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mapillary_tools-0.11.1 → mapillary_tools-0.12.0}/mapillary_tools.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|