mapillary-tools 0.13.3a1__py3-none-any.whl → 0.14.0__py3-none-any.whl
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/__init__.py +1 -1
- mapillary_tools/api_v4.py +287 -22
- mapillary_tools/authenticate.py +326 -64
- mapillary_tools/blackvue_parser.py +195 -0
- mapillary_tools/camm/camm_builder.py +55 -97
- mapillary_tools/camm/camm_parser.py +429 -181
- mapillary_tools/commands/__main__.py +17 -8
- mapillary_tools/commands/authenticate.py +8 -1
- mapillary_tools/commands/process.py +27 -51
- mapillary_tools/commands/process_and_upload.py +19 -5
- mapillary_tools/commands/sample_video.py +2 -3
- mapillary_tools/commands/upload.py +44 -13
- mapillary_tools/commands/video_process_and_upload.py +19 -5
- mapillary_tools/config.py +65 -26
- mapillary_tools/constants.py +141 -18
- mapillary_tools/exceptions.py +37 -34
- mapillary_tools/exif_read.py +221 -116
- mapillary_tools/exif_write.py +10 -8
- mapillary_tools/exiftool_read.py +33 -42
- mapillary_tools/exiftool_read_video.py +97 -47
- mapillary_tools/exiftool_runner.py +57 -0
- mapillary_tools/ffmpeg.py +417 -242
- mapillary_tools/geo.py +158 -118
- mapillary_tools/geotag/__init__.py +0 -1
- mapillary_tools/geotag/base.py +147 -0
- mapillary_tools/geotag/factory.py +307 -0
- mapillary_tools/geotag/geotag_images_from_exif.py +14 -131
- mapillary_tools/geotag/geotag_images_from_exiftool.py +136 -85
- mapillary_tools/geotag/geotag_images_from_gpx.py +60 -124
- mapillary_tools/geotag/geotag_images_from_gpx_file.py +13 -126
- mapillary_tools/geotag/geotag_images_from_nmea_file.py +4 -5
- mapillary_tools/geotag/geotag_images_from_video.py +88 -51
- mapillary_tools/geotag/geotag_videos_from_exiftool.py +123 -0
- mapillary_tools/geotag/geotag_videos_from_gpx.py +52 -0
- mapillary_tools/geotag/geotag_videos_from_video.py +20 -185
- mapillary_tools/geotag/image_extractors/base.py +18 -0
- mapillary_tools/geotag/image_extractors/exif.py +60 -0
- mapillary_tools/geotag/image_extractors/exiftool.py +18 -0
- mapillary_tools/geotag/options.py +182 -0
- mapillary_tools/geotag/utils.py +52 -16
- mapillary_tools/geotag/video_extractors/base.py +18 -0
- mapillary_tools/geotag/video_extractors/exiftool.py +70 -0
- mapillary_tools/geotag/video_extractors/gpx.py +116 -0
- mapillary_tools/geotag/video_extractors/native.py +160 -0
- mapillary_tools/{geotag → gpmf}/gpmf_parser.py +205 -182
- mapillary_tools/{geotag → gpmf}/gps_filter.py +5 -3
- mapillary_tools/history.py +134 -20
- mapillary_tools/mp4/construct_mp4_parser.py +17 -10
- mapillary_tools/mp4/io_utils.py +0 -1
- mapillary_tools/mp4/mp4_sample_parser.py +36 -28
- mapillary_tools/mp4/simple_mp4_builder.py +10 -9
- mapillary_tools/mp4/simple_mp4_parser.py +13 -22
- mapillary_tools/process_geotag_properties.py +184 -414
- mapillary_tools/process_sequence_properties.py +594 -225
- mapillary_tools/sample_video.py +20 -26
- mapillary_tools/serializer/description.py +587 -0
- mapillary_tools/serializer/gpx.py +132 -0
- mapillary_tools/telemetry.py +26 -13
- mapillary_tools/types.py +98 -611
- mapillary_tools/upload.py +408 -416
- mapillary_tools/upload_api_v4.py +172 -174
- mapillary_tools/uploader.py +804 -284
- mapillary_tools/utils.py +49 -18
- {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/METADATA +93 -35
- mapillary_tools-0.14.0.dist-info/RECORD +75 -0
- {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/WHEEL +1 -1
- mapillary_tools/geotag/blackvue_parser.py +0 -118
- mapillary_tools/geotag/geotag_from_generic.py +0 -22
- mapillary_tools/geotag/geotag_images_from_exiftool_both_image_and_video.py +0 -93
- mapillary_tools/geotag/geotag_videos_from_exiftool_video.py +0 -145
- mapillary_tools/video_data_extraction/cli_options.py +0 -22
- mapillary_tools/video_data_extraction/extract_video_data.py +0 -176
- mapillary_tools/video_data_extraction/extractors/base_parser.py +0 -75
- mapillary_tools/video_data_extraction/extractors/blackvue_parser.py +0 -34
- mapillary_tools/video_data_extraction/extractors/camm_parser.py +0 -38
- mapillary_tools/video_data_extraction/extractors/exiftool_runtime_parser.py +0 -71
- mapillary_tools/video_data_extraction/extractors/exiftool_xml_parser.py +0 -53
- mapillary_tools/video_data_extraction/extractors/generic_video_parser.py +0 -52
- mapillary_tools/video_data_extraction/extractors/gopro_parser.py +0 -43
- mapillary_tools/video_data_extraction/extractors/gpx_parser.py +0 -108
- mapillary_tools/video_data_extraction/extractors/nmea_parser.py +0 -24
- mapillary_tools/video_data_extraction/video_data_parser_factory.py +0 -39
- mapillary_tools-0.13.3a1.dist-info/RECORD +0 -75
- /mapillary_tools/{geotag → gpmf}/gpmf_gps_filter.py +0 -0
- {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/entry_points.txt +0 -0
- {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info/licenses}/LICENSE +0 -0
- {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/top_level.txt +0 -0
mapillary_tools/sample_video.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import datetime
|
|
2
4
|
import logging
|
|
3
5
|
import os
|
|
@@ -11,14 +13,14 @@ from . import constants, exceptions, ffmpeg as ffmpeglib, geo, types, utils
|
|
|
11
13
|
from .exif_write import ExifEdit
|
|
12
14
|
from .geotag import geotag_videos_from_video
|
|
13
15
|
from .mp4 import mp4_sample_parser
|
|
14
|
-
from .
|
|
16
|
+
from .serializer.description import parse_capture_time
|
|
15
17
|
|
|
16
18
|
LOG = logging.getLogger(__name__)
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
def _normalize_path(
|
|
20
22
|
video_import_path: Path, skip_subfolders: bool
|
|
21
|
-
) ->
|
|
23
|
+
) -> tuple[Path, list[Path]]:
|
|
22
24
|
if video_import_path.is_dir():
|
|
23
25
|
video_list = utils.find_videos(
|
|
24
26
|
[video_import_path], skip_subfolders=skip_subfolders
|
|
@@ -46,12 +48,11 @@ def sample_video(
|
|
|
46
48
|
video_import_path: Path,
|
|
47
49
|
import_path: Path,
|
|
48
50
|
# None if called from the sample_video command
|
|
49
|
-
geotag_source: T.Optional[GeotagSource] = None,
|
|
50
51
|
skip_subfolders=False,
|
|
51
52
|
video_sample_distance=constants.VIDEO_SAMPLE_DISTANCE,
|
|
52
53
|
video_sample_interval=constants.VIDEO_SAMPLE_INTERVAL,
|
|
53
54
|
video_duration_ratio=constants.VIDEO_DURATION_RATIO,
|
|
54
|
-
video_start_time:
|
|
55
|
+
video_start_time: str | None = None,
|
|
55
56
|
skip_sample_errors: bool = False,
|
|
56
57
|
rerun: bool = False,
|
|
57
58
|
) -> None:
|
|
@@ -62,10 +63,10 @@ def sample_video(
|
|
|
62
63
|
f"Expect either non-negative video_sample_distance or positive video_sample_interval but got {video_sample_distance} and {video_sample_interval} respectively"
|
|
63
64
|
)
|
|
64
65
|
|
|
65
|
-
video_start_time_dt:
|
|
66
|
+
video_start_time_dt: datetime.datetime | None = None
|
|
66
67
|
if video_start_time is not None:
|
|
67
68
|
try:
|
|
68
|
-
video_start_time_dt =
|
|
69
|
+
video_start_time_dt = parse_capture_time(video_start_time)
|
|
69
70
|
except ValueError as ex:
|
|
70
71
|
raise exceptions.MapillaryBadParameterError(str(ex))
|
|
71
72
|
|
|
@@ -86,16 +87,6 @@ def sample_video(
|
|
|
86
87
|
elif sample_dir.is_file():
|
|
87
88
|
os.remove(sample_dir)
|
|
88
89
|
|
|
89
|
-
if geotag_source is None:
|
|
90
|
-
geotag_source = "exif"
|
|
91
|
-
|
|
92
|
-
# If it is not exif, then we use the legacy interval-based sample and geotag them in "process" for backward compatibility
|
|
93
|
-
if geotag_source not in ["exif"]:
|
|
94
|
-
if 0 <= video_sample_distance:
|
|
95
|
-
raise exceptions.MapillaryBadParameterError(
|
|
96
|
-
f'Geotagging from "{geotag_source}" works with the legacy interval-based sampling only. To switch back, rerun the command with "--video_sample_distance -1 --video_sample_interval 2"'
|
|
97
|
-
)
|
|
98
|
-
|
|
99
90
|
for video_path in video_list:
|
|
100
91
|
# need to resolve video_path because video_dir might be absolute
|
|
101
92
|
sample_dir = Path(import_path).joinpath(
|
|
@@ -189,7 +180,7 @@ def _sample_single_video_by_interval(
|
|
|
189
180
|
sample_dir: Path,
|
|
190
181
|
sample_interval: float,
|
|
191
182
|
duration_ratio: float,
|
|
192
|
-
start_time:
|
|
183
|
+
start_time: datetime.datetime | None = None,
|
|
193
184
|
) -> None:
|
|
194
185
|
ffmpeg = ffmpeglib.FFMPEG(constants.FFMPEG_PATH, constants.FFPROBE_PATH)
|
|
195
186
|
|
|
@@ -203,8 +194,8 @@ def _sample_single_video_by_interval(
|
|
|
203
194
|
)
|
|
204
195
|
|
|
205
196
|
with wip_dir_context(wip_sample_dir(sample_dir), sample_dir) as wip_dir:
|
|
206
|
-
ffmpeg.
|
|
207
|
-
frame_samples = ffmpeglib.sort_selected_samples(wip_dir, video_path
|
|
197
|
+
ffmpeg.extract_frames_by_interval(video_path, wip_dir, sample_interval)
|
|
198
|
+
frame_samples = ffmpeglib.FFMPEG.sort_selected_samples(wip_dir, video_path)
|
|
208
199
|
for frame_idx_1based, sample_paths in frame_samples:
|
|
209
200
|
assert len(sample_paths) == 1
|
|
210
201
|
if sample_paths[0] is None:
|
|
@@ -229,7 +220,7 @@ def _sample_video_stream_by_distance(
|
|
|
229
220
|
points: T.Sequence[geo.Point],
|
|
230
221
|
video_track_parser: mp4_sample_parser.TrackBoxParser,
|
|
231
222
|
sample_distance: float,
|
|
232
|
-
) ->
|
|
223
|
+
) -> dict[int, tuple[mp4_sample_parser.Sample, geo.Point]]:
|
|
233
224
|
"""
|
|
234
225
|
Locate video frames along the track (points), then resample them by the minimal sample_distance, and return the sparse frames.
|
|
235
226
|
"""
|
|
@@ -285,7 +276,7 @@ def _sample_single_video_by_distance(
|
|
|
285
276
|
video_path: Path,
|
|
286
277
|
sample_dir: Path,
|
|
287
278
|
sample_distance: float,
|
|
288
|
-
start_time:
|
|
279
|
+
start_time: datetime.datetime | None = None,
|
|
289
280
|
) -> None:
|
|
290
281
|
ffmpeg = ffmpeglib.FFMPEG(constants.FFMPEG_PATH, constants.FFPROBE_PATH)
|
|
291
282
|
|
|
@@ -299,9 +290,12 @@ def _sample_single_video_by_distance(
|
|
|
299
290
|
)
|
|
300
291
|
|
|
301
292
|
LOG.info("Extracting video metdata")
|
|
302
|
-
|
|
303
|
-
|
|
293
|
+
|
|
294
|
+
video_metadatas = geotag_videos_from_video.GeotagVideosFromVideo().to_description(
|
|
295
|
+
[video_path]
|
|
304
296
|
)
|
|
297
|
+
assert len(video_metadatas) == 1, "expect 1 video metadata"
|
|
298
|
+
video_metadata = video_metadatas[0]
|
|
305
299
|
if isinstance(video_metadata, types.ErrorMetadata):
|
|
306
300
|
LOG.warning(str(video_metadata.error))
|
|
307
301
|
return
|
|
@@ -328,11 +322,11 @@ def _sample_single_video_by_distance(
|
|
|
328
322
|
video_path,
|
|
329
323
|
wip_dir,
|
|
330
324
|
frame_indices=set(sorted_sample_indices),
|
|
331
|
-
|
|
325
|
+
stream_specifier=str(video_stream_idx),
|
|
332
326
|
)
|
|
333
327
|
|
|
334
|
-
frame_samples = ffmpeglib.sort_selected_samples(
|
|
335
|
-
wip_dir, video_path, [video_stream_idx]
|
|
328
|
+
frame_samples = ffmpeglib.FFMPEG.sort_selected_samples(
|
|
329
|
+
wip_dir, video_path, selected_stream_specifiers=[str(video_stream_idx)]
|
|
336
330
|
)
|
|
337
331
|
if len(frame_samples) != len(sorted_sample_indices):
|
|
338
332
|
raise exceptions.MapillaryVideoError(
|