Beispiel #1
0
    def test_mdhd_build(self):
        mdhd_data = Box.build(
            dict(type=b"mdhd",
                 creation_time=0,
                 modification_time=0,
                 timescale=1000000,
                 duration=0,
                 language=u"und"))
        self.assertEqual(len(mdhd_data), 32)
        self.assertEqual(
            mdhd_data,
            b'\x00\x00\x00\x20mdhd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0fB@\x00\x00\x00\x00U\xc4\x00\x00'
        )

        mdhd_data64 = Box.build(
            dict(type=b"mdhd",
                 version=1,
                 creation_time=0,
                 modification_time=0,
                 timescale=1000000,
                 duration=0,
                 language=u"und"))
        self.assertEqual(len(mdhd_data64), 44)
        self.assertEqual(
            mdhd_data64,
            b'\x00\x00\x00,mdhd\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0fB@\x00\x00\x00\x00\x00\x00\x00\x00U\xc4\x00\x00'
        )
Beispiel #2
0
 def test_ftyp_build(self):
     self.assertEqual(
         Box.build(
             dict(type=b"ftyp",
                  major_brand=b"iso5",
                  minor_version=1,
                  compatible_brands=[b"iso5", b"avc1"])),
         b'\x00\x00\x00\x18ftypiso5\x00\x00\x00\x01iso5avc1')
Beispiel #3
0
 def test_tenc_build(self):
     self.assertEqual(
         Box.build(dict(
             type=b"tenc",
             key_ID=UUID('337b9643-21b6-4355-9e59-3eccb46c7ef7'),
             iv_size=8,
             is_encrypted=1)),
         b'\x00\x00\x00 tenc\x00\x00\x00\x00\x00\x00\x01\x083{\x96C!\xb6CU\x9eY>\xcc\xb4l~\xf7')
Beispiel #4
0
def decrypt(key, inp, out):
    """
    decrypt()

    @param key: AES-128 CENC key in bytes
    @param inp: Open input file
    @param out: Open output file
    """

    with BufferedReader(inp) as reader:
        senc_boxes = deque()
        trun_boxes = deque()

        while reader.peek(1):
            box = Box.parse_stream(reader)
            fix_headers(box)

            for stsd_box in BoxUtil.find(box, b'stsz'):
                sample_size = stsd_box.sample_size

            if box.type == b'moof':
                senc_boxes.extend(BoxUtil.find(box, b'senc'))
                trun_boxes.extend(BoxUtil.find(box, b'trun'))
            elif box.type == b'mdat':
                senc_box = senc_boxes.popleft()
                trun_box = trun_boxes.popleft()

                clear_box = b''

                with BytesIO(box.data) as box_bytes:
                    for sample, sample_info in zip(
                            senc_box.sample_encryption_info,
                            trun_box.sample_info):
                        counter = Counter.new(64,
                                              prefix=sample.iv,
                                              initial_value=0)

                        cipher = AES.new(key, AES.MODE_CTR, counter=counter)

                        if sample_size:
                            cipher_bytes = box_bytes.read(sample_size)
                            clear_box += cipher.decrypt(cipher_bytes)
                        elif not sample.subsample_encryption_info:
                            cipher_bytes = box_bytes.read(
                                sample_info.sample_size)
                            clear_box += cipher.decrypt(cipher_bytes)
                        else:
                            for subsample in sample.subsample_encryption_info:
                                clear_box += box_bytes.read(
                                    subsample.clear_bytes)
                                cipher_bytes = box_bytes.read(
                                    subsample.cipher_bytes)
                                clear_box += cipher.decrypt(cipher_bytes)
                box.data = clear_box
            out.write(Box.build(box))
    return
Beispiel #5
0
    def test_moov_build(self):
        moov = \
            Container(type=b"moov")(children=[  # 96 bytes
                Container(type=b"mvex")(children=[  # 88 bytes
                    Container(type=b"mehd")(version=0)(flags=0)(fragment_duration=0),  # 16 bytes
                    Container(type=b"trex")(track_ID=1),  # 32 bytes
                    Container(type=b"trex")(track_ID=2),  # 32 bytes
                ])
            ])

        moov_data = Box.build(moov)

        self.assertEqual(len(moov_data), 96)
        self.assertEqual(
            moov_data, b'\x00\x00\x00\x60moov'
            b'\x00\x00\x00\x58mvex'
            b'\x00\x00\x00\x10mehd\x00\x00\x00\x00\x00\x00\x00\x00'
            b'\x00\x00\x00\x20trex\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
            b'\x00\x00\x00\x20trex\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
        )
Beispiel #6
0
    def test_build_emib(self):
        emib_b = Box.build(
            dict(type=b"emib",
                 version=0,
                 reserved=1,
                 presentation_time_delta=-1000,
                 value=b'',
                 id=1,
                 scheme_id_uri=b"my_test_scheme",
                 duration=2000,
                 message_data=b"asdfdasgfaghhgsdgh"))

        emib_b_p = Box.parse(emib_b)
        self.assertEqual(emib_b_p["type"], b'emib')
        self.assertEqual(emib_b_p["presentation_time_delta"], -1000)
        self.assertEqual(emib_b_p["value"], b'')
        self.assertEqual(emib_b_p["id"], 1)
        self.assertEqual(emib_b_p["scheme_id_uri"], b"my_test_scheme")
        self.assertEqual(emib_b_p["duration"], 2000)
        self.assertEqual(emib_b_p["reserved"], 1)
        self.assertEqual(emib_b_p["message_data"], b"asdfdasgfaghhgsdgh")
Beispiel #7
0
    def test_build_emsg(self):
        emsg_b = Box.build(
            dict(type=b"emsg",
                 version=1,
                 presentation_time=1000,
                 value=b'',
                 id=1,
                 scheme_id_uri=b"my_test_scheme",
                 event_duration=20,
                 timescale=1,
                 message_data=b"asdfdasgfaghhgsdgh"))

        emsg_b_p = Box.parse(emsg_b)
        self.assertEqual(emsg_b_p["type"], b'emsg')
        self.assertEqual(emsg_b_p["version"], 1)
        self.assertEqual(emsg_b_p["presentation_time"], 1000)
        self.assertEqual(emsg_b_p["value"], b'')
        self.assertEqual(emsg_b_p["id"], 1)
        self.assertEqual(emsg_b_p["scheme_id_uri"], b"my_test_scheme")
        self.assertEqual(emsg_b_p["event_duration"], 20)
        self.assertEqual(emsg_b_p["timescale"], 1)
        self.assertEqual(emsg_b_p["message_data"], b"asdfdasgfaghhgsdgh")
Beispiel #8
0
    def test_parse_edit_list(self):
        elst_b = Box.parse(
            b'\x00\x00\x00\x1celst\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x0f\xa0\x00\x00\x04\x00\x00\x01\x00\x00'
        )
        [Container(edit_duration=4000)(media_time=1024)]
        self.assertEqual(elst_b["type"], b"elst")
        self.assertEqual(len(elst_b["entries"]), 1)
        self.assertEqual(elst_b["entries"][0]["edit_duration"], 4000)
        self.assertEqual(elst_b["entries"][0]["media_time"], 1024)
        self.assertEqual(elst_b["entries"][0]["media_rate_integer"], 1)
        self.assertEqual(elst_b["entries"][0]["media_rate_fraction"], 0)

        t = dict(
             type=b"elst",
             version=1,
             flags=0,
             entries=[dict(edit_duration=1,media_time=1, media_rate_integer=1, media_rate_fraction=1)\
                 ,dict(edit_duration=2,media_time=2, media_rate_integer=1,
             media_rate_fraction=1)  ],

            )
        elst_b = Box.build(t)
        t2 = Box.parse(elst_b)
        self.assertEqual(len(t["entries"]), len(t2["entries"]))
Beispiel #9
0
 def test_build_evte(self):
     evte = Box.build(dict(type=b"evte", children=[]))
Beispiel #10
0
 def test_smhd_build(self):
     smhd_data = Box.build(dict(type=b"smhd", balance=0))
     self.assertEqual(len(smhd_data), 16),
     self.assertEqual(
         smhd_data, b'\x00\x00\x00\x10smhd\x00\x00\x00\x00\x00\x00\x00\x00')
Beispiel #11
0
    def _output_mp4_footer(self, framerate, resolution):
        # Extact all the variables used after in the construction of the boxes
        sample_count = len(self._sample_sizes)
        timescale = framerate.numerator
        sample_delta = framerate.denominator
        duration = sample_count * sample_delta
        chunk_offset = self.mdat_payload_offset
        width = resolution[0]
        height = resolution[1]
        profile, compatibility, level = DEFAULT_SPS_INDICATIONS if self.indications is None else self.indications
        sample_sizes = self._sample_sizes
        sps = list(self.seq_parm_sets)
        pps = list(self.pic_parm_sets)

        # Build all the boxes we need
        HDLR = Container(type=b'hdlr')
        HDLR(version=0)
        HDLR(flags=0)
        HDLR(handler_type=b'vide')
        HDLR(name='VideoHandler')

        MDHD = Container(type=b'mdhd')
        MDHD(version=0)
        MDHD(flags=0)
        MDHD(creation_time=0)
        MDHD(modification_time=0)
        MDHD(timescale=timescale)
        MDHD(duration=duration)
        MDHD(language='und')

        URL_ = Container(type=b'url ')
        URL_(version=0)
        URL_(flags=Container(self_contained=True))
        URL_(location=None)

        DREF = Container(type=b'dref')
        DREF(version=0)
        DREF(flags=0)
        DREF(data_entries=[URL_])

        DINF = Container(type=b'dinf')
        DINF(children=[DREF])

        STTS = Container(type=b'stts')
        STTS(version=0)
        STTS(flags=0)
        STTS(entries=[
            Container(sample_count=sample_count)(sample_delta=sample_delta)
        ])

        AVCC = Container(type=b'avcC')
        AVCC(version=1)
        AVCC(profile=profile)
        AVCC(compatibility=compatibility)
        AVCC(level=level)
        AVCC(nal_unit_length_field=3)
        AVCC(sps=sps)
        AVCC(pps=pps)

        AVC1 = Container(format=b'avc1')
        AVC1(data_reference_index=1)
        AVC1(version=0)
        AVC1(revision=0)
        AVC1(vendor=b'')
        AVC1(temporal_quality=0)
        AVC1(spatial_quality=0)
        AVC1(width=width)
        AVC1(height=height)
        AVC1(horizontal_resolution=72)
        AVC1(vertical_resolution=72)
        AVC1(data_size=0)
        AVC1(frame_count=1)
        AVC1(compressor_name=b'')
        AVC1(depth=24)
        AVC1(color_table_id=-1)
        AVC1(avc_data=AVCC)

        STSD = Container(type=b'stsd')
        STSD(version=0)
        STSD(flags=0)
        STSD(entries=[AVC1])

        STSC = Container(type=b'stsc')
        STSC(version=0)
        STSC(flags=0)
        STSC(entries=[
            Container(first_chunk=1)(samples_per_chunk=sample_count)(
                sample_description_index=1)
        ])

        STCO = Container(type=b'stco')
        STCO(version=0)
        STCO(flags=0)
        STCO(entries=[Container(chunk_offset=chunk_offset)])

        STSZ = Container(type=b'stsz')
        STSZ(version=0)
        STSZ(flags=0)
        STSZ(sample_size=0)
        STSZ(sample_count=sample_count)
        STSZ(entry_sizes=sample_sizes)

        STBL = Container(type=b'stbl')
        STBL(children=[STSD, STTS, STSC, STSZ, STCO])

        VMHD = Container(type=b'vmhd')
        VMHD(version=0)
        VMHD(flags=1)
        VMHD(graphics_mode=0)
        VMHD(opcolor=Container(red=0)(green=0)(blue=0))

        MINF = Container(type=b'minf')
        MINF(children=[VMHD, DINF, STBL])

        MDIA = Container(type=b'mdia')
        MDIA(children=[MDHD, HDLR, MINF])

        # Width and height in TKHD are 16.16 integers
        TKHD = Container(type=b'tkhd')
        TKHD(version=0)
        TKHD(flags=3)
        TKHD(creation_time=0)
        TKHD(modification_time=0)
        TKHD(track_ID=1)
        TKHD(duration=duration)
        TKHD(layer=0)
        TKHD(alternate_group=0)
        TKHD(volume=0)
        TKHD(matrix=UNITY_MATRIX)
        TKHD(width=width << 16)
        TKHD(height=height << 16)

        TRAK = Container(type=b'trak')
        TRAK(children=[TKHD, MDIA])

        MVHD = Container(type=b'mvhd')
        MVHD(version=0)
        MVHD(flags=0)
        MVHD(creation_time=0)
        MVHD(modification_time=0)
        MVHD(timescale=timescale)
        MVHD(duration=duration)
        MVHD(rate=0x10000)
        MVHD(volume=0x100)
        MVHD(matrix=UNITY_MATRIX)
        MVHD(pre_defined=[0, 0, 0, 0, 0, 0])
        MVHD(next_track_ID=2)

        MOOV = Container(type=b'moov')
        MOOV(children=[MVHD, TRAK])

        # Finally write
        self._write(Box.build(MOOV))
Beispiel #12
0
    #   2 bits for nal ref idc
    #   5 bits for nal type
    return nal_data[0] & ((1 << 5) - 1)


def sps_get_indications(nal_data):
    assert (nal_get_unit_type(nal_data) == NAL_TYPE_SPS)
    # After the nal type, follows the profile_idc, the "constraint set", aka
    # the compatibility byte, followed by level_idc
    return SPSIndications(profile=nal_data[1],
                          compatibility=nal_data[2],
                          level=nal_data[3])


STATIC_FTYP = Box.build(
    Container(type=b'ftyp')(major_brand=b'isom')(minor_version=0x200)(
        compatible_brands=[b'isom', b'iso2', b'avc1', b'mp41']))

STATIC_EMPTY_MDAT = Box.build(Container(type=b'mdat')(data=b''))


class MP4Muxer(object):
    def __init__(self):
        super(MP4Muxer, self).__init__()
        self.indications = None
        self.pic_parm_sets = set()
        self.seq_parm_sets = set()
        self.current_mdat_size = 0

        self._sample_sizes = []
        self._nal_size_patches = []