mapillary-tools 0.14.0a1__py3-none-any.whl → 0.14.0a2__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 (67) hide show
  1. mapillary_tools/__init__.py +1 -1
  2. mapillary_tools/api_v4.py +4 -4
  3. mapillary_tools/camm/camm_parser.py +5 -5
  4. mapillary_tools/commands/__main__.py +1 -2
  5. mapillary_tools/config.py +7 -5
  6. mapillary_tools/constants.py +1 -2
  7. mapillary_tools/exceptions.py +1 -1
  8. mapillary_tools/exif_read.py +65 -65
  9. mapillary_tools/exif_write.py +7 -7
  10. mapillary_tools/exiftool_read.py +23 -46
  11. mapillary_tools/exiftool_read_video.py +36 -34
  12. mapillary_tools/ffmpeg.py +24 -23
  13. mapillary_tools/geo.py +4 -21
  14. mapillary_tools/geotag/{geotag_from_generic.py → base.py} +32 -48
  15. mapillary_tools/geotag/factory.py +27 -34
  16. mapillary_tools/geotag/geotag_images_from_exif.py +15 -51
  17. mapillary_tools/geotag/geotag_images_from_exiftool.py +107 -59
  18. mapillary_tools/geotag/geotag_images_from_gpx.py +20 -10
  19. mapillary_tools/geotag/geotag_images_from_gpx_file.py +2 -34
  20. mapillary_tools/geotag/geotag_images_from_nmea_file.py +0 -3
  21. mapillary_tools/geotag/geotag_images_from_video.py +16 -14
  22. mapillary_tools/geotag/geotag_videos_from_exiftool.py +97 -0
  23. mapillary_tools/geotag/geotag_videos_from_gpx.py +14 -115
  24. mapillary_tools/geotag/geotag_videos_from_video.py +14 -147
  25. mapillary_tools/geotag/image_extractors/base.py +18 -0
  26. mapillary_tools/geotag/image_extractors/exif.py +60 -0
  27. mapillary_tools/geotag/image_extractors/exiftool.py +18 -0
  28. mapillary_tools/geotag/options.py +1 -0
  29. mapillary_tools/geotag/utils.py +62 -0
  30. mapillary_tools/geotag/video_extractors/base.py +18 -0
  31. mapillary_tools/geotag/video_extractors/exiftool.py +70 -0
  32. mapillary_tools/{video_data_extraction/extractors/gpx_parser.py → geotag/video_extractors/gpx.py} +57 -39
  33. mapillary_tools/geotag/video_extractors/native.py +157 -0
  34. mapillary_tools/gpmf/gpmf_parser.py +16 -16
  35. mapillary_tools/gpmf/gps_filter.py +5 -3
  36. mapillary_tools/history.py +4 -2
  37. mapillary_tools/mp4/construct_mp4_parser.py +9 -8
  38. mapillary_tools/mp4/mp4_sample_parser.py +27 -27
  39. mapillary_tools/mp4/simple_mp4_builder.py +10 -9
  40. mapillary_tools/mp4/simple_mp4_parser.py +13 -12
  41. mapillary_tools/process_geotag_properties.py +5 -7
  42. mapillary_tools/process_sequence_properties.py +40 -38
  43. mapillary_tools/sample_video.py +8 -8
  44. mapillary_tools/telemetry.py +6 -5
  45. mapillary_tools/types.py +33 -38
  46. mapillary_tools/utils.py +16 -18
  47. {mapillary_tools-0.14.0a1.dist-info → mapillary_tools-0.14.0a2.dist-info}/METADATA +1 -1
  48. mapillary_tools-0.14.0a2.dist-info/RECORD +72 -0
  49. mapillary_tools/geotag/__init__.py +0 -1
  50. mapillary_tools/geotag/geotag_images_from_exiftool_both_image_and_video.py +0 -77
  51. mapillary_tools/geotag/geotag_videos_from_exiftool_video.py +0 -151
  52. mapillary_tools/video_data_extraction/cli_options.py +0 -22
  53. mapillary_tools/video_data_extraction/extract_video_data.py +0 -157
  54. mapillary_tools/video_data_extraction/extractors/base_parser.py +0 -75
  55. mapillary_tools/video_data_extraction/extractors/blackvue_parser.py +0 -49
  56. mapillary_tools/video_data_extraction/extractors/camm_parser.py +0 -62
  57. mapillary_tools/video_data_extraction/extractors/exiftool_runtime_parser.py +0 -74
  58. mapillary_tools/video_data_extraction/extractors/exiftool_xml_parser.py +0 -52
  59. mapillary_tools/video_data_extraction/extractors/generic_video_parser.py +0 -52
  60. mapillary_tools/video_data_extraction/extractors/gopro_parser.py +0 -58
  61. mapillary_tools/video_data_extraction/extractors/nmea_parser.py +0 -24
  62. mapillary_tools/video_data_extraction/video_data_parser_factory.py +0 -39
  63. mapillary_tools-0.14.0a1.dist-info/RECORD +0 -78
  64. {mapillary_tools-0.14.0a1.dist-info → mapillary_tools-0.14.0a2.dist-info}/WHEEL +0 -0
  65. {mapillary_tools-0.14.0a1.dist-info → mapillary_tools-0.14.0a2.dist-info}/entry_points.txt +0 -0
  66. {mapillary_tools-0.14.0a1.dist-info → mapillary_tools-0.14.0a2.dist-info}/licenses/LICENSE +0 -0
  67. {mapillary_tools-0.14.0a1.dist-info → mapillary_tools-0.14.0a2.dist-info}/top_level.txt +0 -0
@@ -1,157 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import logging
4
- import typing as T
5
- from pathlib import Path
6
-
7
- import tqdm
8
-
9
- from .. import exceptions, geo, utils
10
- from ..gpmf import gpmf_gps_filter
11
- from ..telemetry import GPSPoint
12
- from ..types import ErrorMetadata, FileType, VideoMetadata, VideoMetadataOrError
13
- from . import video_data_parser_factory
14
- from .cli_options import CliOptions
15
- from .extractors.base_parser import BaseParser
16
-
17
-
18
- LOG = logging.getLogger(__name__)
19
-
20
-
21
- class VideoDataExtractor:
22
- options: CliOptions
23
-
24
- def __init__(self, options: CliOptions) -> None:
25
- self.options = options
26
-
27
- def process(self) -> T.List[VideoMetadataOrError]:
28
- paths = self.options["paths"]
29
- self._check_paths(paths)
30
- video_files = utils.find_videos(paths)
31
- self._check_sources_cardinality(video_files)
32
-
33
- map_results = utils.mp_map_maybe(
34
- self.process_file, video_files, num_processes=self.options["num_processes"]
35
- )
36
-
37
- video_metadata_or_errors: list[VideoMetadataOrError] = list(
38
- tqdm.tqdm(
39
- map_results,
40
- desc="Extracting GPS tracks",
41
- unit="videos",
42
- disable=LOG.getEffectiveLevel() <= logging.DEBUG,
43
- total=len(video_files),
44
- )
45
- )
46
-
47
- return video_metadata_or_errors
48
-
49
- def process_file(self, file: Path) -> VideoMetadataOrError:
50
- parsers = video_data_parser_factory.make_parsers(file, self.options)
51
- points: T.Sequence[geo.Point] = []
52
- make = self.options["device_make"]
53
- model = self.options["device_model"]
54
-
55
- ex: T.Optional[Exception]
56
- for parser in parsers:
57
- log_vars = {
58
- "filename": file,
59
- "parser": parser.parser_label,
60
- "source": parser.geotag_source_path,
61
- }
62
- try:
63
- if not points:
64
- points = self._extract_points(parser, log_vars)
65
- if not model:
66
- model = parser.extract_model()
67
- if not make:
68
- make = parser.extract_make()
69
- except Exception as e:
70
- ex = e
71
- LOG.warning(
72
- '%(filename)s: Exception for parser %(parser)s while processing source %(source)s: "%(e)s"',
73
- {**log_vars, "e": e},
74
- )
75
-
76
- # After trying all parsers, return the points if we found any, otherwise
77
- # the last exception thrown or a default one.
78
- # Note that if we have points, we return them, regardless of exceptions
79
- # with make or model.
80
- if points:
81
- video_metadata = VideoMetadata(
82
- filename=file,
83
- filetype=FileType.VIDEO,
84
- filesize=utils.get_file_size(file),
85
- points=points,
86
- make=make,
87
- model=model,
88
- )
89
- return video_metadata
90
- else:
91
- return ErrorMetadata(
92
- filename=file,
93
- error=(
94
- ex
95
- if ex
96
- else exceptions.MapillaryVideoGPSNotFoundError(
97
- "No GPS data found from the video"
98
- )
99
- ),
100
- filetype=FileType.VIDEO,
101
- )
102
-
103
- def _extract_points(
104
- self, parser: BaseParser, log_vars: T.Dict
105
- ) -> T.Sequence[geo.Point]:
106
- points = parser.extract_points()
107
- if points:
108
- LOG.debug(
109
- "%(filename)s: %(points)d points extracted by parser %(parser)s from file %(source)s}",
110
- {**log_vars, "points": len(points)},
111
- )
112
-
113
- return self._sanitize_points(points)
114
-
115
- @staticmethod
116
- def _check_paths(import_paths: T.Sequence[Path]):
117
- for path in import_paths:
118
- if not path.is_file() and not path.is_dir():
119
- raise exceptions.MapillaryFileNotFoundError(
120
- f"Import file or directory not found: {path}"
121
- )
122
-
123
- def _check_sources_cardinality(self, files: T.Sequence[Path]):
124
- if len(files) > 1:
125
- for parser_opts in self.options["geotag_sources_options"]:
126
- pattern = parser_opts.get("pattern")
127
- if pattern and "%" not in pattern:
128
- raise exceptions.MapillaryUserError(
129
- "Multiple video files found: Geotag source pattern for source %s must include filename placeholders",
130
- parser_opts["source"],
131
- )
132
-
133
- @staticmethod
134
- def _sanitize_points(points: T.Sequence[geo.Point]) -> T.Sequence[geo.Point]:
135
- """
136
- Deduplicates points, when possible removes noisy ones, and checks
137
- against stationary videos
138
- """
139
-
140
- if not points:
141
- raise exceptions.MapillaryVideoGPSNotFoundError(
142
- "No GPS data found in the given sources"
143
- )
144
-
145
- points = geo.extend_deduplicate_points(points)
146
-
147
- if all(isinstance(p, GPSPoint) for p in points):
148
- points = T.cast(
149
- T.Sequence[geo.Point],
150
- gpmf_gps_filter.remove_noisy_points(
151
- T.cast(T.Sequence[GPSPoint], points)
152
- ),
153
- )
154
- if not points:
155
- raise exceptions.MapillaryGPSNoiseError("GPS is too noisy")
156
-
157
- return points
@@ -1,75 +0,0 @@
1
- import abc
2
- import functools
3
- import logging
4
- import os
5
- import typing as T
6
- from pathlib import Path
7
-
8
- from ... import geo
9
- from ..cli_options import CliOptions, CliParserOptions
10
-
11
- LOG = logging.getLogger(__name__)
12
-
13
-
14
- class BaseParser(metaclass=abc.ABCMeta):
15
- videoPath: Path
16
- options: CliOptions
17
- parserOptions: CliParserOptions
18
-
19
- def __init__(
20
- self, video_path: Path, options: CliOptions, parser_options: CliParserOptions
21
- ) -> None:
22
- self.videoPath = video_path
23
- self.options = options
24
- self.parserOptions = parser_options
25
-
26
- @property
27
- @abc.abstractmethod
28
- def default_source_pattern(self) -> str:
29
- raise NotImplementedError
30
-
31
- @property
32
- @abc.abstractmethod
33
- def parser_label(self) -> str:
34
- raise NotImplementedError
35
-
36
- @abc.abstractmethod
37
- def extract_points(self) -> T.Sequence[geo.Point]:
38
- raise NotImplementedError
39
-
40
- @abc.abstractmethod
41
- def extract_make(self) -> T.Optional[str]:
42
- raise NotImplementedError
43
-
44
- @abc.abstractmethod
45
- def extract_model(self) -> T.Optional[str]:
46
- raise NotImplementedError
47
-
48
- @functools.cached_property
49
- def geotag_source_path(self) -> T.Optional[Path]:
50
- video_dir = self.videoPath.parent.resolve()
51
- video_filename = self.videoPath.name
52
- video_basename, video_ext = os.path.splitext(video_filename)
53
- pattern = self.parserOptions.get("pattern") or self.default_source_pattern
54
-
55
- replaced = Path(
56
- pattern.replace("%f", video_filename)
57
- .replace("%g", video_basename)
58
- .replace("%e", video_ext)
59
- )
60
- abs_path = (
61
- replaced if replaced.is_absolute() else Path.joinpath(video_dir, replaced)
62
- ).resolve()
63
-
64
- return abs_path if abs_path.is_file() else None
65
-
66
- @staticmethod
67
- def _rebase_times(points: T.Sequence[geo.Point], offset: float = 0.0):
68
- """
69
- Make point times start from 0
70
- """
71
- if points:
72
- first_timestamp = points[0].time
73
- for p in points:
74
- p.time = (p.time - first_timestamp) + offset
75
- return points
@@ -1,49 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import functools
4
-
5
- import typing as T
6
-
7
- from ... import blackvue_parser, geo
8
- from .base_parser import BaseParser
9
-
10
-
11
- class BlackVueParser(BaseParser):
12
- default_source_pattern = "%f"
13
- must_rebase_times_to_zero = False
14
- parser_label = "blackvue"
15
-
16
- pointsFound: bool = False
17
-
18
- @functools.cached_property
19
- def extract_blackvue_info(self) -> blackvue_parser.BlackVueInfo | None:
20
- source_path = self.geotag_source_path
21
- if not source_path:
22
- return None
23
-
24
- with source_path.open("rb") as fp:
25
- return blackvue_parser.extract_blackvue_info(fp)
26
-
27
- def extract_points(self) -> T.Sequence[geo.Point]:
28
- blackvue_info = self.extract_blackvue_info
29
-
30
- if blackvue_info is None:
31
- return []
32
-
33
- return blackvue_info.gps or []
34
-
35
- def extract_make(self) -> str | None:
36
- blackvue_info = self.extract_blackvue_info
37
-
38
- if blackvue_info is None:
39
- return None
40
-
41
- return blackvue_info.make
42
-
43
- def extract_model(self) -> str | None:
44
- blackvue_info = self.extract_blackvue_info
45
-
46
- if blackvue_info is None:
47
- return None
48
-
49
- return blackvue_info.model
@@ -1,62 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import typing as T
4
-
5
- from ... import geo
6
- from ...camm import camm_parser
7
- from ...mp4 import simple_mp4_parser as sparser
8
- from .base_parser import BaseParser
9
-
10
-
11
- class CammParser(BaseParser):
12
- default_source_pattern = "%f"
13
- must_rebase_times_to_zero = False
14
- parser_label = "camm"
15
-
16
- _extracted: bool = False
17
- _cached_camm_info: camm_parser.CAMMInfo | None = None
18
-
19
- # TODO: use @functools.cached_property
20
- def _extract_camm_info(self) -> camm_parser.CAMMInfo | None:
21
- if self._extracted:
22
- return self._cached_camm_info
23
-
24
- self._extracted = True
25
-
26
- source_path = self.geotag_source_path
27
-
28
- if source_path is None:
29
- # source_path not found
30
- return None
31
-
32
- with source_path.open("rb") as fp:
33
- try:
34
- self._cached_camm_info = camm_parser.extract_camm_info(fp)
35
- except sparser.ParsingError:
36
- self._cached_camm_info = None
37
-
38
- return self._cached_camm_info
39
-
40
- def extract_points(self) -> T.Sequence[geo.Point]:
41
- camm_info = self._extract_camm_info()
42
-
43
- if camm_info is None:
44
- return []
45
-
46
- return T.cast(T.List[geo.Point], camm_info.gps or camm_info.mini_gps)
47
-
48
- def extract_make(self) -> str | None:
49
- camm_info = self._extract_camm_info()
50
-
51
- if camm_info is None:
52
- return None
53
-
54
- return camm_info.make
55
-
56
- def extract_model(self) -> str | None:
57
- camm_info = self._extract_camm_info()
58
-
59
- if camm_info is None:
60
- return None
61
-
62
- return camm_info.model
@@ -1,74 +0,0 @@
1
- import shutil
2
- import subprocess
3
- import typing as T
4
- from pathlib import Path
5
-
6
- from ... import constants, exceptions, geo
7
- from ..cli_options import CliOptions, CliParserOptions
8
- from .base_parser import BaseParser
9
- from .exiftool_xml_parser import ExiftoolXmlParser
10
-
11
-
12
- class ExiftoolRuntimeParser(BaseParser):
13
- """
14
- Wrapper around ExiftoolRdfParser that executes exiftool
15
- """
16
-
17
- exiftoolXmlParser: ExiftoolXmlParser
18
-
19
- default_source_pattern = "%f"
20
- must_rebase_times_to_zero = True
21
- parser_label = "exiftool_runtime"
22
-
23
- def __init__(
24
- self, video_path: Path, options: CliOptions, parser_options: CliParserOptions
25
- ):
26
- super().__init__(video_path, options, parser_options)
27
- if constants.EXIFTOOL_PATH is None:
28
- exiftool_path = shutil.which("exiftool")
29
- else:
30
- exiftool_path = shutil.which(constants.EXIFTOOL_PATH)
31
-
32
- if not exiftool_path:
33
- raise exceptions.MapillaryExiftoolNotFoundError(
34
- "Cannot execute exiftool. Please install it from https://exiftool.org/ or you package manager, or set the environment variable MAPILLARY_TOOLS_EXIFTOOL_PATH"
35
- )
36
- if not self.geotag_source_path:
37
- return
38
-
39
- # To handle non-latin1 filenames under Windows, we pass the path
40
- # via stdin. See https://exiftool.org/faq.html#Q18
41
- stdin = str(self.geotag_source_path)
42
- args = [
43
- exiftool_path,
44
- "-q",
45
- "-r",
46
- "-n",
47
- "-ee",
48
- "-api",
49
- "LargeFileSupport=1",
50
- "-X",
51
- "-charset",
52
- "filename=utf8",
53
- "-@",
54
- "-",
55
- ]
56
-
57
- process = subprocess.run(
58
- args, capture_output=True, text=True, input=stdin, encoding="utf-8"
59
- )
60
-
61
- self.exiftoolXmlParser = ExiftoolXmlParser(
62
- video_path, options, parser_options, process.stdout
63
- )
64
-
65
- def extract_points(self) -> T.Sequence[geo.Point]:
66
- return self.exiftoolXmlParser.extract_points() if self.exiftoolXmlParser else []
67
-
68
- def extract_make(self) -> T.Optional[str]:
69
- return self.exiftoolXmlParser.extract_make() if self.exiftoolXmlParser else None
70
-
71
- def extract_model(self) -> T.Optional[str]:
72
- return (
73
- self.exiftoolXmlParser.extract_model() if self.exiftoolXmlParser else None
74
- )
@@ -1,52 +0,0 @@
1
- import typing as T
2
- import xml.etree.ElementTree as ET
3
-
4
- from pathlib import Path
5
-
6
- from ... import geo
7
- from ...exiftool_read import _DESCRIPTION_TAG, EXIFTOOL_NAMESPACES
8
- from ...exiftool_read_video import ExifToolReadVideo
9
- from ..cli_options import CliOptions, CliParserOptions
10
- from .base_parser import BaseParser
11
-
12
-
13
- class ExiftoolXmlParser(BaseParser):
14
- default_source_pattern = "%g.xml"
15
- parser_label = "exiftool_xml"
16
-
17
- exifToolReadVideo: T.Optional[ExifToolReadVideo] = None
18
-
19
- def __init__(
20
- self,
21
- video_path: Path,
22
- options: CliOptions,
23
- parser_options: CliParserOptions,
24
- xml_content: T.Optional[str] = None,
25
- ) -> None:
26
- super().__init__(video_path, options, parser_options)
27
-
28
- if xml_content:
29
- etree = ET.fromstring(xml_content)
30
- else:
31
- xml_path = self.geotag_source_path
32
- if not xml_path:
33
- return
34
- etree = ET.parse(xml_path).getroot()
35
-
36
- element = next(etree.iterfind(_DESCRIPTION_TAG, namespaces=EXIFTOOL_NAMESPACES))
37
- self.exifToolReadVideo = ExifToolReadVideo(ET.ElementTree(element))
38
-
39
- def extract_points(self) -> T.Sequence[geo.Point]:
40
- gps_points = (
41
- self.exifToolReadVideo.extract_gps_track() if self.exifToolReadVideo else []
42
- )
43
- self._rebase_times(gps_points)
44
- return gps_points
45
-
46
- def extract_make(self) -> T.Optional[str]:
47
- return self.exifToolReadVideo.extract_make() if self.exifToolReadVideo else None
48
-
49
- def extract_model(self) -> T.Optional[str]:
50
- return (
51
- self.exifToolReadVideo.extract_model() if self.exifToolReadVideo else None
52
- )
@@ -1,52 +0,0 @@
1
- import typing as T
2
- from pathlib import Path
3
-
4
- from ... import geo
5
- from ..cli_options import CliOptions, CliParserOptions
6
- from .base_parser import BaseParser
7
- from .blackvue_parser import BlackVueParser
8
- from .camm_parser import CammParser
9
- from .gopro_parser import GoProParser
10
-
11
-
12
- class GenericVideoParser(BaseParser):
13
- """
14
- Wrapper around the three native video parsers. It will try to execute them
15
- in the order camm-gopro-blackvue, like the previous implementation
16
- """
17
-
18
- parsers: T.Sequence[BaseParser] = []
19
-
20
- default_source_pattern = "%f"
21
- must_rebase_times_to_zero = False
22
- parser_label = "video"
23
-
24
- def __init__(
25
- self, video_path: Path, options: CliOptions, parser_options: CliParserOptions
26
- ) -> None:
27
- super().__init__(video_path, options, parser_options)
28
- camm_parser = CammParser(video_path, options, parser_options)
29
- gopro_parser = GoProParser(video_path, options, parser_options)
30
- blackvue_parser = BlackVueParser(video_path, options, parser_options)
31
- self.parsers = [camm_parser, gopro_parser, blackvue_parser]
32
-
33
- def extract_points(self) -> T.Sequence[geo.Point]:
34
- for parser in self.parsers:
35
- points = parser.extract_points()
36
- if points:
37
- return points
38
- return []
39
-
40
- def extract_make(self) -> T.Optional[str]:
41
- for parser in self.parsers:
42
- make = parser.extract_make()
43
- if make:
44
- return make
45
- return None
46
-
47
- def extract_model(self) -> T.Optional[str]:
48
- for parser in self.parsers:
49
- model = parser.extract_model()
50
- if model:
51
- return model
52
- return None
@@ -1,58 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import typing as T
4
-
5
- from ... import geo
6
- from ...gpmf import gpmf_parser
7
- from ...mp4 import simple_mp4_parser as sparser
8
- from .base_parser import BaseParser
9
-
10
-
11
- class GoProParser(BaseParser):
12
- default_source_pattern = "%f"
13
- must_rebase_times_to_zero = False
14
- parser_label = "gopro"
15
-
16
- _extracted: bool = False
17
- _cached_gopro_info: gpmf_parser.GoProInfo | None = None
18
-
19
- def _extract_gopro_info(self) -> gpmf_parser.GoProInfo | None:
20
- if self._extracted:
21
- return self._cached_gopro_info
22
-
23
- self._extracted = True
24
-
25
- source_path = self.geotag_source_path
26
-
27
- if source_path is None:
28
- # source_path not found
29
- return None
30
-
31
- with source_path.open("rb") as fp:
32
- try:
33
- self._cached_gopro_info = gpmf_parser.extract_gopro_info(fp)
34
- except sparser.ParsingError:
35
- self._cached_gopro_info = None
36
-
37
- return self._cached_gopro_info
38
-
39
- def extract_points(self) -> T.Sequence[geo.Point]:
40
- gopro_info = self._extract_gopro_info()
41
- if gopro_info is None:
42
- return []
43
-
44
- return T.cast(T.Sequence[geo.Point], gopro_info.gps)
45
-
46
- def extract_make(self) -> str | None:
47
- gopro_info = self._extract_gopro_info()
48
- if gopro_info is None:
49
- return None
50
-
51
- return gopro_info.make
52
-
53
- def extract_model(self) -> str | None:
54
- gopro_info = self._extract_gopro_info()
55
- if gopro_info is None:
56
- return None
57
-
58
- return gopro_info.model
@@ -1,24 +0,0 @@
1
- import typing as T
2
-
3
- from ... import geo
4
- from ...geotag import geotag_images_from_nmea_file
5
- from .base_parser import BaseParser
6
-
7
-
8
- class NmeaParser(BaseParser):
9
- default_source_pattern = "%g.nmea"
10
- must_rebase_times_to_zero = True
11
- parser_label = "nmea"
12
-
13
- def extract_points(self) -> T.Sequence[geo.Point]:
14
- source_path = self.geotag_source_path
15
- if not source_path:
16
- return []
17
- points = geotag_images_from_nmea_file.get_lat_lon_time_from_nmea(source_path)
18
- return points
19
-
20
- def extract_make(self) -> T.Optional[str]:
21
- return None
22
-
23
- def extract_model(self) -> T.Optional[str]:
24
- return None
@@ -1,39 +0,0 @@
1
- import typing as T
2
- from pathlib import Path
3
-
4
- from .cli_options import CliOptions
5
-
6
- from .extractors.base_parser import BaseParser
7
-
8
- from .extractors.blackvue_parser import BlackVueParser
9
- from .extractors.camm_parser import CammParser
10
-
11
- from .extractors.exiftool_runtime_parser import ExiftoolRuntimeParser
12
- from .extractors.exiftool_xml_parser import ExiftoolXmlParser
13
- from .extractors.generic_video_parser import GenericVideoParser
14
- from .extractors.gopro_parser import GoProParser
15
- from .extractors.gpx_parser import GpxParser
16
- from .extractors.nmea_parser import NmeaParser
17
-
18
-
19
- known_parsers = {
20
- "gpx": GpxParser,
21
- "nmea": NmeaParser,
22
- "exiftool_xml": ExiftoolXmlParser,
23
- "exiftool_runtime": ExiftoolRuntimeParser,
24
- "camm": CammParser,
25
- "blackvue": BlackVueParser,
26
- "gopro": GoProParser,
27
- "video": GenericVideoParser,
28
- }
29
-
30
-
31
- def make_parsers(file: Path, options: CliOptions) -> T.Sequence[BaseParser]:
32
- src_options = options["geotag_sources_options"]
33
- parsers = [
34
- known_parsers[s["source"]](file, options, s)
35
- for s in src_options
36
- if s["source"] in known_parsers
37
- ]
38
-
39
- return parsers