예제 #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
            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 = 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 __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
예제 #3
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))
예제 #4
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))
예제 #5
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))
         if size == 1:  # 64bit
             # skip name (4B) and read size (8B)
             size = cdata.ulonglong_be(fileobj.read(12)[4:])
             fileobj.seek(atom.offset + 8)
             fileobj.write(cdata.to_ulonglong_be(size + delta))
         else:  # 32bit
             fileobj.seek(atom.offset)
             fileobj.write(cdata.to_uint_be(size + delta))