def test_get_sample_location(): trak = utils.make_meta_trak(0, 0, b"trak1\0", [12345, 67890], 23456) assert utils.get_sample_location(trak, 0) == (23456, 12345) assert utils.get_sample_location(trak, 1) == (35801, 67890) trak = utils.make_meta_trak(0, 0, b"trak1\0", [12345, 67890], [23456, 78901]) assert utils.get_sample_location(trak, 0) == (23456, 12345) assert utils.get_sample_location(trak, 1) == (78901, 67890)
def test_get_trak_sample_location(): boxes = [bx_def.UnknownBox(hd_def.BoxHeader()), utils.make_meta_trak(0, 0, b"trak1\0", [12345, 67890], 23456)] boxes[0].header.type = b"0001" assert utils.get_trak_sample_location(boxes, b"trak1\0", 0) == (23456, 12345) assert utils.get_trak_sample_location(boxes, b"trak1\0", 1) == (35801, 67890)
def test_find_traks(): boxes = [utils.make_meta_trak(0, 0, b"trak1\0", [], 0), utils.make_meta_trak(0, 0, b"trak2\0", [], 0), utils.make_meta_trak(0, 0, b"trak3\0", [], 0), bx_def.UnknownBox(hd_def.BoxHeader()), utils.make_meta_trak(0, 0, b"trak2\0", [], 0)] boxes[3].header.type = b"0001" assert utils.get_name(next(utils.find_traks(boxes, b"trak1\0"))) == b"trak1\0" assert utils.get_name(next(utils.find_traks(boxes, b"trak2\0"))) == b"trak2\0" assert utils.get_name(next(utils.find_traks(boxes, b"trak3\0"))) == b"trak3\0" assert [utils.get_name(trak) for trak in utils.find_traks(boxes, b"trak2\0")] == [b"trak2\0", b"trak2\0"] assert [utils.get_name(trak) for trak in utils.find_traks(boxes, [b"trak1\0", b"trak3\0"])] == [b"trak1\0", b"trak3\0"] assert next(utils.find_boxes(boxes, b"0004"), None) is None
def test_make_meta_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_meta_trak(creation_time, modification_time, b"bzna_inputs\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"meta" # TODO: validate the use of the name assert hdlr.name == b"bzna_inputs\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"meta", b"\x00" * 4, b"\x00" * 4, b"\x00" * 4, b"bzna_inputs\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.METT mett = stsd.boxes[0] mett.refresh_box_size() assert mett.header.type == b"mett" assert mett.header.box_size == 18 assert mett.data_reference_index == 1 assert mett.content_encoding == b'\0' assert mett.mime_format == b'\0' assert len(mett.boxes) == 0
def test_get_sample_table(): trak = utils.make_meta_trak(0, 0, b"trak1\0", [], 0) assert utils.get_sample_table(trak).header.type == b"stbl"
def test_get_shape(): trak = utils.make_meta_trak(0, 0, b"trak1\0", [], 0) assert utils.get_shape(trak) == (-1, -1)
def test_get_name(): trak = utils.make_meta_trak(0, 0, b"trak1\0", [], 0) assert utils.get_name(trak) == b"trak1\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()