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.
Files changed (87) hide show
  1. mapillary_tools/__init__.py +1 -1
  2. mapillary_tools/api_v4.py +287 -22
  3. mapillary_tools/authenticate.py +326 -64
  4. mapillary_tools/blackvue_parser.py +195 -0
  5. mapillary_tools/camm/camm_builder.py +55 -97
  6. mapillary_tools/camm/camm_parser.py +429 -181
  7. mapillary_tools/commands/__main__.py +17 -8
  8. mapillary_tools/commands/authenticate.py +8 -1
  9. mapillary_tools/commands/process.py +27 -51
  10. mapillary_tools/commands/process_and_upload.py +19 -5
  11. mapillary_tools/commands/sample_video.py +2 -3
  12. mapillary_tools/commands/upload.py +44 -13
  13. mapillary_tools/commands/video_process_and_upload.py +19 -5
  14. mapillary_tools/config.py +65 -26
  15. mapillary_tools/constants.py +141 -18
  16. mapillary_tools/exceptions.py +37 -34
  17. mapillary_tools/exif_read.py +221 -116
  18. mapillary_tools/exif_write.py +10 -8
  19. mapillary_tools/exiftool_read.py +33 -42
  20. mapillary_tools/exiftool_read_video.py +97 -47
  21. mapillary_tools/exiftool_runner.py +57 -0
  22. mapillary_tools/ffmpeg.py +417 -242
  23. mapillary_tools/geo.py +158 -118
  24. mapillary_tools/geotag/__init__.py +0 -1
  25. mapillary_tools/geotag/base.py +147 -0
  26. mapillary_tools/geotag/factory.py +307 -0
  27. mapillary_tools/geotag/geotag_images_from_exif.py +14 -131
  28. mapillary_tools/geotag/geotag_images_from_exiftool.py +136 -85
  29. mapillary_tools/geotag/geotag_images_from_gpx.py +60 -124
  30. mapillary_tools/geotag/geotag_images_from_gpx_file.py +13 -126
  31. mapillary_tools/geotag/geotag_images_from_nmea_file.py +4 -5
  32. mapillary_tools/geotag/geotag_images_from_video.py +88 -51
  33. mapillary_tools/geotag/geotag_videos_from_exiftool.py +123 -0
  34. mapillary_tools/geotag/geotag_videos_from_gpx.py +52 -0
  35. mapillary_tools/geotag/geotag_videos_from_video.py +20 -185
  36. mapillary_tools/geotag/image_extractors/base.py +18 -0
  37. mapillary_tools/geotag/image_extractors/exif.py +60 -0
  38. mapillary_tools/geotag/image_extractors/exiftool.py +18 -0
  39. mapillary_tools/geotag/options.py +182 -0
  40. mapillary_tools/geotag/utils.py +52 -16
  41. mapillary_tools/geotag/video_extractors/base.py +18 -0
  42. mapillary_tools/geotag/video_extractors/exiftool.py +70 -0
  43. mapillary_tools/geotag/video_extractors/gpx.py +116 -0
  44. mapillary_tools/geotag/video_extractors/native.py +160 -0
  45. mapillary_tools/{geotag → gpmf}/gpmf_parser.py +205 -182
  46. mapillary_tools/{geotag → gpmf}/gps_filter.py +5 -3
  47. mapillary_tools/history.py +134 -20
  48. mapillary_tools/mp4/construct_mp4_parser.py +17 -10
  49. mapillary_tools/mp4/io_utils.py +0 -1
  50. mapillary_tools/mp4/mp4_sample_parser.py +36 -28
  51. mapillary_tools/mp4/simple_mp4_builder.py +10 -9
  52. mapillary_tools/mp4/simple_mp4_parser.py +13 -22
  53. mapillary_tools/process_geotag_properties.py +184 -414
  54. mapillary_tools/process_sequence_properties.py +594 -225
  55. mapillary_tools/sample_video.py +20 -26
  56. mapillary_tools/serializer/description.py +587 -0
  57. mapillary_tools/serializer/gpx.py +132 -0
  58. mapillary_tools/telemetry.py +26 -13
  59. mapillary_tools/types.py +98 -611
  60. mapillary_tools/upload.py +408 -416
  61. mapillary_tools/upload_api_v4.py +172 -174
  62. mapillary_tools/uploader.py +804 -284
  63. mapillary_tools/utils.py +49 -18
  64. {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/METADATA +93 -35
  65. mapillary_tools-0.14.0.dist-info/RECORD +75 -0
  66. {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/WHEEL +1 -1
  67. mapillary_tools/geotag/blackvue_parser.py +0 -118
  68. mapillary_tools/geotag/geotag_from_generic.py +0 -22
  69. mapillary_tools/geotag/geotag_images_from_exiftool_both_image_and_video.py +0 -93
  70. mapillary_tools/geotag/geotag_videos_from_exiftool_video.py +0 -145
  71. mapillary_tools/video_data_extraction/cli_options.py +0 -22
  72. mapillary_tools/video_data_extraction/extract_video_data.py +0 -176
  73. mapillary_tools/video_data_extraction/extractors/base_parser.py +0 -75
  74. mapillary_tools/video_data_extraction/extractors/blackvue_parser.py +0 -34
  75. mapillary_tools/video_data_extraction/extractors/camm_parser.py +0 -38
  76. mapillary_tools/video_data_extraction/extractors/exiftool_runtime_parser.py +0 -71
  77. mapillary_tools/video_data_extraction/extractors/exiftool_xml_parser.py +0 -53
  78. mapillary_tools/video_data_extraction/extractors/generic_video_parser.py +0 -52
  79. mapillary_tools/video_data_extraction/extractors/gopro_parser.py +0 -43
  80. mapillary_tools/video_data_extraction/extractors/gpx_parser.py +0 -108
  81. mapillary_tools/video_data_extraction/extractors/nmea_parser.py +0 -24
  82. mapillary_tools/video_data_extraction/video_data_parser_factory.py +0 -39
  83. mapillary_tools-0.13.3a1.dist-info/RECORD +0 -75
  84. /mapillary_tools/{geotag → gpmf}/gpmf_gps_filter.py +0 -0
  85. {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/entry_points.txt +0 -0
  86. {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info/licenses}/LICENSE +0 -0
  87. {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0.dist-info}/top_level.txt +0 -0
@@ -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 .process_geotag_properties import GeotagSource
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
- ) -> T.Tuple[Path, T.List[Path]]:
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: T.Optional[str] = None,
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: T.Optional[datetime.datetime] = None
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 = types.map_capture_time_to_datetime(video_start_time)
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: T.Optional[datetime.datetime] = None,
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.extract_frames(video_path, wip_dir, sample_interval)
207
- frame_samples = ffmpeglib.sort_selected_samples(wip_dir, video_path, [None])
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
- ) -> T.Dict[int, T.Tuple[mp4_sample_parser.Sample, geo.Point]]:
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: T.Optional[datetime.datetime] = None,
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
- video_metadata = geotag_videos_from_video.GeotagVideosFromVideo.geotag_video(
303
- video_path
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
- stream_idx=video_stream_idx,
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(