예제 #1
0
def test_make_text_trak():
    creation_time = utils.to_mp4_time(datetime(2019, 9, 15, 0, 0, 0))
    modification_time = utils.to_mp4_time(datetime(2019, 9, 16, 0, 0, 0))

    samples_sizes = [198297, 127477, 192476]
    samples_offset = 10
    trak = utils.make_text_trak(creation_time, modification_time, b"bzna_fnames\0",
                                samples_sizes, samples_offset)

    # MOOV.TRAK.MDIA.HDLR
    hdlr = trak.boxes[-1].boxes[1]
    hdlr.refresh_box_size()

    assert hdlr.header.type == b"hdlr"
    assert hdlr.header.box_size == 44
    assert hdlr.handler_type == b"text"
    # TODO: validate the use of the name
    assert hdlr.name == b"bzna_fnames\0"

    assert bytes(hdlr) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:32, bytes:4, bits:32, bits:32, bits:32, "
                "bytes:12",
                44, b"hdlr", 0, b"\x00\x00\x00",
                0, b"text", b"\x00" * 4, b"\x00" * 4, b"\x00" * 4,
                b"bzna_fnames\0")

    # MOOV.TRAK.MDIA.MINF.NMHD
    nmhd = trak.boxes[-1].boxes[-1].boxes[0]
    nmhd.refresh_box_size()

    assert nmhd.header.type == b"nmhd"
    assert nmhd.header.box_size == 12
    assert nmhd.header.version == 0
    assert nmhd.header.flags == b"\x00\x00\x00"

    assert bytes(nmhd) == pack("uintbe:32, bytes:4, uintbe:8, bits:24",
                               12, b"nmhd", 0, b"\x00\x00\x00")

    # MOOV.TRAK.MDIA.MINF.STBL.STSD
    stsd = trak.boxes[-1].boxes[-1].boxes[-1].boxes[0]

    assert stsd.header.type == b"stsd"
    assert len(stsd.boxes) == 1

    # MOOV.TRAK.MDIA.MINF.STBL.STSD.STXT
    stxt = stsd.boxes[0]
    stxt.refresh_box_size()

    assert stxt.header.type == b"stxt"
    assert stxt.header.box_size == 28
    assert stxt.data_reference_index == 1
    assert stxt.content_encoding == b'\0'
    assert stxt.mime_format == b'text/plain\0'
    assert len(stxt.boxes) == 0
예제 #2
0
def test_make_trak_co64_explicit_offset():
    creation_time = utils.to_mp4_time(datetime(2019, 9, 15, 0, 0, 0))
    modification_time = utils.to_mp4_time(datetime(2019, 9, 16, 0, 0, 0))

    samples_sizes = [198297, 127477, 192476]
    samples_offsets = [utils.MAX_UINT_32,
                       utils.MAX_UINT_32 + 300000,
                       utils.MAX_UINT_32 + 2 * 300000]
    trak = utils.make_trak(creation_time, modification_time,
                           samples_sizes, samples_offsets)

    # MOOV.TRAK.MDIA
    mdia = trak.boxes[1]

    # MOOV.TRAK.MDIA.MINF
    minf = mdia.boxes[2]

    # MOOV.TRAK.MDIA.MINF.STBL
    stbl = minf.boxes[2]

    # MOOV.TRAK.MDIA.MINF.STBL.CO64
    stco = stbl.boxes[4]
    stco.refresh_box_size()

    assert stco.header.type == b"co64"
    assert stco.header.box_size == 40
    assert stco.header.version == 0
    assert stco.header.flags == b"\x00\x00\x00"
    assert stco.entry_count == 3
    assert len(stco.entries) == 3
    assert stco.entries[0].chunk_offset == utils.MAX_UINT_32
    assert stco.entries[1].chunk_offset == utils.MAX_UINT_32 + 300000
    assert stco.entries[2].chunk_offset == utils.MAX_UINT_32 + 2 * 300000

    assert bytes(stco) == pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                               "uintbe:32, "
                               "uintbe:64, uintbe:64, uintbe:64",
                               40, b"co64", 0, b"\x00\x00\x00",
                               3,
                               utils.MAX_UINT_32,
                               utils.MAX_UINT_32 + 300000,
                               utils.MAX_UINT_32 + 2 * 300000)
예제 #3
0
def test_make_mvhd():
    creation_time = utils.to_mp4_time(datetime(2019, 9, 15, 0, 0, 0))
    modification_time = utils.to_mp4_time(datetime(2019, 9, 16, 0, 0, 0))

    mvhd = utils.make_mvhd(creation_time, modification_time, 3)
    mvhd.refresh_box_size()

    assert mvhd.header.type == b"mvhd"
    assert mvhd.header.box_size == 120
    assert mvhd.header.version == 1
    assert mvhd.header.flags == b"\x00\x00\x00"

    assert mvhd.creation_time == creation_time
    assert mvhd.modification_time == modification_time
    assert mvhd.timescale == 20
    assert mvhd.duration == 60

    assert mvhd.rate == [1, 0]
    assert mvhd.volume == [0, 0]

    assert mvhd.matrix == [65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824]
    assert mvhd.pre_defined == [b"\x00" * 4] * 6

    assert mvhd.next_track_id == 1

    assert bytes(mvhd) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:64, uintbe:64, uintbe:32, uintbe:64, "
                "uintbe:16, uintbe:16, uintbe:8, uintbe:8, "
                "bits:16, bits:32, bits:32, "
                "uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, "
                "bits:32, bits:32, bits:32, bits:32, bits:32, bits:32, "
                "uintbe:32",
                120, b"mvhd", 1, b"\x00\x00\x00",
                creation_time, modification_time, 20, 60,
                1, 0, 0, 0,
                b"\x00" * 2, b"\x00" * 4, b"\x00" * 4,
                65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824,
                b"\x00" * 4, b"\x00" * 4, b"\x00" * 4, b"\x00" * 4, b"\x00" * 4, b"\x00" * 4,
                1)
예제 #4
0
def test_to_mp4_date():
    assert utils.to_mp4_time(datetime(2017, 12, 15, 16, 24, 10)) == 3596199850
    assert utils.to_mp4_time(datetime(1904, 1, 1, 0, 0)) == 0
예제 #5
0
def test_make_trak():
    creation_time = utils.to_mp4_time(datetime(2019, 9, 15, 0, 0, 0))
    modification_time = utils.to_mp4_time(datetime(2019, 9, 16, 0, 0, 0))

    samples_sizes = [198297, 127477, 192476]
    samples_offset = 10
    trak = utils.make_trak(creation_time, modification_time,
                           samples_sizes, samples_offset)

    assert trak.header.type == b"trak"
    assert len(trak.boxes) == 2

    # MOOV.TRAK.TKHD
    tkhd = trak.boxes[0]

    assert tkhd.header.type == b"tkhd"
    assert tkhd.header.version == 1
    assert tkhd.header.flags == b"\x00\x00\x00"

    assert tkhd.creation_time == creation_time
    assert tkhd.modification_time == modification_time
    assert tkhd.track_id == -1
    assert tkhd.duration == 60

    assert tkhd.layer == 0
    assert tkhd.alternate_group == 0
    assert tkhd.volume == [0, 0]

    assert tkhd.matrix == [65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824]

    assert tkhd.width == -1
    assert tkhd.height == -1

    assert tkhd.is_audio is False

    # MOOV.TRAK.MDIA
    mdia = trak.boxes[1]

    assert mdia.header.type == b"mdia"
    assert len(mdia.boxes) == 3

    # MOOV.TRAK.MDIA.MDHD
    mdhd = mdia.boxes[0]
    mdhd.refresh_box_size()

    assert mdhd.header.type == b"mdhd"
    assert mdhd.header.box_size == 44
    assert mdhd.header.version == 1
    assert mdhd.header.flags == b"\x00\x00\x00"

    assert mdhd.creation_time == creation_time
    assert mdhd.modification_time == modification_time
    assert mdhd.timescale == 20
    assert mdhd.duration == 60

    assert mdhd.language == [21, 14, 4]
    assert mdhd.pre_defined == 0

    assert bytes(mdhd) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:64, uintbe:64, uintbe:32, uintbe:64, "
                "bits:1, uint:5, uint:5, uint:5, "
                "bits:16",
                44, b"mdhd", 1, b"\x00\x00\x00",
                creation_time, modification_time, 20, 60,
                0x1, 21, 14, 4,
                b"\x00" * 2)

    # MOOV.TRAK.MDIA.HDLR
    hdlr = mdia.boxes[1]
    hdlr.refresh_box_size()

    assert hdlr.header.type == b"hdlr"
    assert hdlr.header.box_size == 33
    assert hdlr.header.version == 0
    assert hdlr.header.flags == b"\x00\x00\x00"
    assert hdlr.pre_defined == 0
    assert hdlr.handler_type == b"____"
    # TODO: validate the use of the name
    assert hdlr.name == b"\0"

    assert bytes(hdlr) == pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                               "uintbe:32, bytes:4, "
                               "bits:32, bits:32, bits:32, "
                               "bytes:1",
                               33, b"hdlr", 0, b"\x00\x00\x00",
                               0, b"____",
                               b"\x00" * 4, b"\x00" * 4, b"\x00" * 4,
                               b"\0")

    # MOOV.TRAK.MDIA.MINF
    minf = mdia.boxes[2]

    assert minf.header.type == b"minf"
    assert len(minf.boxes) == 3

    # MOOV.TRAK.MDIA.MINF._MHD (placeholder)
    _mhd = minf.boxes[0]
    _mhd.refresh_box_size()

    assert _mhd.header.type == b"_mhd"
    assert _mhd.header.box_size == 8

    assert bytes(_mhd) == pack("uintbe:32, bytes:4", 8, b"_mhd")

    # MOOV.TRAK.MDIA.MINF.DINF
    dinf = minf.boxes[1]

    assert dinf.header.type == b"dinf"
    assert len(dinf.boxes) == 1

    # MOOV.TRAK.MDIA.MINF.DINF.DREF
    dref = dinf.boxes[0]

    assert dref.header.type == b"dref"
    assert dref.header.version == 0
    assert dref.header.flags == b"\x00\x00\x00"
    assert dref.entry_count == 1
    assert len(dref.boxes) == 1

    # MOOV.TRAK.MDIA.MINF.DINF.DREF.URL_
    url_ = dref.boxes[0]
    url_.refresh_box_size()

    assert url_.header.type == b"url "
    assert url_.header.box_size == 12
    assert url_.header.version == 0
    assert url_.header.flags == b"\x00\x00\x01"
    assert url_.location is None

    assert bytes(url_) == pack("uintbe:32, bytes:4, uintbe:8, bits:24",
                               12, b"url ", 0, b"\x00\x00\x01")

    # MOOV.TRAK.MDIA.MINF.STBL
    stbl = minf.boxes[2]

    assert stbl.header.type == b"stbl"
    assert len(stbl.boxes) == 5

    # MOOV.TRAK.MDIA.MINF.STBL.STSD
    stsd = stbl.boxes[0]
    stsd.refresh_box_size()

    assert stsd.header.type == b"stsd"
    assert stsd.header.box_size == 16
    assert stsd.header.version == 0
    assert stsd.header.flags == b"\x00\x00\x00"
    assert stsd.entry_count == 0

    assert bytes(stsd) == pack("uintbe:32, bytes:4, uintbe:8, bits:24, uintbe:32",
                               16, b"stsd", 0, b"\x00\x00\x00", 0)

    # MOOV.TRAK.MDIA.MINF.STBL.STTS
    stts = stbl.boxes[1]
    stts.refresh_box_size()

    assert stts.header.type == b"stts"
    assert stts.header.box_size == 24
    assert stts.header.version == 0
    assert stts.header.flags == b"\x00\x00\x00"
    assert stts.entry_count == 1
    assert len(stts.entries) == 1
    assert stts.entries[0].sample_count == 3
    assert stts.entries[0].sample_delta == 20

    assert bytes(stts) == pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                               "uintbe:32, uintbe:32, uintbe:32",
                               24, b"stts", 0, b"\x00\x00\x00",
                               1, 3, 20)

    # MOOV.TRAK.MDIA.MINF.STBL.STSZ
    stsz = stbl.boxes[2]
    stsz.refresh_box_size()

    assert stsz.header.type == b"stsz"
    assert stsz.header.box_size == 32
    assert stsz.header.version == 0
    assert stsz.header.flags == b"\x00\x00\x00"
    assert stsz.sample_size == 0
    assert stsz.sample_count == 3
    assert len(stsz.samples) == 3
    assert stsz.samples[0].entry_size == samples_sizes[0]
    assert stsz.samples[1].entry_size == samples_sizes[1]
    assert stsz.samples[2].entry_size == samples_sizes[2]

    assert bytes(stsz) == pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                               "uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32",
                               32, b"stsz", 0, b"\x00\x00\x00",
                               0, 3,
                               samples_sizes[0], samples_sizes[1], samples_sizes[2])

    # MOOV.TRAK.MDIA.MINF.STBL.STSC
    stsc = stbl.boxes[3]
    stsc.refresh_box_size()

    assert stsc.header.type == b"stsc"
    assert stsc.header.box_size == 28
    assert stsc.header.version == 0
    assert stsc.header.flags == b"\x00\x00\x00"
    assert stsc.entry_count == 1
    assert len(stsc.entries) == 1
    assert stsc.entries[0].first_chunk == 1
    assert stsc.entries[0].samples_per_chunk == 1
    assert stsc.entries[0].sample_description_index == 1

    assert bytes(stsc) == pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                               "uintbe:32, "
                               "uintbe:32, uintbe:32, uintbe:32",
                               28, b"stsc", 0, b"\x00\x00\x00",
                               1,
                               1, 1, 1)

    # MOOV.TRAK.MDIA.MINF.STBL.STCO
    stco = stbl.boxes[4]
    stco.refresh_box_size()

    assert stco.header.type == b"stco"
    assert stco.header.box_size == 28
    assert stco.header.version == 0
    assert stco.header.flags == b"\x00\x00\x00"
    assert stco.entry_count == 3
    assert len(stco.entries) == 3
    assert stco.entries[0].chunk_offset == samples_offset
    assert stco.entries[1].chunk_offset == samples_offset + sum(samples_sizes[0:1])
    assert stco.entries[2].chunk_offset == samples_offset + sum(samples_sizes[0:2])

    assert bytes(stco) == pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                               "uintbe:32, "
                               "uintbe:32, uintbe:32, uintbe:32",
                               28, b"stco", 0, b"\x00\x00\x00",
                               3,
                               samples_offset,
                               samples_offset + sum(samples_sizes[0:1]),
                               samples_offset + sum(samples_sizes[0:2]))
예제 #6
0
def test_make_vide_trak():
    creation_time = utils.to_mp4_time(datetime(2019, 9, 15, 0, 0, 0))
    modification_time = utils.to_mp4_time(datetime(2019, 9, 16, 0, 0, 0))

    samples_sizes = [198297, 127477, 192476]
    samples_offset = 10
    trak = utils.make_vide_trak(creation_time, modification_time, b"VideoHandler\0",
                                samples_sizes, samples_offset)

    # MOOV.TRAK.MDIA.HDLR
    hdlr = trak.boxes[-1].boxes[1]
    hdlr.refresh_box_size()

    assert hdlr.header.type == b"hdlr"
    assert hdlr.header.box_size == 45
    assert hdlr.handler_type == b"vide"
    # TODO: validate the use of the name
    assert hdlr.name == b"VideoHandler\0"

    assert bytes(hdlr) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:32, bytes:4, bits:32, bits:32, bits:32, "
                "bytes:13",
                45, b"hdlr", 0, b"\x00\x00\x00",
                0, b"vide", b"\x00" * 4, b"\x00" * 4, b"\x00" * 4,
                b"VideoHandler\0")

    # MOOV.TRAK.MDIA.MINF.VMHD
    vmhd = trak.boxes[-1].boxes[-1].boxes[0]
    vmhd.refresh_box_size()

    assert vmhd.header.type == b"vmhd"
    assert vmhd.header.box_size == 20
    assert vmhd.header.version == 0
    assert vmhd.header.flags == b"\x00\x00\x01"
    assert vmhd.graphicsmode == 0
    assert vmhd.opcolor == [0, 0, 0]

    assert bytes(vmhd) == pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                               "uintbe:16, uintbe:16, uintbe:16, uintbe:16",
                               20, b"vmhd", 0, b"\x00\x00\x01",
                               0, 0, 0, 0)

    # MOOV.TRAK.MDIA.MINF.STBL.STSD
    stsd = trak.boxes[-1].boxes[-1].boxes[-1].boxes[0]

    assert stsd.header.type == b"stsd"
    assert len(stsd.boxes) == 1

    # MOOV.TRAK.MDIA.MINF.STBL.STSD.AVC1
    avc1 = stsd.boxes[0]

    assert avc1.header.type == b"avc1"
    assert avc1.data_reference_index == 1
    assert avc1.width == -1
    assert avc1.height == -1
    assert avc1.horizresolution == [72, 0]
    assert avc1.vertresolution == [72, 0]
    assert avc1.frame_count == 1
    assert avc1.compressorname == b'\0' * 32
    assert avc1.depth == 24
    assert len(avc1.boxes) == 2

    # MOOV.TRAK.MDIA.MINF.STBL.STSD.AVC1.AVCC
    avcC = avc1.boxes[0]
    avcC.refresh_box_size()

    assert avcC.header.type == b"avcC"
    assert avcC.header.box_size == 53
    assert avcC.payload == b'\x01d\x10\x16\xff\xe1\x00\x1bgd\x10\x16\xac\xb8' \
                           b'\x10\x02\r\xff\x80K\x00N\xb6\xa5\x00\x00\x03\x00' \
                           b'\x01\x00\x00\x03\x00\x02\x04\x01\x00\x07h\xee\x01' \
                           b'\x9cL\x84\xc0'

    # MOOV.TRAK.MDIA.MINF.STBL.STSD.AVC1.PASP
    pasp = avc1.boxes[1]
    pasp.refresh_box_size()

    assert pasp.header.type == b"pasp"
    assert pasp.header.box_size == 16
    assert pasp.h_spacing == 1
    assert pasp.v_spacing == 1
예제 #7
0
def test_mp4_small_vid():
    creation_time = to_mp4_time(datetime(2019, 9, 15, 0, 0, 0))
    modification_time = to_mp4_time(datetime(2019, 9, 16, 0, 0, 0))

    # FTYP
    ftyp = bx_def.FTYP(BoxHeader())
    ftyp.header.type = b"ftyp"
    ftyp.major_brand = 1836069937                # b"mp41"
    ftyp.minor_version = 0
    ftyp.compatible_brands = [1836069937]        # b'mp41'

    ftyp.refresh_box_size()

    assert ftyp.header.type == b"ftyp"
    assert ftyp.header.box_size == 20
    assert ftyp.major_brand == 1836069937           # b"mp41"
    assert ftyp.minor_version == 0
    assert ftyp.compatible_brands == [1836069937]   # b'mp41'
    assert bytes(ftyp) == pack("uintbe:32, bytes:4, "
                               "bytes:4, uintbe:32, bytes:4",
                               20, b"ftyp",
                               b"mp41", 0, b'mp41')

    # MDAT
    mdat = bx_def.MDAT(BoxHeader())
    mdat.header.type = b"mdat"

    data = []

    with open("tests/data/small_vid_mdat_im0", "rb") as f:
        data.append(f.read())
    with open("tests/data/small_vid_mdat_im1", "rb") as f:
        data.append(f.read())
    with open("tests/data/small_vid_mdat_im2", "rb") as f:
        data.append(f.read())

    mdat.data = b''.join(data)

    mdat.refresh_box_size()

    assert mdat.header.type == b"mdat"
    assert mdat.header.box_size == 518258

    # MOOV
    moov = bx_def.MOOV(BoxHeader())
    moov.header.type = b"moov"

    # MOOV.MVHD
    mvhd = make_mvhd(creation_time, modification_time, 3)
    # == total number of tracks
    mvhd.next_track_id = 2

    assert mvhd.next_track_id == 2

    moov.append(mvhd)

    # MOOV.TRAK
    offset = ftyp.header.box_size + mdat.header.header_size
    sizes = [198297, 127477, 192476]
    trak = make_vide_trak(creation_time, modification_time, b"VideoHandler\0",
                          sizes, offset)

    # MOOV.TRAK.TKHD
    tkhd = trak.boxes[0]

    # "\x00\x00\x01" trak is enabled
    # "\x00\x00\x02" trak is used in the presentation
    # "\x00\x00\x04" trak is used in the preview
    # "\x00\x00\x08" trak size in not in pixel but in aspect ratio
    tkhd.header.flags = b"\x00\x00\x03"

    tkhd.track_id = 1

    # TODO: make sure that this is the canvas size
    tkhd.width = [512, 0]
    tkhd.height = [512, 0]

    tkhd.refresh_box_size()

    assert tkhd.header.type == b"tkhd"
    assert tkhd.header.box_size == 104
    assert tkhd.header.flags == b"\x00\x00\x03"

    assert tkhd.track_id == 1

    assert tkhd.width == 512
    assert tkhd.height == 512

    assert bytes(tkhd) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:64, uintbe:64, uintbe:32, "
                "bits:32, "
                "uintbe:64, "
                "bits:32, bits:32, "
                "uintbe:16, uintbe:16, uintbe:8, uintbe:8, "
                "bits:16, "
                "uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, "
                "uintbe:16, uintbe:16, uintbe:16, uintbe:16",
                104, b"tkhd", 1, b"\x00\x00\x03",
                creation_time, modification_time, 1,
                b"\x00" * 4,
                60,
                b"\x00" * 4, b"\x00" * 4,
                0, 0, 0, 0,
                b"\x00" * 2,
                65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824,
                512, 0, 512, 0)

    # MOOV.TRAK.MDIA.MDHD
    mdhd = trak.boxes[-1].boxes[0]
    mdhd.timescale = 20
    mdhd.duration = 60

    mdhd.refresh_box_size()

    assert mdhd.header.type == b"mdhd"
    assert mdhd.header.box_size == 44
    assert mdhd.timescale == 20
    assert mdhd.duration == 60

    assert bytes(mdhd) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:64, uintbe:64, uintbe:32, uintbe:64, "
                "bits:1, uint:5, uint:5, uint:5, "
                "bits:16",
                44, b"mdhd", 1, b"\x00\x00\x00",
                creation_time, modification_time, 20, 60,
                0x1, 21, 14, 4,
                b"\x00" * 2)

    # MOOV.TRAK.MDIA.MINF.STBL.STSD
    stsd = trak.boxes[-1].boxes[-1].boxes[-1].boxes[0]

    assert stsd.header.type == b"stsd"
    assert len(stsd.boxes) == 1

    # MOOV.TRAK.MDIA.MINF.STBL.STSD.AVC1
    avc1 = stsd.boxes[0]
    avc1.width = 512
    avc1.height = 512

    assert avc1.header.type == b"avc1"
    assert avc1.width == 512
    assert avc1.height == 512

    moov.append(trak)

    moov.refresh_box_size()

    assert mvhd.next_track_id == len(moov.boxes)

    assert moov.header.type == b"moov"
    assert len(moov.boxes) == 2

    mp4_bytes = b''.join([bytes(ftyp), bytes(mdat), bytes(moov)])

    with open("tests/data/small_vid.out.mp4", "rb") as f:
        assert mp4_bytes == f.read()
예제 #8
0
def test_mp4_dataset():
    creation_time = to_mp4_time(datetime(2019, 9, 15, 0, 0, 0))
    modification_time = to_mp4_time(datetime(2019, 9, 16, 0, 0, 0))

    # FTYP
    ftyp = bx_def.FTYP(BoxHeader())
    ftyp.header.type = b"ftyp"
    ftyp.major_brand = 1769172845           # b"isom"
    ftyp.minor_version = 0
    ftyp.compatible_brands = [1652190817,   # b"bzna"
                              1769172845]   # b"isom"

    ftyp.refresh_box_size()

    assert ftyp.header.type == b"ftyp"
    assert ftyp.header.box_size == 24
    assert ftyp.major_brand == 1769172845           # b"isom"
    assert ftyp.minor_version == 0
    assert ftyp.compatible_brands == [1652190817,   # b"bzna"
                                      1769172845]   # b"isom"
    assert bytes(ftyp) == pack("uintbe:32, bytes:4, bytes:4, uintbe:32, "
                               "bytes:8",
                               24, b"ftyp", b"isom", 0,
                               b"bznaisom")

    # MDAT
    mdat = bx_def.MDAT(BoxHeader())
    mdat.header.type = b"mdat"

    data = []

    with open("tests/data/small_vid_mdat_im0", "rb") as f:
        data.append(f.read())
    with open("tests/data/small_vid_mdat_im1", "rb") as f:
        data.append(f.read())
    with open("tests/data/small_vid_mdat_im2", "rb") as f:
        data.append(f.read())

    data.append(b"/path/image_1_name.JPEG")
    data.append(b"/path/image_2_name.JPEG")
    data.append(b"/path/image_3_name.JPEG")

    data.append((0).to_bytes(8, byteorder="little"))
    data.append((1).to_bytes(8, byteorder="little"))
    data.append((0).to_bytes(8, byteorder="little"))

    mdat.data = b''.join(data)

    mdat.refresh_box_size()

    assert mdat.header.type == b"mdat"
    assert mdat.header.box_size == 8 + sum(len(entry) for entry in data)

    # MOOV
    moov = bx_def.MOOV(BoxHeader())
    moov.header.type = b"moov"

    # MOOV.MVHD
    mvhd = make_mvhd(creation_time, modification_time, 3)
    # == total number of tracks
    mvhd.next_track_id = 5

    assert mvhd.next_track_id == 5

    moov.append(mvhd)

    # MOOV.TRAK
    offset = ftyp.header.box_size + mdat.header.header_size
    sizes = [198297, 127477, 192476]
    trak = make_vide_trak(creation_time, modification_time, b"VideoHandler\0",
                          sizes, offset)

    # MOOV.TRAK.TKHD
    tkhd = trak.boxes[0]

    # "\x00\x00\x01" trak is enabled
    # "\x00\x00\x02" trak is used in the presentation
    # "\x00\x00\x04" trak is used in the preview
    # "\x00\x00\x08" trak size in not in pixel but in aspect ratio
    tkhd.header.flags = b"\x00\x00\x03"

    tkhd.track_id = 1

    # TODO: make sure that this is the canvas size
    tkhd.width = [512, 0]
    tkhd.height = [512, 0]

    tkhd.refresh_box_size()

    assert tkhd.header.type == b"tkhd"
    assert tkhd.header.box_size == 104
    assert tkhd.header.flags == b"\x00\x00\x03"

    assert tkhd.track_id == 1

    assert tkhd.width == 512
    assert tkhd.height == 512

    assert bytes(tkhd) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:64, uintbe:64, uintbe:32, "
                "bits:32, "
                "uintbe:64, "
                "bits:32, bits:32, "
                "uintbe:16, uintbe:16, uintbe:8, uintbe:8, "
                "bits:16, "
                "uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, "
                "uintbe:16, uintbe:16, uintbe:16, uintbe:16",
                104, b"tkhd", 1, b"\x00\x00\x03",
                creation_time, modification_time, 1,
                b"\x00" * 4,
                60,
                b"\x00" * 4, b"\x00" * 4,
                0, 0, 0, 0,
                b"\x00" * 2,
                65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824,
                512, 0, 512, 0)

    # MOOV.TRAK.MDIA.MINF.STBL.STSD.AVC1
    avc1 = trak.boxes[-1].boxes[-1].boxes[-1].boxes[0].boxes[0]
    avc1.width = 512
    avc1.height = 512

    assert avc1.header.type == b"avc1"
    assert avc1.width == 512
    assert avc1.height == 512

    moov.append(trak)

    # MOOV.TRAK
    trak = make_meta_trak(creation_time, modification_time, b"bzna_inputs\0",
                          sizes, offset)

    # MOOV.TRAK.TKHD
    tkhd = trak.boxes[0]

    # "\x00\x00\x01" trak is enabled
    # "\x00\x00\x02" trak is used in the presentation
    # "\x00\x00\x04" trak is used in the preview
    # "\x00\x00\x08" trak size in not in pixel but in aspect ratio
    tkhd.header.flags = b"\x00\x00\x00"

    tkhd.track_id = 2

    # TODO: make sure that this is the canvas size
    tkhd.width = [0, 0]
    tkhd.height = [0, 0]

    tkhd.refresh_box_size()

    assert tkhd.header.type == b"tkhd"
    assert tkhd.header.box_size == 104
    assert tkhd.header.flags == b"\x00\x00\x00"

    assert tkhd.track_id == 2

    assert tkhd.width == 0
    assert tkhd.height == 0

    assert bytes(tkhd) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:64, uintbe:64, uintbe:32, "
                "bits:32, "
                "uintbe:64, "
                "bits:32, bits:32, "
                "uintbe:16, uintbe:16, uintbe:8, uintbe:8, "
                "bits:16, "
                "uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, "
                "uintbe:16, uintbe:16, uintbe:16, uintbe:16",
                104, b"tkhd", 1, b"\x00\x00\x00",
                creation_time, modification_time, 2,
                b"\x00" * 4,
                60,
                b"\x00" * 4, b"\x00" * 4,
                0, 0, 0, 0,
                b"\x00" * 2,
                65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824,
                0, 0, 0, 0)

    # MOOV.TRAK.MDIA.MDHD
    mdhd = trak.boxes[-1].boxes[0]
    mdhd.timescale = 20
    mdhd.duration = 60

    mdhd.refresh_box_size()

    assert mdhd.header.type == b"mdhd"
    assert mdhd.header.box_size == 44
    assert mdhd.timescale == 20
    assert mdhd.duration == 60

    assert bytes(mdhd) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:64, uintbe:64, uintbe:32, uintbe:64, "
                "bits:1, uint:5, uint:5, uint:5, "
                "bits:16",
                44, b"mdhd", 1, b"\x00\x00\x00",
                creation_time, modification_time, 20, 60,
                0x1, 21, 14, 4,
                b"\x00" * 2)

    # MOOV.TRAK.MDIA.MINF.STBL.STSD.METT
    mett = trak.boxes[-1].boxes[-1].boxes[-1].boxes[0].boxes[0]
    mett.mime_format = b'video/h264\0'
    mett.refresh_box_size()

    assert mett.header.type == b"mett"
    assert mett.header.box_size == 28
    assert mett.mime_format == b'video/h264\0'

    moov.append(trak)

    # MOOV.TRAK
    offset += sum(sizes)
    sizes = [23, 23, 23]
    trak = make_text_trak(creation_time, modification_time, b"bzna_fnames\0",
                          sizes, offset)

    # MOOV.TRAK.TKHD
    tkhd = trak.boxes[0]

    # "\x00\x00\x01" trak is enabled
    # "\x00\x00\x02" trak is used in the presentation
    # "\x00\x00\x04" trak is used in the preview
    # "\x00\x00\x08" trak size in not in pixel but in aspect ratio
    tkhd.header.flags = b"\x00\x00\x00"

    tkhd.track_id = 3

    # TODO: make sure that this is the canvas size
    tkhd.width = [0, 0]
    tkhd.height = [0, 0]

    tkhd.refresh_box_size()

    assert tkhd.header.type == b"tkhd"
    assert tkhd.header.box_size == 104
    assert tkhd.header.flags == b"\x00\x00\x00"

    assert tkhd.track_id == 3

    assert tkhd.width == 0
    assert tkhd.height == 0

    assert bytes(tkhd) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:64, uintbe:64, uintbe:32, "
                "bits:32, "
                "uintbe:64, "
                "bits:32, bits:32, "
                "uintbe:16, uintbe:16, uintbe:8, uintbe:8, "
                "bits:16, "
                "uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, "
                "uintbe:16, uintbe:16, uintbe:16, uintbe:16",
                104, b"tkhd", 1, b"\x00\x00\x00",
                creation_time, modification_time, 3,
                b"\x00" * 4,
                60,
                b"\x00" * 4, b"\x00" * 4,
                0, 0, 0, 0,
                b"\x00" * 2,
                65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824,
                0, 0, 0, 0)

    # MOOV.TRAK.MDIA.MDHD
    mdhd = trak.boxes[-1].boxes[0]
    mdhd.timescale = 20
    mdhd.duration = 60

    mdhd.refresh_box_size()

    assert mdhd.header.type == b"mdhd"
    assert mdhd.header.box_size == 44
    assert mdhd.timescale == 20
    assert mdhd.duration == 60

    assert bytes(mdhd) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:64, uintbe:64, uintbe:32, uintbe:64, "
                "bits:1, uint:5, uint:5, uint:5, "
                "bits:16",
                44, b"mdhd", 1, b"\x00\x00\x00",
                creation_time, modification_time, 20, 60,
                0x1, 21, 14, 4,
                b"\x00" * 2)

    moov.append(trak)

    # MOOV.TRAK
    offset += sum(sizes)
    sizes = [8, 8, 8]
    trak = make_text_trak(creation_time, modification_time, b"bzna_targets\0",
                          sizes, offset)

    # MOOV.TRAK.TKHD
    tkhd = trak.boxes[0]

    # "\x00\x00\x01" trak is enabled
    # "\x00\x00\x02" trak is used in the presentation
    # "\x00\x00\x04" trak is used in the preview
    # "\x00\x00\x08" trak size in not in pixel but in aspect ratio
    tkhd.header.flags = b"\x00\x00\x00"

    tkhd.track_id = 4

    # TODO: make sure that this is the canvas size
    tkhd.width = [0, 0]
    tkhd.height = [0, 0]

    tkhd.refresh_box_size()

    assert tkhd.header.type == b"tkhd"
    assert tkhd.header.box_size == 104
    assert tkhd.header.flags == b"\x00\x00\x00"

    assert tkhd.track_id == 4

    assert tkhd.width == 0
    assert tkhd.height == 0

    assert bytes(tkhd) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:64, uintbe:64, uintbe:32, "
                "bits:32, "
                "uintbe:64, "
                "bits:32, bits:32, "
                "uintbe:16, uintbe:16, uintbe:8, uintbe:8, "
                "bits:16, "
                "uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, uintbe:32, "
                "uintbe:16, uintbe:16, uintbe:16, uintbe:16",
                104, b"tkhd", 1, b"\x00\x00\x00",
                creation_time, modification_time, 4,
                b"\x00" * 4,
                60,
                b"\x00" * 4, b"\x00" * 4,
                0, 0, 0, 0,
                b"\x00" * 2,
                65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824,
                0, 0, 0, 0)

    # MOOV.TRAK.MDIA.MDHD
    mdhd = trak.boxes[-1].boxes[0]
    mdhd.timescale = 20
    mdhd.duration = 60

    mdhd.refresh_box_size()

    assert mdhd.header.type == b"mdhd"
    assert mdhd.header.box_size == 44
    assert mdhd.timescale == 20
    assert mdhd.duration == 60

    assert bytes(mdhd) == \
           pack("uintbe:32, bytes:4, uintbe:8, bits:24, "
                "uintbe:64, uintbe:64, uintbe:32, uintbe:64, "
                "bits:1, uint:5, uint:5, uint:5, "
                "bits:16",
                44, b"mdhd", 1, b"\x00\x00\x00",
                creation_time, modification_time, 20, 60,
                0x1, 21, 14, 4,
                b"\x00" * 2)

    moov.append(trak)

    moov.refresh_box_size()

    assert mvhd.next_track_id == len(moov.boxes)

    assert moov.header.type == b"moov"
    assert len(moov.boxes) == 5

    mp4_bytes = b''.join([bytes(ftyp), bytes(mdat), bytes(moov)])

    for box in moov.boxes:
        if isinstance(box, bx_def.TRAK):
            mdia = box.boxes[1]
        else:
            continue

        # trak.mdia.tkhd.name == b"bzna_inputs\0"
        if mdia.boxes[1].name == b"bzna_inputs\0":
            pass
        # trak.mdia.tkhd.name == b"bzna_names\0"
        elif mdia.boxes[1].name == b"bzna_fnames\0":
            # trak.mdia.minf.stbl.stsz
            stsz = mdia.boxes[2].boxes[2].boxes[2]
            # trak.mdia.minf.stbl.stco
            stco = mdia.boxes[2].boxes[2].boxes[4]
            for i, (sample, entry) in enumerate(zip(stsz.samples, stco.entries)):
                sample_end = entry.chunk_offset + sample.entry_size
                if i == 0:
                    assert mp4_bytes[entry.chunk_offset:sample_end] == \
                           b"/path/image_1_name.JPEG"
                elif i == 1:
                    assert mp4_bytes[entry.chunk_offset:sample_end] == \
                           b"/path/image_2_name.JPEG"
                elif i == 2:
                    assert mp4_bytes[entry.chunk_offset:sample_end] == \
                           b"/path/image_3_name.JPEG"
        # trak.mdia.tkhd.name == b"bzna_targets\0"
        elif mdia.boxes[1].name == b"bzna_targets\0":
            # trak.mdia.minf.stbl.stsz
            stsz = mdia.boxes[2].boxes[2].boxes[2]
            # trak.mdia.minf.stbl.stco
            stco = mdia.boxes[2].boxes[2].boxes[4]
            for i, (sample, entry) in enumerate(zip(stsz.samples, stco.entries)):
                sample_end = entry.chunk_offset + sample.entry_size
                if i == 0:
                    assert mp4_bytes[entry.chunk_offset:sample_end] == \
                           (0).to_bytes(8, byteorder="little")
                elif i == 1:
                    assert mp4_bytes[entry.chunk_offset:sample_end] == \
                           (1).to_bytes(8, byteorder="little")
                elif i == 2:
                    assert mp4_bytes[entry.chunk_offset:sample_end] == \
                           (0).to_bytes(8, byteorder="little")

    with open("tests/data/small_dataset.out.mp4", "rb") as f:
        assert mp4_bytes == f.read()