From 3430b0ec987199cdb2d4218f2379aa4bcbb7f9fb Mon Sep 17 00:00:00 2001 From: Philip de Nier Date: Thu, 25 Jul 2024 16:39:53 +0100 Subject: [PATCH 1/3] docs: highlight support for concatenated GSF files --- gsf_docs/gsf.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gsf_docs/gsf.md b/gsf_docs/gsf.md index 846bd21..c165c99 100644 --- a/gsf_docs/gsf.md +++ b/gsf_docs/gsf.md @@ -46,6 +46,13 @@ As such the overall structure of the file is (count shown in brackets): * [grai](#grai-block) (0..1): terminator block +## Concatenated Files + +A reader may support concatenated GSF files by handling the occurence of the [SSB header](#general-file-structure) when a [grai](#grai-block) block is expected or after a terminator [grai](#grai-block) block. + +A basic reader implementation could detect the SSBB file signature and skip the [file header](#ssb.md#general-file-structure) and the following [head](#head-block) block. A reader could also read the [head](#head-block) block, replace existing metadata and do some checks to ensure the data is consistent given knowledge of what it acceptable, e.g. if grains are from the same flow. The mediagrains implementation reads the [head](#head-block) block, replacing what is stored in the decoder object. + + ## "head" Block The unique "head" block consists of a standard block header From 7e6b3b06bfd9263b107d7b3d58ebd4bf201613c0 Mon Sep 17 00:00:00 2001 From: Philip de Nier Date: Thu, 25 Jul 2024 15:46:55 +0100 Subject: [PATCH 2/3] Add support for reading concatenated GSF files sem-ver: feature --- mediagrains/gsf.py | 209 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 158 insertions(+), 51 deletions(-) diff --git a/mediagrains/gsf.py b/mediagrains/gsf.py index 39c2622..7aff1fc 100644 --- a/mediagrains/gsf.py +++ b/mediagrains/gsf.py @@ -280,17 +280,20 @@ async def __aenter__(self) -> "AsyncGSFBlock": assert self.file_data.tell() == self.block_start, "Can't enter context manager after the block start" while True: - tag_bytes = await self.file_data.read(4) - - try: - self.tag = tag_bytes.decode(encoding="utf-8") - except UnicodeDecodeError: - raise GSFDecodeError( - "Bytes {!r} at location {} do not make a valid tag for a block".format(tag_bytes, self.block_start), - self.block_start - ) - - self.size = await self.read_uint(4) + self.tag = await self.read_tag() + + if self.tag == "SSBB": + # A concatenated file header + grsg_tag = await self.read_tag() + if grsg_tag != "grsg": + raise GSFDecodeError( + f"Expected grsg tag after SSBB but got {grsg_tag} at {self.block_start}", + self.block_start + ) + # Include just the grsg tag in this pseudo block + self.size = 8 + else: + self.size = await self.read_uint(4) if self.want_tag is None or self.tag == self.want_tag: return self @@ -298,13 +301,26 @@ async def __aenter__(self) -> "AsyncGSFBlock": raise GSFDecodeError("Wanted tag {} but got {} at {}".format(self.want_tag, self.tag, self.block_start), self.block_start) else: - self.file_data.seek(self.block_start + self.size, SEEK_SET) + # If size is < 8 bytes then it is a special value, e.g. a terminator grai. + # If the size is special value then the actual size is 8 + actual_size = max(8, self.size) + + self.file_data.seek(self.block_start + actual_size, SEEK_SET) self.block_start = self.file_data.tell() + self.size = None + self.tag = "" + async def __aexit__(self, *args): """When used as a context manager, exiting context should seek to the block end""" try: - self.file_data.seek(self.block_start + self.size, SEEK_SET) + if self.size is not None: + # If size is < 8 bytes then it is a special value, e.g. a terminator grai. + # If the size is special value then the actual size is 8 + actual_size = max(8, self.size) + else: + actual_size = 0 + self.file_data.seek(self.block_start + actual_size, SEEK_SET) except Exception: pass @@ -377,6 +393,14 @@ async def read_remaining_block(self) -> "SyncGSFBlock": return block + async def read_tag(self) -> str: + """Read a 4 character tag + + :returns: Tag string + :raises EOFError: If there are fewer than 4 bytes left in the source + """ + return await self.read_string(4) + async def read_uint(self, length) -> int: """Read an unsigned integer of length `length` @@ -405,7 +429,16 @@ async def read_string(self, length: int) -> str: if (len(string_data) != length): raise EOFError("Unable to read enough bytes from source") - return string_data.decode(encoding='utf-8') + try: + string = string_data.decode(encoding='utf-8').rstrip('\x00') + if not string or string[0] == '\x00': + return "" + return string + except UnicodeDecodeError: + raise GSFDecodeError( + f"Failed to decode bytes in block starting at {self.block_start} to a valid string", + self.block_start + ) class SyncGSFBlock(): @@ -464,17 +497,20 @@ def __enter__(self) -> "SyncGSFBlock": # NOTE: Ensure that changes to the state set here is also changed in read_remaining_block # in SyncGSFBlock and AsyncGSFBlock while True: - tag_bytes = self.file_data.read(4) - - try: - self.tag = tag_bytes.decode(encoding="utf-8") - except UnicodeDecodeError: - raise GSFDecodeError( - "Bytes {!r} at location {} do not make a valid tag for a block".format(tag_bytes, self.block_start), - self.block_start - ) - - self.size = self.read_uint(4) + self.tag = self.read_tag() + + if self.tag == "SSBB": + # A concatenated file header + grsg_tag = self.read_tag() + if grsg_tag != "grsg": + raise GSFDecodeError( + f"Expected grsg tag after SSBB but got {grsg_tag} at {self.block_start}", + self.block_start + ) + # Include just the grsg tag in this pseudo block + self.size = 8 + else: + self.size = self.read_uint(4) if self.want_tag is None or self.tag == self.want_tag: return self @@ -482,13 +518,26 @@ def __enter__(self) -> "SyncGSFBlock": raise GSFDecodeError("Wanted tag {} but got {} at {}".format(self.want_tag, self.tag, self.block_start), self.block_start) else: - self.file_data.seek(self.block_start + self.size - self.file_data_start, SEEK_SET) + # If size is < 8 bytes then it is a special value, e.g. a terminator grai. + # If the size is special value then the actual size is 8 + actual_size = max(8, self.size) + + self.file_data.seek(self.block_start + actual_size - self.file_data_start, SEEK_SET) self.block_start = self._base_file_tell() + self.size = None + self.tag = "" + def __exit__(self, *args): """When used as a context manager, exiting context should seek to the block end""" try: - self.file_data.seek(self.block_start + self.size - self.file_data_start, SEEK_SET) + if self.size is not None: + # If size is < 8 bytes then it is a special value, e.g. a terminator grai. + # If the size is special value then the actual size is 8 + actual_size = max(8, self.size) + else: + actual_size = 0 + self.file_data.seek(self.block_start + actual_size - self.file_data_start, SEEK_SET) except Exception: pass @@ -561,6 +610,14 @@ def read_remaining_block(self) -> "SyncGSFBlock": return block + def read_tag(self) -> str: + """Read a 4 character tag + + :returns: Tag string + :raises EOFError: If there are fewer than 4 bytes left in the source + """ + return self.read_string(4) + def read_uint(self, length) -> int: """Read an unsigned integer of length `length` @@ -635,10 +692,16 @@ def read_string(self, length: int) -> str: if (len(string_data) != length): raise EOFError("Unable to read enough bytes from source") - string = string_data.decode(encoding='utf-8').rstrip('\x00') - if not string or string[0] == '\x00': - return "" - return string + try: + string = string_data.decode(encoding='utf-8').rstrip('\x00') + if not string or string[0] == '\x00': + return "" + return string + except UnicodeDecodeError: + raise GSFDecodeError( + f"Failed to decode bytes in block starting at {self.block_start} to a valid string", + self.block_start + ) def read_varstring(self) -> str: """Read a variable length string @@ -971,7 +1034,8 @@ class GSFAsyncDecoderSession(BaseGSFDecoderSession): def __init__(self, parse_grain: ParseGrainType, file_data: OpenAsyncBinaryIO, - sync_compatibility_mode: bool): + sync_compatibility_mode: bool, + support_concatenation: bool = True): super().__init__() self.file_data = file_data @@ -986,8 +1050,9 @@ def __init__(self, self._next_lazy_grain_number = 0 self._sync_compatibility_mode = sync_compatibility_mode + self._support_concatenation = support_concatenation - async def _decode_ssb_header(self): + async def _decode_ssb_header(self, head_tag=""): """Find and read the SSB header in the GSF file :returns: (major, minor) version tuple @@ -995,24 +1060,25 @@ async def _decode_ssb_header(self): """ ssb_block = AsyncGSFBlock(self.file_data) - tag = await ssb_block.read_string(8) + if not head_tag: + head_tag = await ssb_block.read_string(8) - if tag != "SSBBgrsg": - raise GSFDecodeBadFileTypeError("File lacks correct header", ssb_block.block_start, tag) + if head_tag != "SSBBgrsg": + raise GSFDecodeBadFileTypeError("File lacks correct header", ssb_block.block_start, head_tag) major = await ssb_block.read_uint(2) minor = await ssb_block.read_uint(2) return (major, minor) - async def _decode_file_headers(self) -> None: + async def _decode_file_headers(self, head_tag="") -> None: """Verify the file is a supported version, get the file header and store it in the file_headers property :raises GSFDecodeBadVersionError: If the file version is not supported :raises GSFDecodeBadFileTypeError: If this isn't a GSF file :raises GSFDecodeError: If the file doesn't have a "head" block """ - (self.major, self.minor) = await self._decode_ssb_header() + (self.major, self.minor) = await self._decode_ssb_header(head_tag=head_tag) if self.major not in [7, 8, 9]: raise GSFDecodeBadVersionError(f"Unknown Version {self.major}.{self.minor}", 0, self.major, self.minor) @@ -1072,11 +1138,28 @@ async def _read_out_of_order(parent: GSFAsyncDecoderSession, else: return None + have_concatenation = False + while True: try: - async with AsyncGSFBlock(self.file_data, want_tag="grai") as grai_block: + if have_concatenation: + await self._decode_file_headers(head_tag="SSBBgrsg") + have_concatenation = False + + async with AsyncGSFBlock(self.file_data) as block: + if block.tag != "grai": + if block.tag == "SSBB": + if not self._support_concatenation: + break + have_concatenation = True + continue + + grai_block = block if grai_block.size == 0: - return # Terminator block reached + # Terminator block reached + if self._support_concatenation: + continue + break local_id = await grai_block.read_uint(2) @@ -1135,16 +1218,19 @@ async def _read_out_of_order(parent: GSFAsyncDecoderSession, class GSFSyncDecoderSession(BaseGSFDecoderSession): def __init__(self, parse_grain: ParseGrainType, - file_data: IO[bytes]): + file_data: IO[bytes], + support_concatenation: bool = True): super().__init__() self.file_data = file_data self.Grain = parse_grain self.file_headers: Optional[GSFFileHeaderDict] = None + self._support_concatenation = support_concatenation + self._exiting = False - def _decode_ssb_header(self): + def _decode_ssb_header(self, head_tag=""): """Find and read the SSB header in the GSF file :returns: (major, minor) version tuple @@ -1152,24 +1238,25 @@ def _decode_ssb_header(self): """ ssb_block = SyncGSFBlock(self.file_data) - tag = ssb_block.read_string(8) + if not head_tag: + head_tag = ssb_block.read_string(8) - if tag != "SSBBgrsg": - raise GSFDecodeBadFileTypeError("File lacks correct header", ssb_block.block_start, tag) + if head_tag != "SSBBgrsg": + raise GSFDecodeBadFileTypeError("File lacks correct header", ssb_block.block_start, head_tag) major = ssb_block.read_uint(2) minor = ssb_block.read_uint(2) return (major, minor) - def _decode_file_headers(self) -> None: + def _decode_file_headers(self, head_tag="") -> None: """Verify the file is a supported version, get the file header and store it in the file_headers property :raises GSFDecodeBadVersionError: If the file version is not supported :raises GSFDecodeBadFileTypeError: If this isn't a GSF file :raises GSFDecodeError: If the file doesn't have a "head" block """ - (self.major, self.minor) = self._decode_ssb_header() + (self.major, self.minor) = self._decode_ssb_header(head_tag=head_tag) if self.major not in [7, 8, 9]: raise GSFDecodeBadVersionError(f"Unknown Version {self.major}.{self.minor}", 0, self.major, self.minor) @@ -1197,11 +1284,28 @@ def grains(self, :yields: (Grain, local_id) tuple for each grain :raises GSFDecodeError: If grain is invalid (e.g. no "gbhd" child) """ + have_concatenation = False + while True: try: - with SyncGSFBlock(self.file_data, want_tag="grai") as grai_block: + if have_concatenation: + self._decode_file_headers(head_tag="SSBBgrsg") + have_concatenation = False + + with SyncGSFBlock(self.file_data) as block: + if block.tag != "grai": + if block.tag == "SSBB": + if not self._support_concatenation: + break + have_concatenation = True + continue + + grai_block = block if grai_block.size == 0: - return # Terminator block reached + # Terminator block reached + if self._support_concatenation: + continue + break local_id = grai_block.read_uint(2) @@ -1289,13 +1393,15 @@ def __init__(self, self._open_asession: Optional[GSFAsyncDecoderSession] = None self._sync_compatibility_mode: bool = False + self._support_concatenation = kwargs.get("support_concatenation", True) def __enter__(self) -> GSFSyncDecoderSession: if self._file_data is None: raise TypeError("file_data must be a synchronous binary file to use this class as a sync context manager") self._open_session = GSFSyncDecoderSession(file_data=cast(IO[bytes], self._file_data), - parse_grain=self.Grain) + parse_grain=self.Grain, + support_concatenation=self._support_concatenation) self._open_session._decode_file_headers() return self._open_session @@ -1313,7 +1419,8 @@ async def __aenter__(self) -> GSFAsyncDecoderSession: self._open_asession = GSFAsyncDecoderSession(file_data=self._open_afile, parse_grain=self.Grain, - sync_compatibility_mode=self._sync_compatibility_mode) + sync_compatibility_mode=self._sync_compatibility_mode, + support_concatenation=self._support_concatenation) await self._open_asession._decode_file_headers() return self._open_asession From 0c78bdbcf01a010645d4c9a6da08d398e5469cce Mon Sep 17 00:00:00 2001 From: Philip de Nier Date: Thu, 25 Jul 2024 16:11:49 +0100 Subject: [PATCH 3/3] Add a concatenated file test --- examples/concat_coded_video_9.gsf | Bin 0 -> 68402 bytes tests/test_gsf.py | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 examples/concat_coded_video_9.gsf diff --git a/examples/concat_coded_video_9.gsf b/examples/concat_coded_video_9.gsf new file mode 100644 index 0000000000000000000000000000000000000000..7761e7d1a99da8feb6bcb0a728506caf609d9f3f GIT binary patch literal 68402 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 z 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 literal 0 HcmV?d00001 diff --git a/tests/test_gsf.py b/tests/test_gsf.py index 4c7abc3..507ece1 100644 --- a/tests/test_gsf.py +++ b/tests/test_gsf.py @@ -80,6 +80,9 @@ with open('examples/interleaved_7.gsf', 'rb') as f: INTERLEAVED_DATA_7 = f.read() +with open('examples/concat_coded_video_9.gsf', 'rb') as f: + CONCAT_CODED_VIDEO_DATA_9 = f.read() + class TestGSFDumps(IsolatedAsyncioTestCase): def test_dumps_no_grains(self): @@ -2126,6 +2129,24 @@ def test_lazy_load_grain_data__deprecated(self): self.assertEqual(bytes_read, grain_data_size) self.assertEqual(grain.length, grain_data_size) + def test_load_concatenated_gsf_grains(self): + """Test that the generator yields each grain from a concatenated file""" + video_data_stream = BytesIO(CONCAT_CODED_VIDEO_DATA_9) + + start_ts = Timestamp.from_str("1420102800:0") + grain_count = 0 + + with GSFDecoder(file_data=video_data_stream) as dec: + for (grain, local_id) in dec.grains(): + self.assertIsInstance(grain, CodedVideoGrain) + self.assertEqual(grain.source_id, UUID('49578552-fb9e-4d3e-a197-3e3c437a895d')) + self.assertEqual(grain.flow_id, UUID('b6b05efb-6067-4ff8-afac-ec735a85674e')) + self.assertEqual(grain.origin_timestamp, start_ts + Timestamp.from_count(grain_count, grain.rate)) + + grain_count += 1 + + self.assertEqual(10, grain_count) # There are 5 grains in each of the concatenated files + class TestGSFLoads(IsolatedAsyncioTestCase): def _verify_loaded_video(self, head, segments):