コード例 #1
0
    def mux_on_sample_level(self):
        "Mux media samples into one mdata. This is done by simple concatenation."

        def get_traf_with_mod_offset(mstruct, delta_offset):
            "Get a traf box but with modified offset."
            if mstruct.trun_data_offset is None:
                return mstruct.traf
            new_data_offset = mstruct.trun_data_offset + delta_offset
            traf = mstruct.traf
            offset = mstruct.trun_data_offset_in_traf
            return traf[:offset] + uint32_to_str(new_data_offset) + traf[offset+4:]

        delta_offset1 = len(self.mstruct2.traf)
        delta_offset2 = len(self.mstruct1.traf) + len(self.mstruct1.mdat) - 8
        traf1 = get_traf_with_mod_offset(self.mstruct1, delta_offset1)
        traf2 = get_traf_with_mod_offset(self.mstruct2, delta_offset2)

        moof_size = 8 + len(self.mstruct1.mfhd) + len(self.mstruct1.traf) + len(self.mstruct2.traf)
        mdat_size = len(self.mstruct1.mdat) + len(self.mstruct2.mdat) - 8

        data = []
        data.append(self.mstruct1.styp)
        data.append(uint32_to_str(moof_size))
        data.append(b'moof')
        data.append(self.mstruct1.mfhd)
        data.append(traf1)
        data.append(traf2)
        data.append(uint32_to_str(mdat_size))
        data.append(b'mdat')
        data.append(self.mstruct1.mdat[8:])
        data.append(self.mstruct2.mdat[8:])

        return b"".join(data)
コード例 #2
0
    def process_tfdt(self, data):
        """Generate new timestamps for tfdt and change size of boxes above if needed.

       Try to keep in 32 bits if possible."""
        version = data[8]
        if self.track_timescale is not None:
            tfdt_offset = self.offset * self.track_timescale
        else:
            tfdt_offset = 0
        if version == 0:  # 32-bit baseMediaDecodeTime
            base_media_decode_time = str_to_uint32(data[12:16])
            new_base_media_decode_time = base_media_decode_time + tfdt_offset
            if new_base_media_decode_time < 4294967296:
                output = data[:12]
                output += uint32_to_str(new_base_media_decode_time)
            else:
                # print "Forced to change to 64-bit tfdt."
                self.size_change = 4
                output = uint32_to_str(
                    str_to_uint32(data[:4]) + self.size_change)
                output += data[4:8]
                output += b'\x01'
                output += data[9:12]
                output += uint64_to_str(new_base_media_decode_time)
        else:  # 64-bit
            # print "Staying at 64-bit tfdt."
            output = data[:12]
            base_media_decode_time = str_to_uint64(data[12:20])
            new_base_media_decode_time = base_media_decode_time + tfdt_offset
            output += uint64_to_str(new_base_media_decode_time)
        self.tfdt_value = new_base_media_decode_time
        return output
コード例 #3
0
 def process_tfhd(self, data):
     "Process a tfhd box and set trackID, defaultSampleDuration and defaultSampleSize"
     tf_flags = str_to_uint32(data[8:12]) & 0xffffff
     assert tf_flags == 0x020018, "Can only handle certain tf_flags combinations"
     output = data[:12]
     output += uint32_to_str(self.track_id)
     output += uint32_to_str(self.default_sample_duration)
     output += uint32_to_str(len(self.ttml_data))
     return output
コード例 #4
0
 def update_ttml_mdat(self, data):
     "Update the ttml payload of mdat and its size."
     ttml_xml = data[8:]
     ttml_out = adjust_ttml_content(ttml_xml, self.offset, self.seg_nr)
     self.ttml_size = len(ttml_out)
     out_size = self.ttml_size + 8
     return uint32_to_str(out_size) + b'mdat' + ttml_out
コード例 #5
0
 def get_box(self):
     "Return emsg box as string."
     size = 12 + 4 * 4 + len(self.scheme_id_uri) + 1 + len(
         self.value) + 1 + len(self.messagedata)
     parts = []
     parts.append(uint32_to_str(size))
     parts.append(b"emsg")
     parts.append(b"\x00\x00\x00\x00")
     parts.append(self.scheme_id_uri.encode("utf-8") + b"\x00")
     parts.append(self.value.encode('utf-8') + b"\x00")
     parts.append(uint32_to_str(self.timescale))
     parts.append(uint32_to_str(self.presentation_time_delta))
     parts.append(uint32_to_str(self.event_duration))
     parts.append(uint32_to_str(self.emsg_id))
     parts.append(self.messagedata.encode("utf-8"))
     return b"".join(parts)
コード例 #6
0
    def create_sidx(self, seg_size):
        """Return a sidx box which can be inserted right before the moof.

        This is optional, but some clients require it to present."""
        output = uint32_to_str(52)  # Size of box
        output += b'sidx\x01\x00\x00\x00'  # type, version and flags
        output += b'\x00\x00\x00\x01'  # refID
        output += uint32_to_str(self.track_timescale)
        output += uint64_to_str(self.tfdt_value)  # decode_time for now
        output += uint64_to_str(0)  # first_offset = 0
        output += b'\x00\x00\x00\x01'  # reserved and reference_count
        # Next 1 bit reference type + 31 bit size of segment
        output += uint32_to_str(seg_size)
        output += uint32_to_str(self.duration)
        output += b'\x90\x00\x00\x00'
        return output
コード例 #7
0
 def process_saio(self, data):
     "Process saio and possibly change offset by size_change if needed."
     version_flags = str_to_uint32(data[8:12])
     version = version_flags >> 24
     flags = version_flags & 0xffffff
     pos = 12
     if flags & 0x1:
         pos += 8
     entry_count = str_to_uint32(data[pos:pos + 4])
     pos += 4
     output = data[:pos]
     delta_offset = self.size_change
     if version == 0:
         for i in range(entry_count):
             offset = str_to_uint32(data[pos:pos + 4])
             pos += 4
             output += uint32_to_str(offset + delta_offset)
             if i == 0:
                 self.new_saio_value = offset + delta_offset
     else:
         for i in range(entry_count):
             offset = str_to_uint64(data[pos:pos + 8])
             pos += 8
             output += uint64_to_str(offset + delta_offset)
             if i == 0:
                 self.new_saio_value = offset + delta_offset
     return output
コード例 #8
0
 def process_mvhd(self, data):
     "Set nextTrackId and time and movie timescale."
     output = self._insert_timing_data(data)
     pos = len(output)
     output += data[pos:-4]
     output += uint32_to_str(self.track_id + 1)  # next_track_ID
     return output
コード例 #9
0
 def process_tfhd(self, data):
     "Process tfhd (assuming that we know the ttml size size)."
     tf_flags = str_to_uint32(data[8:12]) & 0xffffff
     pos = 16
     if tf_flags & 0x01:
         raise MediaSegmentFilterError(
             "base-data-offset-present not supported in ttml segments")
     if tf_flags & 0x02:
         pos += 4
     if tf_flags & 0x08:
         self.default_sample_duration = str_to_uint32(data[pos:pos + 4])
         pos += 4
     elif self.ttml_size:
         raise MediaSegmentFilterError(
             "Cannot handle ttml segments with default_sample_duration absent"
         )
     output = data[:pos]
     if self.ttml_size:
         if tf_flags & 0x10:
             # old_ttml__size = str_to_uint32(data[pos:pos+4])
             output += uint32_to_str(self.ttml_size)
             # print("Changed ttml sample size from %d to %d" % (old_ttml__size, self.ttml_size))
             pos += 4
         else:
             raise MediaSegmentFilterError(
                 "Cannot handle ttml segments if default_sample_size_offset is absent"
             )
     if self.ttml_size:
         output += data[pos:]
     else:
         output = data
     return output
コード例 #10
0
    def filter_box(self, boxtype, data, file_pos, path=b""):
        "Filter box or tree of boxes recursively."

        if boxtype == b"moof":
            self.moof_start = file_pos
        elif boxtype == b"mdat":
            self.mdat_start = file_pos

        if path == b"":
            path = boxtype
        else:
            path = b"%s.%s" % (path, boxtype)

        if boxtype in self.composite_boxes_to_parse:
            # print("Parsing %s" % path)
            output = data[:8]
            pos = 8
            while pos < len(data):
                child_size, child_box_type = self.check_box(data[pos:pos + 8])
                output_child_box = self.filter_box(child_box_type,
                                                   data[pos:pos + child_size],
                                                   file_pos + pos, path)
                output += output_child_box
                pos += child_size
            if len(output) != len(data):
                output = uint32_to_str(len(output)) + output[4:]
        else:
            method_name = "process_%s" % boxtype.decode('utf-8')
            method = getattr(self, method_name, None)
            if method is not None:
                output = method(data)
            else:
                output = data
        return output
コード例 #11
0
 def process_sidx(self, data):
     "Process sidx data and add to output."
     if not KEEP_SIDX:
         return b""
     output = b""
     version = data[8]
     timescale = str_to_uint32(data[16:20])
     if version == 0:
         # print("Changing sidx version to 1")
         size = str_to_uint32(data[0:4])
         sidx_size_expansion = 8
         output += uint32_to_str(size + sidx_size_expansion)
         output += data[4:8]
         output += b'\x01'
         output += data[9:20]
         earliest_presentation_time = str_to_uint32(data[20:24])
         first_offset = str_to_uint32(data[24:28])
     else:
         output += data[0:20]
         earliest_presentation_time = str_to_uint64(data[20:28])
         first_offset = str_to_uint64(data[28:36])
     new_presentation_time = earliest_presentation_time + timescale * self.offset
     output += uint64_to_str(new_presentation_time)
     output += uint64_to_str(first_offset)
     if version == 0:
         output += data[28:]
     else:
         output += data[36:]
     return output
コード例 #12
0
 def get_traf_with_mod_offset(mstruct, delta_offset):
     "Get a traf box but with modified offset."
     if mstruct.trun_data_offset is None:
         return mstruct.traf
     new_data_offset = mstruct.trun_data_offset + delta_offset
     traf = mstruct.traf
     offset = mstruct.trun_data_offset_in_traf
     return traf[:offset] + uint32_to_str(new_data_offset) + traf[offset+4:]
コード例 #13
0
 def process_tkhd(self, data):
     "Set trackID and time."
     version = data[8]
     output = data[:12]
     if version == 1:
         if self.creation_modfication_time:
             output += uint64_to_str(self.creation_modfication_time)
             output += uint64_to_str(self.creation_modfication_time)
         else:
             output += data[12:28]
         output += uint32_to_str(self.track_id)
         output += uint32_to_str(0)
         output += uint64_to_str(0)  # duration
         pos = 44
     else:
         if self.creation_modfication_time:
             output += uint32_to_str(self.creation_modfication_time)
             output += uint32_to_str(self.creation_modfication_time)
         else:
             output += data[12:20]
         output += uint32_to_str(self.track_id)
         output += uint32_to_str(0)
         output += uint32_to_str(0)  # duration
         pos = 32
     output += data[pos:]
     return output
コード例 #14
0
    def construct_muxed(self):
        "Construct a multiplexed init segment."
        data = []

        data.append(self.istruct1.ftyp)
        mvex_size = 8 + len(self.istruct1.trex) + len(self.istruct2.trex)
        moov_size = 8 + len(self.istruct1.mvhd) + mvex_size + len(self.istruct1.trak) + len(self.istruct2.trak)

        data.append(uint32_to_str(moov_size))
        data.append(b'moov')
        data.append(self.istruct1.mvhd)
        data.append(uint32_to_str(mvex_size))
        data.append(b'mvex')
        data.append(self.istruct1.trex)
        data.append(self.istruct2.trex)
        data.append(self.istruct1.trak)
        data.append(self.istruct2.trak)

        return b"".join(data)
コード例 #15
0
 def process_hdlr(self, data):
     "Set handler name, if desired."
     hdlr = data[16:20]
     hdlr_name = data[32:-1]  # Actually UTF-8 encoded
     print("Found hdlr %s: %s" % (hdlr, hdlr_name))
     if self.handler_name:
         output = uint32_to_str(len(self.handler_name) + 33) + data[4:32] + self.handler_name + '\x00'
         print("Wrote hdlr %s" % self.handler_name)
     else:
         output = data
     return output
コード例 #16
0
 def _insert_timing_data(self, data):
     "Help function to insert timestamps and timescale in similar boxes."
     version = data[8]
     output = data[:12]
     if version == 1:
         if self.creation_modfication_time:
             output += uint64_to_str(self.creation_modfication_time)
             output += uint64_to_str(self.creation_modfication_time)
         else:
             output += data[12:28]
         output += uint32_to_str(self.timescale)
         output += uint64_to_str(0)  # duration
     else:
         if self.creation_modfication_time:
             output += uint32_to_str(self.creation_modfication_time)
             output += uint32_to_str(self.creation_modfication_time)
         else:
             output += data[12:20]
         output += uint32_to_str(self.timescale)
         output += uint32_to_str(0)
     return output
コード例 #17
0
    def process_mdhd(self, data):
        "Set the timescale for the trak, language and time."

        def get_char_bits(char):
            "Each character in the language is smaller case and offset at 0x60."
            return ord(char) - 96

        output = self._insert_timing_data(data)
        assert len(self.lang) == 3
        lang = self.lang
        lang_bits = (get_char_bits(lang[0]) << 10) + (get_char_bits(lang[1]) << 5) + get_char_bits(lang[2])
        output += uint32_to_str(lang_bits << 16)
        return output
コード例 #18
0
    def process_tfdt_to_64bit(self, data, output):
        """Generate new timestamps for tfdt and change size of boxes above if needed.

        Note that the input output will be returned and can have another size."""
        version = data[8]
        tfdt_offset = self.offset * self.track_timescale
        if version == 0:  # 32-bit baseMediaDecodeTime
            self.size_change = 4
            output = uint32_to_str(str_to_uint32(data[:4]) + self.size_change)
            output += data[4:8]
            output += b'\x01'
            output += data[9:12]
            base_media_decode_time = str_to_uint32(data[12:16])
        else:  # 64-bit
            output = data[:12]
            base_media_decode_time = str_to_uint64(data[12:20])
        new_base_media_decode_time = base_media_decode_time + tfdt_offset
        output += uint64_to_str(new_base_media_decode_time)
        self.tfdt_value = new_base_media_decode_time
        return output
コード例 #19
0
 def process_styp(self, data):
     "Process styp and make sure lmsg presence follows the lmsg flag parameter. Add scte35 box if appropriate"
     lmsg = self.lmsg
     output = b""
     size = str_to_uint32(data[:4])
     pos = 8
     brands = []
     while pos < size:
         brand = data[pos:pos + 4]
         if brand != b"lmsg":
             brands.append(brand)
         pos += 4
     if lmsg:
         brands.append(b"lmsg")
     new_size = 8 + 4 * len(brands)
     output += uint32_to_str(new_size)
     output += b"styp"
     for brand in brands:
         output += brand
     scte35box = self.create_scte35box()
     output += scte35box
     return output
コード例 #20
0
 def process_mfhd(self, data):
     "Set sequence number."
     return data[:12] + uint32_to_str(self.sequence_nr)
コード例 #21
0
    def process_trun(self, data):
        """Process trun box."""
        # pylint: disable=too-many-locals,too-many-branches,too-many-statements
        output = data[:16]

        flags = str_to_uint32(data[8:12]) & 0xffffff
        sample_count = str_to_uint32(data[12:16])
        pos = 16
        # data_offset_present = False

        if flags & 0x1:  # Data offset present
            # data_offset_present = True
            self.trun_offset = str_to_uint32(data[16:20])
            output += uint32_to_str(self.trun_offset)
            pos += 4
        if flags & 0x4:
            pos += 4  # First sample flags present

        sample_duration_present = flags & 0x100
        sample_size_present = flags & 0x200
        sample_flags_present = flags & 0x400
        sample_comp_time_present = flags & 0x800
        sample_time_tfdt = self.tfdt

        orig_sample_pos = 0

        for i in range(sample_count):
            duration = 0
            size = 0
            flags = 0
            comp_time = 0

            if sample_duration_present:
                duration = str_to_uint32(data[pos:pos + 4])
                pos += 4
            if sample_size_present:
                size = str_to_uint32(data[pos:pos + 4])
                pos += 4
            if sample_flags_present:
                flags = str_to_uint32(data[pos:pos + 4])
                pos += 4
            if sample_comp_time_present:
                comp_time = str_to_uint32(data[pos:pos + 4])
                pos += 4

            start_time = 0
            if i == 0:
                start_time = (sample_time_tfdt) / float(self.time_scale)
            else:
                start_time = (sample_time_tfdt + comp_time) / float(
                    self.time_scale)

            end_time = (sample_time_tfdt + comp_time + duration) / float(
                self.time_scale)
            # start_time = (sample_time_tfdt) / float(self.time_scale)
            # end_time = (sample_time_tfdt + duration) / float(self.time_scale)

            # print("startTime:", start_time, "(", comp_time, ")", ", endTime:", end_time)

            scc_samples = self.get_scc_data(start_time, end_time)
            orig_sample_pos += size
            if len(scc_samples):
                print(
                    " ", i, "SampleTime: " + str(
                        (sample_time_tfdt) / float(self.time_scale)),
                    "num samples to add: ", len(scc_samples))
                scc_generated_data = generate_data(scc_samples)
                self.scc_map.append({
                    'pos': orig_sample_pos,
                    'scc': scc_generated_data,
                    'len': len(scc_generated_data)
                })
                size += len(scc_generated_data)

            if sample_duration_present:
                output += uint32_to_str(duration)
            if sample_size_present:
                output += uint32_to_str(size)
            if sample_flags_present:
                output += uint32_to_str(flags)
            if sample_comp_time_present:
                output += uint32_to_str(comp_time)

            sample_time_tfdt += duration

        return output
コード例 #22
0
 def process_mdat(self, data):
     "Make an mdat box with the right size to contain the one-and-only ttml sample."
     size = len(self.ttml_data) + 8
     return uint32_to_str(size) + b'mdat' + self.ttml_data
コード例 #23
0
 def process_mfhd(self, data):
     "Process mfhd box and set segmentNumber if requested."
     if self.seg_nr is None:
         return data
     else:
         return data[0:12] + uint32_to_str(self.seg_nr)