def find_media_segments(self, reader: ByteReader) -> List[MediaSegment]: try: ebml_id, size = read_element_header(reader) assert ebml_id == 0x1A45DFA3 reader.skip(size) segment_id, _ = read_element_header(reader) assert segment_id == 0x18538067 segment_reader = RegionByteReader(reader, reader.position, size=None) segment_info = next(element for element in iter_elements(segment_reader) if element.element_id == 0x1549A966) timestamp_scale = next( (element for element in iter_elements(segment_info.reader) if element.element_id == 0x2AD7B1), None) timestamp_scale_value = read_uint( timestamp_scale.reader ) if timestamp_scale is not None else 1000000 clusters = [ Cluster(element, timestamp_scale_value) for element in iter_elements(segment_reader) if element.element_id == 0x1F43B675 ] return [ MediaSegment(offset=cluster.element.offset, size=cluster.element.full_size, time=cluster.timestamp) for cluster in clusters ] finally: reader.close()
def find_media_segments(self, reader: ByteReader) -> List[MediaSegment]: try: moov = MovieBox( next(box for box in iter_boxes(reader) if box.kind == b"moov")) moofs = [ MovieFragmentBox(box) for box in iter_boxes(reader) if box.kind == b"moof" ] def fragment_size(fragment_index): if fragment_index < len(moofs) - 1: return moofs[ fragment_index + 1].box.offset - moofs[fragment_index].box.offset else: movie_size = reader.size return movie_size - moofs[fragment_index].box.offset return [ MediaSegment(moof.box.offset, fragment_size(i), self._moof_start_time(moov, moof)) for i, moof in enumerate(moofs) ] finally: reader.close()
def read_vint(reader: ByteReader, raw: bool = False): header_byte = ord(reader.read(1)) if header_byte == 0: raise WrongFile("VINT with zero header byte") tail_length = 0 mask = 0x80 while header_byte & mask == 0: tail_length += 1 mask >>= 1 header_number_part = header_byte & ~mask if not raw else header_byte return parse_big_endian_number( bytes([header_number_part]) + reader.read(tail_length))
def __init__(self, reader: ByteReader): self.offset = reader.position size = parse_big_endian_number(reader.read(4)) kind = reader.read(4) if size == 1: size = parse_big_endian_number(reader.read(8)) elif size == 0: size = reader.end - reader.position if kind == b"uuid": kind += reader.read(16) content_offset = reader.position content_size = size - (content_offset - self.offset) self.kind = kind self.full_size = size self.reader = RegionByteReader(reader, content_offset, content_size) reader.skip(content_size)
def read_uint(reader: ByteReader, default: int = 0) -> int: if reader.ended: return default return parse_big_endian_number(reader.read())
def iter_elements(reader: ByteReader): while not reader.ended: element = read_element(reader) yield element reader.skip(element.reader.size)
def iter_boxes(reader: ByteReader, rewind: bool = False): if rewind: reader.position = reader.start while not reader.ended: yield Box(reader)