Beispiel #1
0
    def process_tfhd(self, data):
        "Process the mvhd box and set timescale."
        tf_flags = str_to_uint32(data[8:12]) & 0xffffff
        #print "tfhd flags = %06x" % tf_flags

        if self.new_default_sample_duration is not None:
            output = uint32_to_str(str_to_uint32(data[0:4]) + 4)
            output += data[4:8]
            output += uint32_to_str(tf_flags | 0x8)
        else:
            output = data[0:8]
            output += uint32_to_str(tf_flags)

        if self.new_track_id is not None:
            old_track_id = str_to_uint32(data[12:16])
            output += uint32_to_str(self.new_track_id)
            print "Changed trackId from %d to %d" % (old_track_id, self.new_track_id)
        else:
            output += data[12:16]

        if self.new_default_sample_duration is not None:
            output += uint32_to_str(self.new_default_sample_duration)
            print "Added new default sample duration: %d"%(self.new_default_sample_duration)

        output += data[16:]
        return output
Beispiel #2
0
    def _generate_trun(self, seg_info, offset):
        "Generate trun box with correct sample data for segment."

        def nr_sample_bytes(sample_flags):
            nr_bytes = 0
            for pattern in (0x100, 0x200, 0x400, 0x800):
                if sample_flags & pattern != 0:
                    nr_bytes += 4
            return nr_bytes

        version = 0
        ip = self.input_parser
        sample_data_size = nr_sample_bytes(self.sample_flags)
        sample_count = seg_info.end_nr - seg_info.start_nr
        trun_size = 20 + sample_count * sample_data_size
        output = uint32_to_str(trun_size) + 'trun'
        flags = self.sample_flags | 0x01  # offset present
        version_and_flags = (version << 24) | flags
        output += uint32_to_str(version_and_flags)
        output += uint32_to_str(sample_count)
        output += uint32_to_str(offset + trun_size + 8)  # 8 bytes into mdat
        for sample in ip.samples[seg_info.start_nr:seg_info.end_nr]:
            if self.sample_flags & 0x100:
                output += uint32_to_str(sample.dur)
            if self.sample_flags & 0x200:
                output += uint32_to_str(sample.size)
            if self.sample_flags & 0x400:
                output += uint32_to_str(sample.flags)
            if self.sample_flags & 0x800:
                output += uint32_to_str(sample.cto)
        return output
Beispiel #3
0
 def _generate_tfdt(self, seg_info):
     if seg_info.start_time > 2**30:
         version = 1
         size = 20
     else:
         version = 0
         size = 16
     output = uint32_to_str(size) + 'tfdt'
     if version == 0:
         output += uint32_to_str(0x00000000) + uint32_to_str(
             seg_info.start_time)
     else:
         output += uint32_to_str(0x01000000) + uint64_to_str(
             seg_info.start_time)
     return output
Beispiel #4
0
 def _generate_traf(self, seg_info, offset):
     tfhd = self._generate_tfhd(seg_info, self.track_id)
     tfdt = self._generate_tfdt(seg_info)
     offset += 8 + len(tfhd) + len(tfdt)
     trun = self._generate_trun(seg_info, offset)
     size = 8 + len(tfhd) + len(tfdt) + len(trun)
     return uint32_to_str(size) + 'traf' + tfhd + tfdt + trun
 def process_tkhd(self, data):
     "Process tkhd and set flags, trackId and duration."
     version = ord(data[8])
     output = data[0:9]
     output += '\x00' + '\x00' + '\x07' # Set flags to 0x000007
     pos = 12
     if version == 1:
         drange = 16
     else:
         drange = 8
     output += data[pos:pos+drange]
     pos += drange
     if self.new_track_id is not None:
         old_track_id = str_to_uint32(data[pos:pos+4])
         output += uint32_to_str(self.new_track_id)
         print "Changed trackId from %d to %d" % (old_track_id, self.new_track_id)
     else:
         output += data[pos:pos+4]
     pos += 4
     output += data[pos:pos+4]
     pos += 4
     if version == 1:
         output += '\x00'*8 # duration
         pos += 8
     else: # version = 0
         output += '\x00'*4 # duration
         pos += 4
     output += data[pos:]
     return output
 def process_trun(self, data, output):
     """Adjust time of tfdt if offset set."""
     version_and_flags = str_to_uint32(data[8:12])
     # version = version_and_flags >> 24
     flags = version_and_flags & 0xffffff
     sample_count = str_to_uint32(data[12:16])
     offset = 16
     if flags & 0x1:  # data_offset_present
         offset += 4
     if flags & 0x4:  # first_sample_flags
         offset += 4
     output += data[:offset]
     for i in range(sample_count):
         if flags & 0x100:  # sample_duration present
             output += data[offset:offset + 4]
             offset += 4
         if flags & 0x200:  # sample_size present
             output += data[offset:offset + 4]
             offset += 4
         if flags & 0x400:  # sample_flags present
             sample_flags = str_to_uint32(data[offset:offset + 4])
             if sample_flags != 0x2000000:  # Depends on other samples
                 sample_flags |= 0x10000
             output += uint32_to_str(sample_flags)
             offset += 4
         if flags & 0x800:  # composition_time_offset present
             output += data[offset:offset + 4]
             offset += 4
     return output
Beispiel #7
0
 def process_mfhd(self, data, output):
     "Set the sequence number in mfhd."
     if self.seq_nr is not None:
         output += data[:12] + uint32_to_str(self.seq_nr)
     else:
         output += data
     return output
Beispiel #8
0
 def _generate_moof(self, sequence_nr, seg_info):
     "Generate a moof box with the correct sample entries"
     mfhd = self._generate_mfhd(sequence_nr)
     offset = 8 + len(mfhd)
     traf = self._generate_traf(seg_info, offset)
     size = 8 + len(mfhd) + len(traf)
     return uint32_to_str(size) + 'moof' + mfhd + traf
Beispiel #9
0
 def process_tkhd(self, data):
     "Process tkhd and set flags, trackId and duration."
     version = ord(data[8])
     output = data[0:9]
     output += '\x00' + '\x00' + '\x07'  # Set flags to 0x000007
     pos = 12
     if version == 1:
         drange = 16
     else:
         drange = 8
     output += data[pos:pos + drange]
     pos += drange
     if self.new_track_id is not None:
         old_track_id = str_to_uint32(data[pos:pos + 4])
         output += uint32_to_str(self.new_track_id)
         print "Changed trackId from %d to %d" % (old_track_id,
                                                  self.new_track_id)
     else:
         output += data[pos:pos + 4]
     pos += 4
     output += data[pos:pos + 4]
     pos += 4
     if version == 1:
         output += '\x00' * 8  # duration
         pos += 8
     else:  # version = 0
         output += '\x00' * 4  # duration
         pos += 4
     output += data[pos:]
     return output
 def construct_new_mdat(self, media_info):
     "Return an mdat box with data for samples in media_info."
     start_nr = media_info.start_nr
     end_nr = media_info.end_nr
     sample_data = []
     for i in range(media_info.start_nr, media_info.end_nr):
         sample = self.samples[i]
         sample_data.append(self.data[sample.offset:sample.offset +
                                      sample.size])
     combined_data = "".join(sample_data)
     return uint32_to_str(8 + len(combined_data)) + 'mdat' + combined_data
Beispiel #11
0
    def process_trun(self, data):
        tf_flags = str_to_uint32(data[8:12]) & 0xffffff

        output = data[0:8]
        output += uint32_to_str(tf_flags)

        print "Changing trun sample count"
        output += uint32_to_str(1)

        if tf_flags & 1:
            data_offset = str_to_uint32(data[16:20])
            if self.new_default_sample_duration is not None:
                print "Changing trun data offset: %d to %d"%(data_offset, data_offset + 4)
                data_offset += 4

            output += uint32_to_str(data_offset)

            output += data[20:]

        return output
    def finalize(self):
        "Rewrite the size fields which have changed"
        op = self.output
        op_parts = []

        size_reduction = self.trun_data['size'] - self.trun_data['new_size']
        op_parts.append(op[:self.moof_data['pos']])

        # Write new moof size
        new_moof_size = self.moof_data['size'] - size_reduction
        op_parts.append(uint32_to_str(new_moof_size))
        pos = self.moof_data['pos'] + 4
        op_parts.append(op[pos:self.traf_data['pos']])

        # Write new traf size
        new_traf_size = self.traf_data['size'] - size_reduction
        op_parts.append(uint32_to_str(new_traf_size))
        pos = self.traf_data['pos'] + 4

        op_parts.append(op[pos:])

        self.output = "".join(op_parts)
Beispiel #13
0
 def process_tfhd(self, data):
     "Process the mvhd box and set timescale."
     tf_flags = str_to_uint32(data[8:12]) & 0xffffff
     print "tfhd flags = %06x" % tf_flags
     output = data[0:12]
     if self.new_track_id is not None:
         old_track_id = str_to_uint32(data[12:16])
         output += uint32_to_str(self.new_track_id)
         print "Changed trackId from %d to %d" % (old_track_id, self.new_track_id)
     else:
         output += data[12:16]
     output += data[16:]
     return output
 def process_composite_box(self, path, data):
     "Process a composite box."
     #pylint: disable=unused-variable
     container_size, container_box_type = self.check_box(data[0:8])
     inner_data = ""
     pos = 8
     while pos < len(data):
         size, box_type = self.check_box(data[pos:pos + 8])
         inner_data += self.filterbox(box_type, data[pos:pos+size], None, path)
         pos += size
     new_container_size = 8 + len(inner_data)
     #Note. If this has changed, make sure that offsets are changes appropriately
     return uint32_to_str(new_container_size) + container_box_type + inner_data
Beispiel #15
0
def change_brands(indata, major_brand, compatibility_brands, minor_version=0):
    "Change brands in input string indata and return new string."
    size = str_to_uint32(indata)
    ftyp = indata[4:8]
    assert ftyp == "ftyp"
    in_major_brand = indata[8:12]
    print "Changing major brand %s - > %s" % (in_major_brand, major_brand)
    in_minor_version = str_to_uint32(indata[12:16])
    print "minorVersion: %s -> %s" % (in_minor_version, minor_version)
    pos = 16
    in_compatibility_brands = []
    while pos < size:
        in_compatibility_brands.append(indata[pos:pos+4])
        pos += 4
    print "Compatibility brands: %s -> %s" % (in_compatibility_brands, compatibility_brands)

    out_size = 16 + 4*len(compatibility_brands)
    outdata = uint32_to_str(out_size) + "ftyp" + major_brand + uint32_to_str(minor_version)
    for brand in compatibility_brands:
        outdata += brand
    outdata += indata[size:]
    return outdata
Beispiel #16
0
 def process_composite_box(self, path, data):
     "Process composite boxes."
     container_size, container_box_type = self.check_box(data[0:8])
     inner_data = ""
     pos = 8
     while pos < len(data):
         size, box_type = self.check_box(data[pos:pos + 8])
         inner_data += self.filterbox(box_type, data[pos:pos+size], None, path)
         #print "Box:",box_type,", size:",size,", newsize:",len(inner_data)
         pos += size
     new_container_size = 8 + len(inner_data)
     #TODO. If this has changed, make sure that offsets are changes appropriately
     return uint32_to_str(new_container_size) + container_box_type + inner_data
Beispiel #17
0
 def process_composite_box(self, path, data):
     "Process a composite box."
     #pylint: disable=unused-variable
     container_size, container_box_type = self.check_box(data[0:8])
     inner_data = ""
     pos = 8
     while pos < len(data):
         size, box_type = self.check_box(data[pos:pos + 8])
         inner_data += self.filterbox(box_type, data[pos:pos+size], None, path)
         pos += size
     new_container_size = 8 + len(inner_data)
     #Note. If this has changed, make sure that offsets are changes appropriately
     return uint32_to_str(new_container_size) + container_box_type + inner_data
def change_brands(indata, major_brand, compatibility_brands, minor_version=0):
    "Change brands in input string indata and return new string."
    size = str_to_uint32(indata)
    ftyp = indata[4:8]
    assert ftyp == "ftyp"
    in_major_brand = indata[8:12]
    print "Changing major brand %s - > %s" % (in_major_brand, major_brand)
    in_minor_version = str_to_uint32(indata[12:16])
    print "minorVersion: %s -> %s" % (in_minor_version, minor_version)
    pos = 16
    in_compatibility_brands = []
    while pos < size:
        in_compatibility_brands.append(indata[pos : pos + 4])
        pos += 4
    print "Compatibility brands: %s -> %s" % (in_compatibility_brands, compatibility_brands)

    out_size = 16 + 4 * len(compatibility_brands)
    outdata = uint32_to_str(out_size) + "ftyp" + major_brand + uint32_to_str(minor_version)
    for brand in compatibility_brands:
        outdata += brand
    outdata += indata[size:]
    return outdata
 def process_tfhd(self, data):
     "Process the mvhd box and set timescale."
     tf_flags = str_to_uint32(data[8:12]) & 0xffffff
     print "tfhd flags = %06x" % tf_flags
     output = data[0:12]
     if self.new_track_id is not None:
         old_track_id = str_to_uint32(data[12:16])
         output += uint32_to_str(self.new_track_id)
         print "Changed trackId from %d to %d" % (old_track_id, self.new_track_id)
     else:
         output += data[12:16]
     output += data[16:]
     return output
Beispiel #20
0
 def _generate_sidx(self, segment_info, segment_sizes, timescale):
     "Generate sidx box."
     earliest_presentation_time = segment_info[0].start_time
     parts = ['sidx',
              uint32_to_str(0), # version + flags
              uint32_to_str(1), # reference_ID
              uint32_to_str(timescale),
              uint32_to_str(earliest_presentation_time),
              uint32_to_str(0),  # first_offset
              uint16_to_str(0),  # reserved
              uint16_to_str(len(segment_sizes))]  # reference_count
     for info, size in zip(segment_info, segment_sizes):
         parts.append(uint32_to_str(size))  # Setting reference type to 0
         parts.append(uint32_to_str(info.dur))
         parts.append(uint32_to_str(0x90000000)) # SAP info
     output = ''.join(parts)
     size = 4 + len(output)
     output = uint32_to_str(size) + output
     return output
    def process_file(self):
        "Process the file and add or remove lmsg."
        ifh = open(self.file_path, "rb")
        data = ifh.read()
        styplen = str_to_uint32(data[:4])
        box_type = data[4:8]
        assert box_type == "styp"

        pos = 16
        lmsg_found = False
        while pos < styplen:
            compatible_brand = data[pos:pos+4]
            if compatible_brand == "lmsg":
                lmsg_found = True
                if self.remove_lmsg_flag:
                    print "Found lmsg to remove"
                    break
            pos += 4
        ofh = cStringIO.StringIO()
        if self.add_lmsg_flag and not lmsg_found:
            ofh.write(uint32_to_str(styplen+4))
            ofh.write(data[4:styplen])
            ofh.write("lmsg")
            ofh.write(data[styplen:])
            print "Adding lmsg"
        elif self.remove_lmsg_flag and lmsg_found:
            ofh.write(uint32_to_str(styplen-4))
            ofh.write(data[4:pos])
            ofh.write(data[pos+4:])
        else:
            print "No change done to %s" % self.file_path
            return # Nothing to do
        ifh.close()
        replace = open(self.file_path, "wb")
        replace.write(ofh.getvalue())
        replace.close()
        print "Wrote %s" % self.file_path
Beispiel #22
0
    def process_file(self):
        "Process the file and add or remove lmsg."
        ifh = open(self.file_path, "rb")
        data = ifh.read()
        styplen = str_to_uint32(data[:4])
        box_type = data[4:8]
        assert box_type == "styp"

        pos = 16
        lmsg_found = False
        while pos < styplen:
            compatible_brand = data[pos:pos + 4]
            if compatible_brand == "lmsg":
                lmsg_found = True
                if self.remove_lmsg_flag:
                    print "Found lmsg to remove"
                    break
            pos += 4
        ofh = cStringIO.StringIO()
        if self.add_lmsg_flag and not lmsg_found:
            ofh.write(uint32_to_str(styplen + 4))
            ofh.write(data[4:styplen])
            ofh.write("lmsg")
            ofh.write(data[styplen:])
            print "Adding lmsg"
        elif self.remove_lmsg_flag and lmsg_found:
            ofh.write(uint32_to_str(styplen - 4))
            ofh.write(data[4:pos])
            ofh.write(data[pos + 4:])
        else:
            print "No change done to %s" % self.file_path
            return  # Nothing to do
        ifh.close()
        replace = open(self.file_path, "wb")
        replace.write(ofh.getvalue())
        replace.close()
        print "Wrote %s" % self.file_path
Beispiel #23
0
    def finalize(self):
        print "Changing default sample size"

        if self.new_default_sample_duration:
            newoutput = self.output[:76]
        else:
            newoutput = self.output[:72]

        newoutput += uint32_to_str(self.ttml_length)

        if self.new_default_sample_duration:
            newoutput += self.output[80:]
        else:
            newoutput += self.output[76:]

        self.output = newoutput
Beispiel #24
0
    def process_mdat(self, data):
        print "Merging all ttml samples into one"
        ttml = data[8:]
        #print "------------------------------"
        #print ttml

        # Process TTML
        # TODO Fix this to use something better then string replace
        ttml = ttml.replace(REPLACE_STRING, "")
        self.ttml_length = len(ttml)

        #print "------------------------------"
        #print ttml

        output = uint32_to_str(self.ttml_length + 8)
        output += data[4:8]
        output += ttml

        return output
Beispiel #25
0
 def process_tfdt(self, data, output):
     """Adjust time of tfdt if offset set."""
     version = ord(data[8])
     if version == 0: # 32-bit baseMediaDecodeTime
         tfdt = str_to_uint32(data[12:16])
         if self.offset != None:
             tfdt += self.offset
             output += data[:12] + uint32_to_str(tfdt) + data[16:]
         else:
             output += data
     else:
         output = data[:12]
         tfdt = str_to_uint64(data[12:20])
         if self.offset != None:
             tfdt += self.offset
             output += uint64_to_str(tfdt)
         else:
             output += data
     self.tfdt = tfdt
     return output
 def process_tfdt(self, data, output):
     """Adjust time of tfdt if offset set."""
     version = ord(data[8])
     if version == 0: # 32-bit baseMediaDecodeTime
         tfdt = str_to_uint32(data[12:16])
         if self.offset != None:
             tfdt += self.offset
             output += data[:12] + uint32_to_str(tfdt) + data[16:]
         else:
             output += data
     else:
         output = data[:12]
         tfdt = str_to_uint64(data[12:20])
         if self.offset != None:
             tfdt += self.offset
             output += uint64_to_str(tfdt)
         else:
             output += data
     self.tfdt = tfdt
     return output
Beispiel #27
0
    def _generate_tfhd(self, seg_info, track_id):
        ip = self.input_parser
        first_sample = ip.samples[seg_info.start_nr]
        common_size = first_sample.size
        common_dur = first_sample.dur
        common_flags = first_sample.flags
        common_cto = first_sample.cto
        for sample in ip.samples[seg_info.start_nr + 1:seg_info.end_nr]:
            if sample.dur != common_dur:
                common_dur = None
            if sample.size != common_size:
                common_size = None
            if sample.flags != common_flags:
                common_flags = None
            if sample.cto != common_cto:
                common_cto = None
        flags = 0x020000
        data = ""
        sample_flags = 0  # Which individual sample data is needed
        if common_dur is not None:
            flags |= 0x08
            data += uint32_to_str(common_dur)
        else:
            sample_flags |= 0x100
        if common_size is not None:
            flags |= 0x10
            data += uint32_to_str(common_size)
        else:
            sample_flags |= 0x200
        if common_flags is not None:
            flags |= 0x20
            data += uint32_to_str(common_flags)
        else:
            sample_flags |= 0x400
        if common_cto is None or common_cto != 0:
            sample_flags |= 0x800
        size = 16 + len(data)
        self.sample_flags = sample_flags

        version_and_flags = flags
        return (uint32_to_str(size) + 'tfhd' +
                uint32_to_str(version_and_flags) + uint32_to_str(track_id) +
                data)
Beispiel #28
0
 def _generate_mfhd(self, sequence_nr):
     return (uint32_to_str(16) +  # size
             'mfhd' + uint32_to_str(0) +  # version_and_flags
             uint32_to_str(sequence_nr))
    def process_trun(self, data):
        """Remove all samples but one, and change offset and report size."""
        size, b_type = self.check_box(data)
        assert b_type == "trun"
        self.trun_data = {'size': size}
        # version = ord(data[8])

        flags = str_to_uint32(data[8:12]) & 0xffffff
        has_data_offset = flags & 0x0001
        if not has_data_offset:
            raise ValueError("Cannot shorten segment without data_offset")
        has_first_sample_flags = flags & 0x0004
        has_sample_duration = flags & 0x0100
        if not has_sample_duration:
            raise ValueError("Cannot shorten segment without sample duration")
        has_sample_size = flags & 0x0200
        if not has_sample_size:
            raise ValueError("Cannot shorten segment without sample_size")
        has_sample_flags = flags & 0x0400
        has_sample_composition_time_offset = flags & 0x0800

        sample_count = str_to_uint32(data[12:16])

        entry_offset = 16

        data_offset = str_to_uint32(data[entry_offset:entry_offset + 4])
        entry_offset += 4

        if has_first_sample_flags:
            entry_offset += 4

        sample_row_size = ((has_sample_duration and 4) +
                           (has_sample_size and 4) + (has_sample_flags and 4) +
                           (has_sample_composition_time_offset and 4))

        # Iterate over all samples and add up duration.
        # Set the duration of the I-frame to the total duration

        total_duration = 0

        pos = entry_offset
        for i in range(sample_count):
            total_duration += str_to_uint32(data[pos:pos + 4])
            pos += 4
            if i == 0:
                sample_size = str_to_uint32(data[pos:pos + 4])
                self.trun_data['first_sample_size'] = sample_size
            pos += 4
            if has_sample_flags:
                pos += 4
            if has_sample_composition_time_offset:
                pos += 4

        new_size = size - (sample_count - 1) * sample_row_size
        self.trun_data['new_size'] = new_size

        new_data_offset = data_offset - (size - new_size)

        # Here starts the trun output
        output = uint32_to_str(new_size) + data[4:12]
        output += uint32_to_str(1)  # 1 sample
        output += uint32_to_str(new_data_offset)
        pos = entry_offset
        if has_first_sample_flags:
            output += data[pos:pos + 4]
            pos += 4
        output += uint32_to_str(total_duration)
        pos += 4
        output += data[pos:pos + sample_row_size - 4]

        return output
 def process_mdat(self, data):
     """Remove all samples but one, and change offset and report size."""
     size, b_type = self.check_box(data)
     assert b_type == "mdat"
     data_size = self.trun_data['first_sample_size']
     return uint32_to_str(data_size + 8) + "mdat" + data[8:8 + data_size]