def test_is_aligned(self): r = BitReader(BytesIO(b"\xAB\xCD\xEF")) self.assertTrue(r.is_aligned()) r.skip(1) self.assertFalse(r.is_aligned()) r.skip(7) self.assertTrue(r.is_aligned()) r.bits(7) self.assertFalse(r.is_aligned()) r.bits(1) self.assertTrue(r.is_aligned())
def test_is_aligned(self): r = BitReader(cBytesIO(b"\xAB\xCD\xEF")) self.assertTrue(r.is_aligned()) r.skip(1) self.assertFalse(r.is_aligned()) r.skip(7) self.assertTrue(r.is_aligned()) r.bits(7) self.assertFalse(r.is_aligned()) r.bits(1) self.assertTrue(r.is_aligned())
def __init__(self, fileobj, length): """Raises DescriptorError""" r = BitReader(fileobj) try: self.ES_ID = r.bits(16) self.streamDependenceFlag = r.bits(1) self.URL_Flag = r.bits(1) self.OCRstreamFlag = r.bits(1) self.streamPriority = r.bits(5) if self.streamDependenceFlag: self.dependsOn_ES_ID = r.bits(16) if self.URL_Flag: URLlength = r.bits(8) self.URLstring = r.bytes(URLlength) if self.OCRstreamFlag: self.OCR_ES_Id = r.bits(16) tag = r.bits(8) except BitReaderError as e: raise DescriptorError(e) if tag != DecoderConfigDescriptor.TAG: raise DescriptorError("unexpected DecoderConfigDescrTag %d" % tag) assert r.is_aligned() self.decConfigDescr = DecoderConfigDescriptor.parse(fileobj)
def __init__(self, fileobj, length): """Raises DescriptorError""" r = BitReader(fileobj) try: self.objectTypeIndication = r.bits(8) self.streamType = r.bits(6) self.upStream = r.bits(1) self.reserved = r.bits(1) self.bufferSizeDB = r.bits(24) self.maxBitrate = r.bits(32) self.avgBitrate = r.bits(32) if (self.objectTypeIndication, self.streamType) != (0x40, 0x5): return # all from here is optional if length * 8 == r.get_position(): return tag = r.bits(8) except BitReaderError as e: raise DescriptorError(e) if tag == DecoderSpecificInfo.TAG: assert r.is_aligned() self.decSpecificInfo = DecoderSpecificInfo.parse(fileobj)
def _parse_esds(self, esds, fileobj): assert esds.name == b"esds" ok, data = esds.read(fileobj) if not ok: raise ASEntryError("truncated %s atom" % esds.name) try: version, flags, data = parse_full_atom(data) except ValueError as e: raise ASEntryError(e) if version != 0: raise ASEntryError("Unsupported version %d" % version) fileobj = cBytesIO(data) r = BitReader(fileobj) try: tag = r.bits(8) if tag != ES_Descriptor.TAG: raise ASEntryError("unexpected descriptor: %d" % tag) assert r.is_aligned() except BitReaderError as e: raise ASEntryError(e) try: decSpecificInfo = ES_Descriptor.parse(fileobj) except DescriptorError as e: raise ASEntryError(e) dec_conf_desc = decSpecificInfo.decConfigDescr self.bitrate = dec_conf_desc.avgBitrate self.codec += dec_conf_desc.codec_param self.codec_description = dec_conf_desc.codec_desc decSpecificInfo = dec_conf_desc.decSpecificInfo if decSpecificInfo is not None: if decSpecificInfo.channels != 0: self.channels = decSpecificInfo.channels if decSpecificInfo.sample_rate != 0: self.sample_rate = decSpecificInfo.sample_rate
def __init__(self, atom, fileobj): ok, data = atom.read(fileobj) if not ok: raise ASEntryError("too short %r atom" % atom.name) fileobj = cBytesIO(data) r = BitReader(fileobj) try: # SampleEntry r.skip(6 * 8) # reserved r.skip(2 * 8) # data_ref_index # AudioSampleEntry r.skip(8 * 8) # reserved self.channels = r.bits(16) self.sample_size = r.bits(16) r.skip(2 * 8) # pre_defined r.skip(2 * 8) # reserved self.sample_rate = r.bits(32) >> 16 except BitReaderError as e: raise ASEntryError(e) assert r.is_aligned() try: extra = Atom(fileobj) except AtomError as e: raise ASEntryError(e) self.codec = atom.name.decode("latin-1") self.codec_description = None if atom.name == b"mp4a" and extra.name == b"esds": self._parse_esds(extra, fileobj) elif atom.name == b"alac" and extra.name == b"alac": self._parse_alac(extra, fileobj) elif atom.name == b"ac-3" and extra.name == b"dac3": self._parse_dac3(extra, fileobj) if self.codec_description is None: self.codec_description = self.codec.upper()
def __init__(self, xing, fileobj): """Raises LAMEError if parsing fails""" payload = fileobj.read(27) if len(payload) != 27: raise LAMEError("Not enough data") # extended lame header r = BitReader(cBytesIO(payload)) revision = r.bits(4) if revision != 0: raise LAMEError("unsupported header revision %d" % revision) self.vbr_method = r.bits(4) self.lowpass_filter = r.bits(8) * 100 # these have a different meaning for lame; expose them again here self.quality = (100 - xing.vbr_scale) % 10 self.vbr_quality = (100 - xing.vbr_scale) // 10 track_peak_data = r.bytes(4) if track_peak_data == b"\x00\x00\x00\x00": self.track_peak = None else: # see PutLameVBR() in LAME's VbrTag.c self.track_peak = ( cdata.uint32_be(track_peak_data) - 0.5) / 2 ** 23 track_gain_type = r.bits(3) self.track_gain_origin = r.bits(3) sign = r.bits(1) gain_adj = r.bits(9) / 10.0 if sign: gain_adj *= -1 if track_gain_type == 1: self.track_gain_adjustment = gain_adj else: self.track_gain_adjustment = None assert r.is_aligned() album_gain_type = r.bits(3) self.album_gain_origin = r.bits(3) sign = r.bits(1) album_gain_adj = r.bits(9) / 10.0 if album_gain_type == 2: self.album_gain_adjustment = album_gain_adj else: self.album_gain_adjustment = None self.encoding_flags = r.bits(4) self.ath_type = r.bits(4) self.bitrate = r.bits(8) self.encoder_delay_start = r.bits(12) self.encoder_padding_end = r.bits(12) self.source_sample_frequency_enum = r.bits(2) self.unwise_setting_used = r.bits(1) self.stereo_mode = r.bits(3) self.noise_shaping = r.bits(2) sign = r.bits(1) mp3_gain = r.bits(7) if sign: mp3_gain *= -1 self.mp3_gain = mp3_gain r.skip(2) self.surround_info = r.bits(3) self.preset_used = r.bits(11) self.music_length = r.bits(32) self.music_crc = r.bits(16) self.header_crc = r.bits(16) assert r.is_aligned()
def __init__(self, fileobj): """Raises HeaderNotFoundError""" self.frame_offset = fileobj.tell() r = BitReader(fileobj) try: if r.bits(11) != 0x7ff: raise HeaderNotFoundError("invalid sync") version = r.bits(2) layer = r.bits(2) protection = r.bits(1) bitrate = r.bits(4) sample_rate = r.bits(2) padding = r.bits(1) r.skip(1) # private self.mode = r.bits(2) r.skip(6) except BitReaderError: raise HeaderNotFoundError("truncated header") assert r.get_position() == 32 and r.is_aligned() # try to be strict here to redice the chance of a false positive if version == 1 or layer == 0 or sample_rate == 0x3 or \ bitrate == 0xf or bitrate == 0: raise HeaderNotFoundError("invalid header") self.channels = 1 if self.mode == MONO else 2 self.version = [2.5, None, 2, 1][version] self.layer = 4 - layer self.protected = not protection self.padding = bool(padding) self.bitrate = self.__BITRATE[(self.version, self.layer)][bitrate] self.bitrate *= 1000 self.sample_rate = self.__RATES[self.version][sample_rate] if self.layer == 1: frame_size = 384 slot = 4 elif self.version >= 2 and self.layer == 3: frame_size = 576 slot = 1 else: frame_size = 1152 slot = 1 frame_length = ( ((frame_size // 8 * self.bitrate) // self.sample_rate) + padding) * slot self.sketchy = True # Try to find/parse the Xing header, which trumps the above length # and bitrate calculation. if self.layer == 3: self._parse_vbr_header(fileobj, self.frame_offset, frame_size, frame_length) fileobj.seek(self.frame_offset + frame_length, 0)