mapillary-tools 0.13.3a1__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.
- mapillary_tools/__init__.py +1 -1
- mapillary_tools/api_v4.py +237 -16
- mapillary_tools/authenticate.py +325 -64
- mapillary_tools/{geotag/blackvue_parser.py → blackvue_parser.py} +74 -54
- mapillary_tools/camm/camm_builder.py +55 -97
- mapillary_tools/camm/camm_parser.py +429 -181
- mapillary_tools/commands/__main__.py +12 -6
- 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 +18 -9
- mapillary_tools/commands/video_process_and_upload.py +19 -5
- mapillary_tools/config.py +31 -13
- mapillary_tools/constants.py +47 -6
- mapillary_tools/exceptions.py +34 -35
- mapillary_tools/exif_read.py +221 -116
- mapillary_tools/exif_write.py +7 -7
- mapillary_tools/exiftool_read.py +33 -42
- mapillary_tools/exiftool_read_video.py +46 -33
- mapillary_tools/exiftool_runner.py +77 -0
- mapillary_tools/ffmpeg.py +24 -23
- mapillary_tools/geo.py +144 -120
- mapillary_tools/geotag/base.py +147 -0
- mapillary_tools/geotag/factory.py +291 -0
- mapillary_tools/geotag/geotag_images_from_exif.py +14 -131
- mapillary_tools/geotag/geotag_images_from_exiftool.py +126 -82
- mapillary_tools/geotag/geotag_images_from_gpx.py +53 -118
- 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 +53 -51
- mapillary_tools/geotag/geotag_videos_from_exiftool.py +97 -0
- mapillary_tools/geotag/geotag_videos_from_gpx.py +39 -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 +160 -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/{video_data_extraction/extractors/gpx_parser.py → geotag/video_extractors/gpx.py} +57 -39
- mapillary_tools/geotag/video_extractors/native.py +157 -0
- mapillary_tools/{geotag → gpmf}/gpmf_parser.py +205 -182
- mapillary_tools/{geotag → gpmf}/gps_filter.py +5 -3
- mapillary_tools/history.py +7 -13
- mapillary_tools/mp4/construct_mp4_parser.py +9 -8
- 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 +155 -392
- mapillary_tools/process_sequence_properties.py +562 -208
- mapillary_tools/sample_video.py +13 -20
- mapillary_tools/telemetry.py +26 -13
- mapillary_tools/types.py +111 -58
- mapillary_tools/upload.py +316 -298
- mapillary_tools/upload_api_v4.py +55 -122
- mapillary_tools/uploader.py +396 -254
- mapillary_tools/utils.py +42 -18
- {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0a2.dist-info}/METADATA +3 -2
- mapillary_tools-0.14.0a2.dist-info/RECORD +72 -0
- {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0a2.dist-info}/WHEEL +1 -1
- mapillary_tools/geotag/__init__.py +0 -1
- 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/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.0a2.dist-info}/entry_points.txt +0 -0
- {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0a2.dist-info/licenses}/LICENSE +0 -0
- {mapillary_tools-0.13.3a1.dist-info → mapillary_tools-0.14.0a2.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# pyre-ignore-all-errors[5, 16, 21, 58]
|
|
2
|
+
from __future__ import annotations
|
|
2
3
|
|
|
3
4
|
import typing as T
|
|
4
5
|
|
|
@@ -42,7 +43,7 @@ BoxType = T.Literal[
|
|
|
42
43
|
|
|
43
44
|
class BoxDict(T.TypedDict, total=True):
|
|
44
45
|
type: BoxType
|
|
45
|
-
data: T.
|
|
46
|
+
data: T.Sequence["BoxDict"] | dict[str, T.Any] | bytes
|
|
46
47
|
|
|
47
48
|
|
|
48
49
|
_UNITY_MATRIX = [0x10000, 0, 0, 0, 0x10000, 0, 0, 0, 0x40000000]
|
|
@@ -376,7 +377,7 @@ class Box64ConstructBuilder:
|
|
|
376
377
|
NOTE: Do not build data with this struct. For building, use Box32StructBuilder instead.
|
|
377
378
|
"""
|
|
378
379
|
|
|
379
|
-
_box:
|
|
380
|
+
_box: C.Construct | None
|
|
380
381
|
|
|
381
382
|
def __init__(
|
|
382
383
|
self,
|
|
@@ -438,7 +439,7 @@ class Box64ConstructBuilder:
|
|
|
438
439
|
def parse_box(self, data: bytes) -> BoxDict:
|
|
439
440
|
return T.cast(BoxDict, self.Box.parse(data))
|
|
440
441
|
|
|
441
|
-
def parse_boxlist(self, data: bytes) ->
|
|
442
|
+
def parse_boxlist(self, data: bytes) -> list[BoxDict]:
|
|
442
443
|
return T.cast(T.List[BoxDict], self.BoxList.parse(data))
|
|
443
444
|
|
|
444
445
|
|
|
@@ -464,7 +465,7 @@ class Box32ConstructBuilder(Box64ConstructBuilder):
|
|
|
464
465
|
def parse_box(self, data: bytes) -> BoxDict:
|
|
465
466
|
raise NotImplementedError("Box32ConstructBuilder does not support parsing")
|
|
466
467
|
|
|
467
|
-
def parse_boxlist(self, data: bytes) ->
|
|
468
|
+
def parse_boxlist(self, data: bytes) -> list[BoxDict]:
|
|
468
469
|
raise NotImplementedError("Box32ConstructBuilder does not support parsing")
|
|
469
470
|
|
|
470
471
|
def build_box(self, box: BoxDict) -> bytes:
|
|
@@ -584,7 +585,7 @@ MOOVWithoutSTBLBuilderConstruct = Box32ConstructBuilder(
|
|
|
584
585
|
|
|
585
586
|
|
|
586
587
|
def find_box_at_pathx(
|
|
587
|
-
box: T.
|
|
588
|
+
box: T.Sequence[BoxDict] | BoxDict, path: T.Sequence[bytes]
|
|
588
589
|
) -> BoxDict:
|
|
589
590
|
found = find_box_at_path(box, path)
|
|
590
591
|
if found is None:
|
|
@@ -593,8 +594,8 @@ def find_box_at_pathx(
|
|
|
593
594
|
|
|
594
595
|
|
|
595
596
|
def find_box_at_path(
|
|
596
|
-
box: T.
|
|
597
|
-
) ->
|
|
597
|
+
box: T.Sequence[BoxDict] | BoxDict, path: T.Sequence[bytes]
|
|
598
|
+
) -> BoxDict | None:
|
|
598
599
|
if not path:
|
|
599
600
|
return None
|
|
600
601
|
|
|
@@ -608,7 +609,7 @@ def find_box_at_path(
|
|
|
608
609
|
if box["type"] == path[0]:
|
|
609
610
|
if len(path) == 1:
|
|
610
611
|
return box
|
|
611
|
-
box_data = T.cast(T.
|
|
612
|
+
box_data = T.cast(T.List[BoxDict], box["data"])
|
|
612
613
|
# ListContainer from construct is not sequence
|
|
613
614
|
assert isinstance(box_data, T.Sequence), (
|
|
614
615
|
f"expect a list of boxes but got {type(box_data)} at path {path}"
|
mapillary_tools/mp4/io_utils.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import datetime
|
|
2
4
|
import typing as T
|
|
3
5
|
from pathlib import Path
|
|
@@ -42,16 +44,16 @@ class Sample(T.NamedTuple):
|
|
|
42
44
|
exact_timedelta: float
|
|
43
45
|
|
|
44
46
|
# reference to the sample description
|
|
45
|
-
description:
|
|
47
|
+
description: dict
|
|
46
48
|
|
|
47
49
|
|
|
48
50
|
def _extract_raw_samples(
|
|
49
51
|
sizes: T.Sequence[int],
|
|
50
|
-
chunk_entries: T.Sequence[
|
|
52
|
+
chunk_entries: T.Sequence[dict],
|
|
51
53
|
chunk_offsets: T.Sequence[int],
|
|
52
54
|
timedeltas: T.Sequence[int],
|
|
53
|
-
composition_offsets:
|
|
54
|
-
syncs:
|
|
55
|
+
composition_offsets: list[int] | None,
|
|
56
|
+
syncs: set[int] | None,
|
|
55
57
|
) -> T.Generator[RawSample, None, None]:
|
|
56
58
|
if not sizes:
|
|
57
59
|
return
|
|
@@ -128,7 +130,7 @@ def _extract_raw_samples(
|
|
|
128
130
|
|
|
129
131
|
def _extract_samples(
|
|
130
132
|
raw_samples: T.Iterator[RawSample],
|
|
131
|
-
descriptions:
|
|
133
|
+
descriptions: list,
|
|
132
134
|
timescale: int,
|
|
133
135
|
) -> T.Generator[Sample, None, None]:
|
|
134
136
|
acc_delta = 0
|
|
@@ -152,21 +154,21 @@ STBLBoxlistConstruct = cparser.Box64ConstructBuilder(
|
|
|
152
154
|
|
|
153
155
|
def extract_raw_samples_from_stbl_data(
|
|
154
156
|
stbl: bytes,
|
|
155
|
-
) ->
|
|
156
|
-
descriptions = []
|
|
157
|
-
sizes = []
|
|
158
|
-
chunk_offsets = []
|
|
159
|
-
chunk_entries = []
|
|
160
|
-
timedeltas:
|
|
161
|
-
composition_offsets:
|
|
162
|
-
syncs:
|
|
157
|
+
) -> tuple[list[dict], T.Generator[RawSample, None, None]]:
|
|
158
|
+
descriptions: list[dict] = []
|
|
159
|
+
sizes: list[int] = []
|
|
160
|
+
chunk_offsets: list[int] = []
|
|
161
|
+
chunk_entries: list[dict] = []
|
|
162
|
+
timedeltas: list[int] = []
|
|
163
|
+
composition_offsets: list[int] | None = None
|
|
164
|
+
syncs: set[int] | None = None
|
|
163
165
|
|
|
164
166
|
stbl_children = T.cast(
|
|
165
167
|
T.Sequence[cparser.BoxDict], STBLBoxlistConstruct.parse(stbl)
|
|
166
168
|
)
|
|
167
169
|
|
|
168
170
|
for box in stbl_children:
|
|
169
|
-
data:
|
|
171
|
+
data: dict = T.cast(dict, box["data"])
|
|
170
172
|
|
|
171
173
|
if box["type"] == b"stsd":
|
|
172
174
|
descriptions = list(data["entries"])
|
|
@@ -225,32 +227,32 @@ class TrackBoxParser:
|
|
|
225
227
|
)
|
|
226
228
|
self.stbl_data = T.cast(bytes, stbl["data"])
|
|
227
229
|
|
|
228
|
-
def extract_tkhd_boxdata(self) ->
|
|
230
|
+
def extract_tkhd_boxdata(self) -> dict:
|
|
229
231
|
return T.cast(
|
|
230
|
-
|
|
232
|
+
dict, cparser.find_box_at_pathx(self.trak_children, [b"tkhd"])["data"]
|
|
231
233
|
)
|
|
232
234
|
|
|
233
235
|
def is_video_track(self) -> bool:
|
|
234
236
|
hdlr = cparser.find_box_at_pathx(self.trak_children, [b"mdia", b"hdlr"])
|
|
235
237
|
return T.cast(T.Dict[str, T.Any], hdlr["data"])["handler_type"] == b"vide"
|
|
236
238
|
|
|
237
|
-
def extract_sample_descriptions(self) ->
|
|
239
|
+
def extract_sample_descriptions(self) -> list[dict]:
|
|
238
240
|
# TODO: return [] if parsing fail
|
|
239
241
|
boxes = _STSDBoxListConstruct.parse(self.stbl_data)
|
|
240
242
|
stsd = cparser.find_box_at_pathx(
|
|
241
243
|
T.cast(T.Sequence[cparser.BoxDict], boxes), [b"stsd"]
|
|
242
244
|
)
|
|
243
|
-
return T.cast(T.List[
|
|
245
|
+
return T.cast(T.List[dict], T.cast(dict, stsd["data"])["entries"])
|
|
244
246
|
|
|
245
|
-
def extract_elst_boxdata(self) ->
|
|
247
|
+
def extract_elst_boxdata(self) -> dict | None:
|
|
246
248
|
box = cparser.find_box_at_path(self.trak_children, [b"edts", b"elst"])
|
|
247
249
|
if box is None:
|
|
248
250
|
return None
|
|
249
|
-
return T.cast(
|
|
251
|
+
return T.cast(dict, box["data"])
|
|
250
252
|
|
|
251
|
-
def extract_mdhd_boxdata(self) ->
|
|
253
|
+
def extract_mdhd_boxdata(self) -> dict:
|
|
252
254
|
box = cparser.find_box_at_pathx(self.trak_children, [b"mdia", b"mdhd"])
|
|
253
|
-
return T.cast(
|
|
255
|
+
return T.cast(dict, box["data"])
|
|
254
256
|
|
|
255
257
|
def extract_raw_samples(self) -> T.Generator[RawSample, None, None]:
|
|
256
258
|
_, raw_samples = extract_raw_samples_from_stbl_data(self.stbl_data)
|
|
@@ -259,7 +261,7 @@ class TrackBoxParser:
|
|
|
259
261
|
def extract_samples(self) -> T.Generator[Sample, None, None]:
|
|
260
262
|
descriptions, raw_samples = extract_raw_samples_from_stbl_data(self.stbl_data)
|
|
261
263
|
mdhd = T.cast(
|
|
262
|
-
|
|
264
|
+
dict,
|
|
263
265
|
cparser.find_box_at_pathx(self.trak_children, [b"mdia", b"mdhd"])["data"],
|
|
264
266
|
)
|
|
265
267
|
yield from _extract_samples(raw_samples, descriptions, mdhd["timescale"])
|
|
@@ -278,16 +280,22 @@ class MovieBoxParser:
|
|
|
278
280
|
def parse_file(cls, video_path: Path) -> "MovieBoxParser":
|
|
279
281
|
with video_path.open("rb") as fp:
|
|
280
282
|
moov = sparser.parse_box_data_firstx(fp, [b"moov"])
|
|
281
|
-
return
|
|
283
|
+
return cls(moov)
|
|
282
284
|
|
|
283
285
|
@classmethod
|
|
284
286
|
def parse_stream(cls, stream: T.BinaryIO) -> "MovieBoxParser":
|
|
285
287
|
moov = sparser.parse_box_data_firstx(stream, [b"moov"])
|
|
286
|
-
return
|
|
288
|
+
return cls(moov)
|
|
287
289
|
|
|
288
|
-
def extract_mvhd_boxdata(self) ->
|
|
290
|
+
def extract_mvhd_boxdata(self) -> dict:
|
|
289
291
|
mvhd = cparser.find_box_at_pathx(self.moov_children, [b"mvhd"])
|
|
290
|
-
return T.cast(
|
|
292
|
+
return T.cast(dict, mvhd["data"])
|
|
293
|
+
|
|
294
|
+
def extract_udta_boxdata(self) -> dict | None:
|
|
295
|
+
box = cparser.find_box_at_path(self.moov_children, [b"udta"])
|
|
296
|
+
if box is None:
|
|
297
|
+
return None
|
|
298
|
+
return T.cast(dict, box["data"])
|
|
291
299
|
|
|
292
300
|
def extract_tracks(self) -> T.Generator[TrackBoxParser, None, None]:
|
|
293
301
|
for box in self.moov_children:
|
|
@@ -312,7 +320,7 @@ class MovieBoxParser:
|
|
|
312
320
|
return TrackBoxParser(trak_children)
|
|
313
321
|
|
|
314
322
|
|
|
315
|
-
_DT_1904 = datetime.datetime.
|
|
323
|
+
_DT_1904 = datetime.datetime.fromtimestamp(0, datetime.timezone.utc).replace(year=1904)
|
|
316
324
|
|
|
317
325
|
|
|
318
326
|
def to_datetime(seconds_since_1904: int) -> datetime.datetime:
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import dataclasses
|
|
2
4
|
import io
|
|
3
5
|
import typing as T
|
|
@@ -64,8 +66,8 @@ class _SampleChunk:
|
|
|
64
66
|
offset: int
|
|
65
67
|
|
|
66
68
|
|
|
67
|
-
def _build_chunks(raw_samples: T.Iterable[RawSample]) ->
|
|
68
|
-
chunks:
|
|
69
|
+
def _build_chunks(raw_samples: T.Iterable[RawSample]) -> list[_SampleChunk]:
|
|
70
|
+
chunks: list[_SampleChunk] = []
|
|
69
71
|
prev_raw_sample = None
|
|
70
72
|
|
|
71
73
|
for raw_sample in raw_samples:
|
|
@@ -120,7 +122,7 @@ class _CompressedSampleDelta:
|
|
|
120
122
|
|
|
121
123
|
def _build_stts(sample_deltas: T.Iterable[int]) -> BoxDict:
|
|
122
124
|
# compress deltas
|
|
123
|
-
compressed:
|
|
125
|
+
compressed: list[_CompressedSampleDelta] = []
|
|
124
126
|
for delta in sample_deltas:
|
|
125
127
|
if compressed and delta == compressed[-1].sample_delta:
|
|
126
128
|
compressed[-1].sample_count += 1
|
|
@@ -146,7 +148,7 @@ class _CompressedSampleCompositionOffset:
|
|
|
146
148
|
|
|
147
149
|
def _build_ctts(sample_composition_offsets: T.Iterable[int]) -> BoxDict:
|
|
148
150
|
# compress offsets
|
|
149
|
-
compressed:
|
|
151
|
+
compressed: list[_CompressedSampleCompositionOffset] = []
|
|
150
152
|
for offset in sample_composition_offsets:
|
|
151
153
|
if compressed and offset == compressed[-1].sample_offset:
|
|
152
154
|
compressed[-1].sample_count += 1
|
|
@@ -182,7 +184,7 @@ def _build_stss(is_syncs: T.Iterable[bool]) -> BoxDict:
|
|
|
182
184
|
|
|
183
185
|
def build_stbl_from_raw_samples(
|
|
184
186
|
descriptions: T.Sequence[T.Any], raw_samples: T.Iterable[RawSample]
|
|
185
|
-
) ->
|
|
187
|
+
) -> list[BoxDict]:
|
|
186
188
|
# raw_samples could be iterator so convert to list
|
|
187
189
|
raw_samples = list(raw_samples)
|
|
188
190
|
# It is recommended that the boxes within the Sample Table Box be in the following order:
|
|
@@ -329,9 +331,8 @@ _MOOVChildrenParserConstruct = cparser.Box64ConstructBuilder(
|
|
|
329
331
|
|
|
330
332
|
def transform_mp4(
|
|
331
333
|
src_fp: T.BinaryIO,
|
|
332
|
-
sample_generator: T.
|
|
333
|
-
|
|
334
|
-
] = None,
|
|
334
|
+
sample_generator: T.Callable[[T.BinaryIO, list[BoxDict]], T.Iterator[io.IOBase]]
|
|
335
|
+
| None = None,
|
|
335
336
|
) -> io_utils.ChainedIO:
|
|
336
337
|
# extract ftyp
|
|
337
338
|
src_fp.seek(0)
|
|
@@ -347,7 +348,7 @@ def transform_mp4(
|
|
|
347
348
|
|
|
348
349
|
# extract video samples
|
|
349
350
|
source_samples = list(iterate_samples(moov_children))
|
|
350
|
-
sample_readers:
|
|
351
|
+
sample_readers: list[io.IOBase] = [
|
|
351
352
|
io_utils.SlicedIO(src_fp, sample.offset, sample.size)
|
|
352
353
|
for sample in source_samples
|
|
353
354
|
]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# pyre-ignore-all-errors[5, 16, 21, 24, 58]
|
|
2
|
+
from __future__ import annotations
|
|
2
3
|
|
|
3
4
|
import io
|
|
4
5
|
import typing as T
|
|
@@ -130,8 +131,8 @@ def parse_boxes_recursive(
|
|
|
130
131
|
stream: T.BinaryIO,
|
|
131
132
|
maxsize: int = -1,
|
|
132
133
|
depth: int = 0,
|
|
133
|
-
box_list_types:
|
|
134
|
-
) -> T.Generator[
|
|
134
|
+
box_list_types: set[bytes] | None = None,
|
|
135
|
+
) -> T.Generator[tuple[Header, int, T.BinaryIO], None, None]:
|
|
135
136
|
assert maxsize == -1 or 0 <= maxsize
|
|
136
137
|
|
|
137
138
|
if box_list_types is None:
|
|
@@ -152,10 +153,10 @@ def parse_boxes_recursive(
|
|
|
152
153
|
|
|
153
154
|
def parse_path(
|
|
154
155
|
stream: T.BinaryIO,
|
|
155
|
-
path: T.Sequence[
|
|
156
|
+
path: T.Sequence[bytes | T.Sequence[bytes]],
|
|
156
157
|
maxsize: int = -1,
|
|
157
158
|
depth: int = 0,
|
|
158
|
-
) -> T.Generator[
|
|
159
|
+
) -> T.Generator[tuple[Header, T.BinaryIO], None, None]:
|
|
159
160
|
if not path:
|
|
160
161
|
return
|
|
161
162
|
|
|
@@ -172,8 +173,8 @@ def parse_path(
|
|
|
172
173
|
|
|
173
174
|
|
|
174
175
|
def _parse_path_first(
|
|
175
|
-
stream: T.BinaryIO, path:
|
|
176
|
-
) ->
|
|
176
|
+
stream: T.BinaryIO, path: list[bytes], maxsize: int = -1, depth: int = 0
|
|
177
|
+
) -> tuple[Header, T.BinaryIO] | None:
|
|
177
178
|
if not path:
|
|
178
179
|
return None
|
|
179
180
|
for h, s in parse_boxes(stream, maxsize=maxsize, extend_eof=depth == 0):
|
|
@@ -187,19 +188,9 @@ def _parse_path_first(
|
|
|
187
188
|
return None
|
|
188
189
|
|
|
189
190
|
|
|
190
|
-
def parse_box_path_firstx(
|
|
191
|
-
stream: T.BinaryIO, path: T.List[bytes], maxsize: int = -1
|
|
192
|
-
) -> T.Tuple[Header, T.BinaryIO]:
|
|
193
|
-
# depth=1 will disable EoF extension
|
|
194
|
-
parsed = _parse_path_first(stream, path, maxsize=maxsize, depth=1)
|
|
195
|
-
if parsed is None:
|
|
196
|
-
raise BoxNotFoundError(f"unable find box at path {path}")
|
|
197
|
-
return parsed
|
|
198
|
-
|
|
199
|
-
|
|
200
191
|
def parse_mp4_data_first(
|
|
201
|
-
stream: T.BinaryIO, path:
|
|
202
|
-
) ->
|
|
192
|
+
stream: T.BinaryIO, path: list[bytes], maxsize: int = -1
|
|
193
|
+
) -> bytes | None:
|
|
203
194
|
# depth=0 will enable EoF extension
|
|
204
195
|
parsed = _parse_path_first(stream, path, maxsize=maxsize, depth=0)
|
|
205
196
|
if parsed is None:
|
|
@@ -209,7 +200,7 @@ def parse_mp4_data_first(
|
|
|
209
200
|
|
|
210
201
|
|
|
211
202
|
def parse_mp4_data_firstx(
|
|
212
|
-
stream: T.BinaryIO, path:
|
|
203
|
+
stream: T.BinaryIO, path: list[bytes], maxsize: int = -1
|
|
213
204
|
) -> bytes:
|
|
214
205
|
data = parse_mp4_data_first(stream, path, maxsize=maxsize)
|
|
215
206
|
if data is None:
|
|
@@ -218,8 +209,8 @@ def parse_mp4_data_firstx(
|
|
|
218
209
|
|
|
219
210
|
|
|
220
211
|
def parse_box_data_first(
|
|
221
|
-
stream: T.BinaryIO, path:
|
|
222
|
-
) ->
|
|
212
|
+
stream: T.BinaryIO, path: list[bytes], maxsize: int = -1
|
|
213
|
+
) -> bytes | None:
|
|
223
214
|
# depth=1 will disable EoF extension
|
|
224
215
|
parsed = _parse_path_first(stream, path, maxsize=maxsize, depth=1)
|
|
225
216
|
if parsed is None:
|
|
@@ -229,7 +220,7 @@ def parse_box_data_first(
|
|
|
229
220
|
|
|
230
221
|
|
|
231
222
|
def parse_box_data_firstx(
|
|
232
|
-
stream: T.BinaryIO, path:
|
|
223
|
+
stream: T.BinaryIO, path: list[bytes], maxsize: int = -1
|
|
233
224
|
) -> bytes:
|
|
234
225
|
data = parse_box_data_first(stream, path, maxsize=maxsize)
|
|
235
226
|
if data is None:
|