コード例 #1
0
    def __init__(self, atoms, fileobj):
        hdlr = atoms["moov.trak.mdia.hdlr"]
        fileobj.seek(hdlr.offset)
        if b"soun" not in fileobj.read(hdlr.length):
            raise M4AStreamInfoError("track has no audio data")

        mdhd = atoms["moov.trak.mdia.mdhd"]
        fileobj.seek(mdhd.offset)
        data = bytearray(fileobj.read(mdhd.length))
        if data[8] == 0:
            offset = 20
            fmt = ">2I"
        else:
            offset = 28
            fmt = ">IQ"
        end = offset + struct_calcsize(fmt)
        unit, length = struct_unpack(fmt, data[offset:end])
        self.length = float(length) / unit

        try:
            atom = atoms["moov.trak.mdia.minf.stbl.stsd"]
            fileobj.seek(atom.offset)
            data = fileobj.read(atom.length)
            self.bitrate = cdata.uint_be(data[-17:-13])
        except (ValueError, KeyError):
            # Bitrate values are optional.
            pass
コード例 #2
0
ファイル: mp4.py プロジェクト: mattbun/sift
    def __init__(self, atoms, fileobj):
        for trak in list(atoms["moov"].findall(b"trak")):
            hdlr = trak["mdia", "hdlr"]
            fileobj.seek(hdlr.offset)
            data = fileobj.read(hdlr.length)
            if data[16:20] == b"soun":
                break
        else:
            raise MP4StreamInfoError("track has no audio data")

        mdhd = trak["mdia", "mdhd"]
        fileobj.seek(mdhd.offset)
        data = bytearray(fileobj.read(mdhd.length))
        if data[8] == 0:
            offset = 20
            fmt = ">2I"
        else:
            offset = 28
            fmt = ">IQ"
        end = offset + struct_calcsize(fmt)
        unit, length = struct_unpack(fmt, data[offset:end])
        self.length = float(length) / unit

        try:
            atom = trak["mdia", "minf", "stbl", "stsd"]
            fileobj.seek(atom.offset)
            data = bytearray(fileobj.read(atom.length))
            if data[20:24] == b"mp4a":
                length = cdata.uint_be(data[16:20])
                (self.channels, self.bits_per_sample, _,
                 self.sample_rate) = struct_unpack(">3HI", data[40:50])
                # ES descriptor type
                if data[56:60] == b"esds" and ord(data[64:65]) == 0x03:
                    pos = 65
                    # skip extended descriptor type tag, length, ES ID
                    # and stream priority
                    if data[pos:pos+3] == b"\x80\x80\x80":
                        pos += 3
                    pos += 4
                    # decoder config descriptor type
                    if data[pos] == 0x04:
                        pos += 1
                        # skip extended descriptor type tag, length,
                        # object type ID, stream type, buffer size
                        # and maximum bitrate
                        if data[pos:pos+3] == b"\x80\x80\x80":
                            pos += 3
                        pos += 10
                        # average bitrate
                        self.bitrate = cdata.uint_be(data[pos:pos+4])
        except (ValueError, KeyError):
            # stsd atoms are optional
            pass
コード例 #3
0
ファイル: flac.py プロジェクト: mattbun/sift
class SeekTable(MetadataBlock):
    """Read and write FLAC seek tables.

    Attributes:
    seekpoints -- list of SeekPoint objects
    """

    __SEEKPOINT_FORMAT = '>QQH'
    __SEEKPOINT_SIZE = struct_calcsize(__SEEKPOINT_FORMAT)

    code = 3

    def __init__(self, data):
        self.seekpoints = []
        super(SeekTable, self).__init__(data)

    def __eq__(self, other):
        try:
            return (self.seekpoints == other.seekpoints)
        except (AttributeError, TypeError):
            return False

    __hash__ = MetadataBlock.__hash__

    def load(self, data):
        self.seekpoints = []
        sp = data.read(self.__SEEKPOINT_SIZE)
        while len(sp) == self.__SEEKPOINT_SIZE:
            self.seekpoints.append(
                SeekPoint(*struct_unpack(self.__SEEKPOINT_FORMAT, sp)))
            sp = data.read(self.__SEEKPOINT_SIZE)

    def write(self):
        f = BytesIO()
        for seekpoint in self.seekpoints:
            packed = struct_pack(self.__SEEKPOINT_FORMAT,
                                 seekpoint.first_sample, seekpoint.byte_offset,
                                 seekpoint.num_samples)
            f.write(packed)
        return f.getvalue()

    def __repr__(self):
        return "<%s seekpoints=%r>" % (type(self).__name__, self.seekpoints)
コード例 #4
0
ファイル: flac.py プロジェクト: mattbun/sift
class CueSheet(MetadataBlock):
    """Read and write FLAC embedded cue sheets.

    Number of tracks should be from 1 to 100. There should always be
    exactly one lead-out track and that track must be the last track
    in the cue sheet.

    Attributes:
    media_catalog_number -- media catalog number in ASCII
    lead_in_samples -- number of lead-in samples
    compact_disc -- true if the cuesheet corresponds to a compact disc
    tracks -- list of CueSheetTrack objects
    lead_out -- lead-out as CueSheetTrack or None if lead-out was not found
    """

    __CUESHEET_FORMAT = '>128sQB258xB'
    __CUESHEET_SIZE = struct_calcsize(__CUESHEET_FORMAT)
    __CUESHEET_TRACK_FORMAT = '>QB12sB13xB'
    __CUESHEET_TRACK_SIZE = struct_calcsize(__CUESHEET_TRACK_FORMAT)
    __CUESHEET_TRACKINDEX_FORMAT = '>QB3x'
    __CUESHEET_TRACKINDEX_SIZE = struct_calcsize(__CUESHEET_TRACKINDEX_FORMAT)

    code = 5

    media_catalog_number = b''
    lead_in_samples = 88200
    compact_disc = True

    def __init__(self, data):
        self.tracks = []
        super(CueSheet, self).__init__(data)

    def __eq__(self, other):
        try:
            return (self.media_catalog_number == other.media_catalog_number
                    and self.lead_in_samples == other.lead_in_samples
                    and self.compact_disc == other.compact_disc
                    and self.tracks == other.tracks)
        except (AttributeError, TypeError):
            return False

    __hash__ = MetadataBlock.__hash__

    def load(self, data):
        header = data.read(self.__CUESHEET_SIZE)
        media_catalog_number, lead_in_samples, flags, num_tracks = \
            struct_unpack(self.__CUESHEET_FORMAT, header)
        self.media_catalog_number = media_catalog_number.rstrip(b'\0')
        self.lead_in_samples = lead_in_samples
        self.compact_disc = bool(flags & 0x80)
        self.tracks = []
        for i in range(num_tracks):
            track = data.read(self.__CUESHEET_TRACK_SIZE)
            start_offset, track_number, isrc_padded, flags, num_indexes = \
                struct_unpack(self.__CUESHEET_TRACK_FORMAT, track)
            isrc = isrc_padded.rstrip(b'\0')
            type_ = (flags & 0x80) >> 7
            pre_emphasis = bool(flags & 0x40)
            val = CueSheetTrack(track_number, start_offset, isrc, type_,
                                pre_emphasis)
            for j in range(num_indexes):
                index = data.read(self.__CUESHEET_TRACKINDEX_SIZE)
                index_offset, index_number = struct_unpack(
                    self.__CUESHEET_TRACKINDEX_FORMAT, index)
                val.indexes.append(
                    CueSheetTrackIndex(index_number, index_offset))
            self.tracks.append(val)

    def write(self):
        f = BytesIO()
        flags = 0
        if self.compact_disc: flags |= 0x80
        packed = struct_pack(self.__CUESHEET_FORMAT, self.media_catalog_number,
                             self.lead_in_samples, flags, len(self.tracks))
        f.write(packed)
        for track in self.tracks:
            track_flags = 0
            track_flags |= (track.type & 1) << 7
            if track.pre_emphasis: track_flags |= 0x40
            track_packed = struct_pack(self.__CUESHEET_TRACK_FORMAT,
                                       track.start_offset, track.track_number,
                                       track.isrc, track_flags,
                                       len(track.indexes))
            f.write(track_packed)
            for index in track.indexes:
                index_packed = struct_pack(self.__CUESHEET_TRACKINDEX_FORMAT,
                                           index.index_offset,
                                           index.index_number)
                f.write(index_packed)
        return f.getvalue()

    def __repr__(self):
        return ("<%s media_catalog_number=%r, lead_in=%r, compact_disc=%r, "
                "tracks=%r>") % (
                    type(self).__name__, self.media_catalog_number,
                    self.lead_in_samples, self.compact_disc, self.tracks)