def _parse_dac3(self, atom, fileobj): # ETSI TS 102 366 assert atom.name == b"dac3" ok, data = atom.read(fileobj) if not ok: raise ASEntryError("truncated %s atom" % atom.name) fileobj = cBytesIO(data) r = BitReader(fileobj) # sample_rate in AudioSampleEntry covers values in # fscod2 and not just fscod, so ignore fscod here. try: r.skip(2 + 5 + 3) # fscod, bsid, bsmod acmod = r.bits(3) lfeon = r.bits(1) bit_rate_code = r.bits(5) r.skip(5) # reserved except BitReaderError as e: raise ASEntryError(e) self.channels = [2, 1, 2, 3, 3, 4, 4, 5][acmod] + lfeon try: self.bitrate = [ 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640 ][bit_rate_code] * 1000 except IndexError: pass
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_dac3(self, atom, fileobj): # ETSI TS 102 366 assert atom.name == b"dac3" ok, data = atom.read(fileobj) if not ok: raise ASEntryError("truncated %s atom" % atom.name) fileobj = cBytesIO(data) r = BitReader(fileobj) # sample_rate in AudioSampleEntry covers values in # fscod2 and not just fscod, so ignore fscod here. try: r.skip(2 + 5 + 3) # fscod, bsid, bsmod acmod = r.bits(3) lfeon = r.bits(1) bit_rate_code = r.bits(5) r.skip(5) # reserved except BitReaderError as e: raise ASEntryError(e) self.channels = [2, 1, 2, 3, 3, 4, 4, 5][acmod] + lfeon try: self.bitrate = [ 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640][bit_rate_code] * 1000 except IndexError: pass
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, 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, 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_alac(self, atom, fileobj): # https://alac.macosforge.org/trac/browser/trunk/ # ALACMagicCookieDescription.txt assert atom.name == b"alac" ok, data = atom.read(fileobj) if not ok: raise ASEntryError("truncated %s atom" % atom.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: # for some files the AudioSampleEntry values default to 44100/2chan # and the real info is in the alac cookie, so prefer it r.skip(32) # frameLength compatibleVersion = r.bits(8) if compatibleVersion != 0: return self.sample_size = r.bits(8) r.skip(8 + 8 + 8) self.channels = r.bits(8) r.skip(16 + 32) self.bitrate = r.bits(32) self.sample_rate = r.bits(32) except BitReaderError as e: raise ASEntryError(e)
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