Пример #1
0
    def __init__(self, atoms, fileobj):
        for trak in list(atoms["moov"].findall("trak")):
            hdlr = trak["mdia", "hdlr"]
            fileobj.seek(hdlr.offset)
            data = fileobj.read(hdlr.length)
            if data[16:20] == "soun":
                break
        else:
            raise MP4StreamInfoError("track has no audio data")

        mdhd = trak["mdia", "mdhd"]
        fileobj.seek(mdhd.offset)
        data = fileobj.read(mdhd.length)
        if ord(data[8]) == 0:
            offset = 20
            format = ">2I"
        else:
            offset = 28
            format = ">IQ"
        end = offset + struct.calcsize(format)
        unit, length = struct.unpack(format, data[offset:end])
        self.length = float(length) / unit

        try:
            atom = trak["mdia", "minf", "stbl", "stsd"]
            fileobj.seek(atom.offset)
            data = fileobj.read(atom.length)
            if data[20:24] == "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] == "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] == "\x80\x80\x80":
                        pos += 3
                    pos += 4
                    # decoder config descriptor type
                    if ord(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] == "\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
Пример #2
0
 def __update_parents(self, fileobj, path, delta):
     """Update all parent atoms with the new size."""
     for atom in path:
         fileobj.seek(atom.offset)
         size = cdata.uint_be(fileobj.read(4)) + delta
         fileobj.seek(atom.offset)
         fileobj.write(cdata.to_uint_be(size))
Пример #3
0
    def __init__(self, atoms, fileobj):
        hdlr = atoms["moov.trak.mdia.hdlr"]
        fileobj.seek(hdlr.offset)
        if "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 = fileobj.read(mdhd.length)
        if ord(data[8]) == 0:
            offset = 20
            format = ">2I"
        else:
            offset = 28
            format = ">IQ"
        end = offset + struct.calcsize(format)
        unit, length = struct.unpack(format, 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
Пример #4
0
 def __parse_freeform(self, atom, data):
     length = cdata.uint_be(data[:4])
     mean = data[12:length]
     pos = length
     length = cdata.uint_be(data[pos:pos+4])
     name = data[pos+12:pos+length]
     pos += length
     value = []
     while pos < atom.length - 8:
         length, atom_name = struct.unpack(">I4s", data[pos:pos+8])
         if atom_name != "data":
             raise MP4MetadataError(
                 "unexpected atom %r inside %r" % (atom_name, atom.name))
         value.append(data[pos+16:pos+length])
         pos += length
     if value:
         self["%s:%s:%s" % (atom.name, mean, name)] = value
Пример #5
0
 def __parse_freeform(self, atom, data):
     try:
         fileobj = StringIO(data)
         mean_length = cdata.uint_be(fileobj.read(4))
         # skip over 8 bytes of atom name, flags
         mean = fileobj.read(mean_length - 4)[8:]
         name_length = cdata.uint_be(fileobj.read(4))
         name = fileobj.read(name_length - 4)[8:]
         value_length = cdata.uint_be(fileobj.read(4))
         # Name, flags, and reserved bytes
         value = fileobj.read(value_length - 4)[12:]
     except struct.error:
         # Some ---- atoms have no data atom, I have no clue why
         # they actually end up in the file.
         pass
     else:
         self["%s:%s:%s" % (atom.name, mean, name)] = value
Пример #6
0
 def __update_offset_table(self, fileobj, fmt, atom, delta, offset):
     """Update offset table in the specified atom."""
     if atom.offset > offset:
         atom.offset += delta
     fileobj.seek(atom.offset + 12)
     data = fileobj.read(atom.length - 12)
     fmt = fmt % cdata.uint_be(data[:4])
     offsets = struct.unpack(fmt, data[4:])
     offsets = [o + (0, delta)[offset < o] for o in offsets]
     fileobj.seek(atom.offset + 16)
     fileobj.write(struct.pack(fmt, *offsets))
Пример #7
0
 def __update_tfhd(self, fileobj, atom, delta, offset):
     if atom.offset > offset:
         atom.offset += delta
     fileobj.seek(atom.offset + 9)
     data = fileobj.read(atom.length - 9)
     flags = cdata.uint_be("\x00" + data[:3])
     if flags & 1:
         o = cdata.ulonglong_be(data[7:15])
         if o > offset:
             o += delta
         fileobj.seek(atom.offset + 16)
         fileobj.write(cdata.to_ulonglong_be(o))
Пример #8
0
 def __parse_text(self, atom, data):
     flags = cdata.uint_be(data[8:12])
     if flags == 1:
         self[atom.name] = data[16:].decode('utf-8', 'replace')