Example #1
0
    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)
Example #2
0
    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)
Example #3
0
    def find_stream(cls, fileobj, max_bytes):
        """Returns a possibly valid _ADTSStream or None.

        Args:
            max_bytes (int): maximum bytes to read
        """

        r = BitReader(fileobj)
        stream = cls(r)
        if stream.sync(max_bytes):
            stream.offset = (r.get_position() - 12) // 8
            return stream
Example #4
0
    def find_stream(cls, fileobj, max_bytes):
        """Returns a possibly valid _ADTSStream or None.

        Args:
            max_bytes (int): maximum bytes to read
        """

        r = BitReader(fileobj)
        stream = cls(r)
        if stream.sync(max_bytes):
            stream.offset = (r.get_position() - 12) // 8
            return stream
Example #5
0
    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
Example #6
0
    def __init__(self, fileobj, length):
        """Raises DescriptorError"""

        r = BitReader(fileobj)
        try:
            self._parse(r, length)
        except BitReaderError as e:
            raise DescriptorError(e)
Example #7
0
    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
Example #8
0
    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
Example #9
0
    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
Example #10
0
    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()
Example #11
0
    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)
Example #12
0
    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)
Example #13
0
    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()
Example #14
0
    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)
Example #15
0
    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)
Example #16
0
    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
Example #17
0
    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