def _parse_adif(self, fileobj): r = BitReader(fileobj) try: copyright_id_present = r.bits(1) if copyright_id_present: r.skip(72) # copyright_id r.skip(1 + 1) # original_copy, home bitstream_type = r.bits(1) self.bitrate = r.bits(23) npce = r.bits(4) if bitstream_type == 0: r.skip(20) # adif_buffer_fullness pce = ProgramConfigElement(r) try: self.sample_rate = _FREQS[pce.sampling_frequency_index] except IndexError: pass self.channels = pce.channels # other pces.. for i in xrange(npce): ProgramConfigElement(r) r.align() except BitReaderError as e: raise AACError(e) # use bitrate + data size to guess length start = fileobj.tell() fileobj.seek(0, 2) length = fileobj.tell() - start if self.bitrate != 0: self.length = (8.0 * length) / self.bitrate
def _parse_adts(self, fileobj, start_offset): max_initial_read = 512 max_resync_read = 10 max_sync_tries = 10 frames_max = 100 frames_needed = 3 # Try up to X times to find a sync word and read up to Y frames. # If more than Z frames are valid we assume a valid stream offset = start_offset for i in xrange(max_sync_tries): fileobj.seek(offset) s = _ADTSStream.find_stream(fileobj, max_initial_read) if s is None: raise AACError("sync not found") # start right after the last found offset offset += s.offset + 1 for i in xrange(frames_max): if not s.parse_frame(): break if not s.sync(max_resync_read): break if s.parsed_frames >= frames_needed: break else: raise AACError("no valid stream found (only %d frames)" % s.parsed_frames) self.sample_rate = s.frequency self.channels = s.channels self.bitrate = s.bitrate # size from stream start to end of file fileobj.seek(0, 2) stream_size = fileobj.tell() - (offset + s.offset) # approx self.length = float(s.samples * stream_size) / (s.size * s.frequency)
def _parse_adts(self, fileobj, start_offset): max_initial_read = 512 max_resync_read = 10 max_sync_tries = 10 frames_max = 100 frames_needed = 3 # Try up to X times to find a sync word and read up to Y frames. # If more than Z frames are valid we assume a valid stream offset = start_offset for i in xrange(max_sync_tries): fileobj.seek(offset) s = _ADTSStream.find_stream(fileobj, max_initial_read) if s is None: raise AACError("sync not found") # start right after the last found offset offset += s.offset + 1 for i in xrange(frames_max): if not s.parse_frame(): break if not s.sync(max_resync_read): break if s.parsed_frames >= frames_needed: break else: raise AACError( "no valid stream found (only %d frames)" % s.parsed_frames) self.sample_rate = s.frequency self.channels = s.channels self.bitrate = s.bitrate # size from stream start to end of file fileobj.seek(0, 2) stream_size = fileobj.tell() - (offset + s.offset) # approx self.length = float(s.samples * stream_size) / (s.size * s.frequency)
def _key_sort(item): (key, v) = item # iTunes always writes the tags in order of "relevance", try # to copy it as closely as possible. order = ["\xa9nam", "\xa9ART", "\xa9wrt", "\xa9alb", "\xa9gen", "gnre", "trkn", "disk", "\xa9day", "cpil", "pgap", "pcst", "tmpo", "\xa9too", "----", "covr", "\xa9lyr"] order = dict(izip(order, xrange(len(order)))) last = len(order) # If there's no key-based way to distinguish, order by length. # If there's still no way, go by string comparison on the # values, so we at least have something determinstic. return (order.get(key[:4], last), len(repr(v)), repr(v))
def parse_full(cls, asf, fileobj): """Raises ASFHeaderError""" header = cls() size, num_objects = cls.parse_size(fileobj) for i in xrange(num_objects): guid, size = struct.unpack("<16sQ", fileobj.read(24)) obj = BaseObject._get_object(guid) data = fileobj.read(size - 24) obj.parse(asf, data) header.objects.append(obj) return header
def _key_sort(item): (key, v) = item # iTunes always writes the tags in order of "relevance", try # to copy it as closely as possible. order = [ "\xa9nam", "\xa9ART", "\xa9wrt", "\xa9alb", "\xa9gen", "gnre", "trkn", "disk", "\xa9day", "cpil", "pgap", "pcst", "tmpo", "\xa9too", "----", "covr", "\xa9lyr" ] order = dict(izip(order, xrange(len(order)))) last = len(order) # If there's no key-based way to distinguish, order by length. # If there's still no way, go by string comparison on the # values, so we at least have something determinstic. return (order.get(key[:4], last), len(repr(v)), repr(v))
def parse(self, asf, data): super(ExtendedContentDescriptionObject, self).parse(asf, data) num_attributes, = struct.unpack("<H", data[0:2]) pos = 2 for i in xrange(num_attributes): name_length, = struct.unpack("<H", data[pos:pos + 2]) pos += 2 name = data[pos:pos + name_length] name = name.decode("utf-16-le").strip("\x00") pos += name_length value_type, value_length = struct.unpack("<HH", data[pos:pos + 4]) pos += 4 value = data[pos:pos + value_length] pos += value_length attr = ASFBaseAttribute._get_type(value_type)(data=value) asf._tags.setdefault(self.GUID, []).append((name, attr))
def _parse_desc_length_file(cls, fileobj): """May raise ValueError""" value = 0 for i in xrange(4): try: b = cdata.uint8(fileobj.read(1)) except cdata.error as e: raise ValueError(e) value = (value << 7) | (b & 0x7f) if not b >> 7: break else: raise ValueError("invalid descriptor length") return value
def parse(self, asf, data): super(MetadataLibraryObject, self).parse(asf, data) num_attributes, = struct.unpack("<H", data[0:2]) pos = 2 for i in xrange(num_attributes): (language, stream, name_length, value_type, value_length) = struct.unpack("<HHHHI", data[pos:pos + 12]) pos += 12 name = data[pos:pos + name_length] name = name.decode("utf-16-le").strip("\x00") pos += name_length value = data[pos:pos + value_length] pos += value_length args = {'data': value, 'language': language, 'stream': stream} if value_type == 2: args['dword'] = False attr = ASFBaseAttribute._get_type(value_type)(**args) asf._tags.setdefault(self.GUID, []).append((name, attr))
def __init__(self, r): """Reads the program_config_element() Raises BitReaderError """ self.element_instance_tag = r.bits(4) self.object_type = r.bits(2) self.sampling_frequency_index = r.bits(4) num_front_channel_elements = r.bits(4) num_side_channel_elements = r.bits(4) num_back_channel_elements = r.bits(4) num_lfe_channel_elements = r.bits(2) num_assoc_data_elements = r.bits(3) num_valid_cc_elements = r.bits(4) mono_mixdown_present = r.bits(1) if mono_mixdown_present == 1: r.skip(4) stereo_mixdown_present = r.bits(1) if stereo_mixdown_present == 1: r.skip(4) matrix_mixdown_idx_present = r.bits(1) if matrix_mixdown_idx_present == 1: r.skip(3) elms = num_front_channel_elements + num_side_channel_elements + \ num_back_channel_elements channels = 0 for i in xrange(elms): channels += 1 element_is_cpe = r.bits(1) if element_is_cpe: channels += 1 r.skip(4) channels += num_lfe_channel_elements self.channels = channels r.skip(4 * num_lfe_channel_elements) r.skip(4 * num_assoc_data_elements) r.skip(5 * num_valid_cc_elements) r.align() comment_field_bytes = r.bits(8) r.skip(8 * comment_field_bytes)
def parse(self, asf, data): super(CodecListObject, self).parse(asf, data) offset = 16 count, offset = cdata.uint32_le_from(data, offset) for i in xrange(count): try: offset, type_, name, desc, codec = \ self._parse_entry(data, offset) except cdata.error: raise ASFError("invalid codec entry") # go with the first audio entry if type_ == 2: name = name.strip() desc = desc.strip() asf.info.codec_type = codec asf.info.codec_name = name asf.info.codec_description = desc return