def test_sbtt_box(): bs = pack("uintbe:32, bytes:4, " "uintbe:8, uintbe:8, uintbe:8, uintbe:8, uintbe:8, uintbe:8, " "uintbe:16, " "bytes:1, bytes:11", 28, b"sbtt", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 1, b'\0', b'text/plain\0') box_header = BoxHeader() stxt = bx_def.STXT(box_header) stxt.header.type = b"sbtt" stxt.data_reference_index = 1 stxt.content_encoding = b'\0' stxt.mime_format = b'text/plain\0' stxt.refresh_box_size() box = stxt assert box.header.type == b"sbtt" assert box.header.box_size == 28 assert box.data_reference_index == 1 assert box.content_encoding == b'\0' assert box.mime_format == b'text/plain\0' assert len(box.boxes) == 0 assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def test_hdlr_box(): bs = pack("uintbe:32, bytes:4, uintbe:8, bits:24, " "uintbe:32, bytes:4, bits:32, bits:32, bits:32, bytes:19", 51, b"hdlr", 0, b"\x00\x00\x00", 0, b"vide", b"\x00" * 4, b"\x00" * 4, b"\x00" * 4, b"Vireo Eyes v2.4.22\0") box_header = FullBoxHeader() hdlr = bx_def.HDLR(box_header) hdlr.header.type = b"hdlr" hdlr.header.version = 0 hdlr.header.flags = b"\x00\x00\x00" hdlr.pre_defined = 0 hdlr.handler_type = b"vide" hdlr.name = b"Vireo Eyes v2.4.22\0" hdlr.refresh_box_size() box = hdlr assert box.header.type == b"hdlr" assert box.header.box_size == 51 assert box.header.version == 0 assert box.header.flags == b"\x00\x00\x00" assert box.pre_defined == 0 assert box.handler_type == b"vide" assert box.name == b"Vireo Eyes v2.4.22\0" assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def test_vmhd_box(): bs = 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) box_header = FullBoxHeader() vmhd = bx_def.VMHD(box_header) vmhd.header.type = b"vmhd" vmhd.header.version = 0 vmhd.header.flags = b"\x00\x00\x01" vmhd.graphicsmode = 0 vmhd.opcolor = [0, 0, 0] vmhd.refresh_box_size() box = vmhd assert box.header.type == b"vmhd" assert box.header.box_size == 20 assert box.header.version == 0 assert box.header.flags == b"\x00\x00\x01" assert box.graphicsmode == 0 assert box.opcolor == [0, 0, 0] assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def test_mett_box(): bs = pack("uintbe:32, bytes:4, " "uintbe:8, uintbe:8, uintbe:8, uintbe:8, uintbe:8, uintbe:8, " "uintbe:16, " "bytes:1, bytes:11", 28, b"mett", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 1, b'\0', b'image/heif\0') box_header = BoxHeader() mett = bx_def.METT(box_header) mett.header.type = b"mett" mett.data_reference_index = 1 mett.content_encoding = b'\0' mett.mime_format = b'image/heif\0' mett.refresh_box_size() box = mett assert box.header.type == b"mett" assert box.header.box_size == 28 assert box.data_reference_index == 1 assert box.content_encoding == b'\0' assert box.mime_format == b'image/heif\0' assert len(box.boxes) == 0 assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def test_stts_box(): bs = pack("uintbe:32, bytes:4, uintbe:8, bits:24, " "uintbe:32, uintbe:32, uintbe:32", 24, b"stts", 0, b"\x00\x00\x00", 1, 1, 1) box_header = FullBoxHeader() stts = bx_def.STTS(box_header) stts.header.type = b"stts" stts.header.version = 0 stts.header.flags = b"\x00\x00\x00" entry = stts.append_and_return() entry.sample_count = 1 entry.sample_delta = 1 stts.refresh_box_size() box = stts assert box.header.type == b"stts" assert box.header.box_size == 24 assert box.header.version == 0 assert box.header.flags == b"\x00\x00\x00" assert box.entry_count == 1 assert len(box.entries) == 1 assert box.entries[0].sample_count == 1 assert box.entries[0].sample_delta == 1 parsed_box = next(Parser.parse(bs)) parsed_box.load(bs) assert bytes(parsed_box) == bs.bytes assert bytes(box) == bs.bytes
def test_ctts_box_v1(): bs = pack("uintbe:32, bytes:4, uintbe:8, bits:24, " "uintbe:32, uintbe:32, intbe:32", 24, b"ctts", 1, b"\x00\x00\x00", 1, 1, -1) box_header = FullBoxHeader() ctts = bx_def.CTTS(box_header) ctts.header.type = b"ctts" ctts.header.version = 1 ctts.header.flags = b"\x00\x00\x00" entry = ctts.append_and_return() entry.sample_count = 1 entry.sample_offset = (-1, "intbe:32") ctts.refresh_box_size() box = ctts assert box.header.type == b"ctts" assert box.header.box_size == 24 assert box.header.version == 1 assert box.header.flags == b"\x00\x00\x00" assert box.entry_count == 1 assert len(box.entries) == 1 assert box.entries[0].sample_count == 1 assert box.entries[0].sample_offset == -1 parsed_box = next(Parser.parse(bs)) parsed_box.load(bs) assert bytes(parsed_box) == bs.bytes assert bytes(box) == bs.bytes
def test_stsz_box(): bs = pack("uintbe:32, bytes:4, uintbe:8, bits:24, " "uintbe:32, uintbe:32, uintbe:32", 24, b"stsz", 0, b"\x00\x00\x00", 0, 1, 1) box_header = FullBoxHeader() stsz = bx_def.STSZ(box_header) stsz.header.type = b"stsz" stsz.header.version = 0 stsz.header.flags = b"\x00\x00\x00" stsz.sample_size = 0 sample = stsz.append_and_return() sample.entry_size = 1 stsz.refresh_box_size() box = stsz assert box.header.type == b"stsz" assert box.header.box_size == 24 assert box.header.version == 0 assert box.header.flags == b"\x00\x00\x00" assert box.sample_size == 0 assert box.sample_count == 1 assert len(box.samples) == 1 assert box.samples[0].entry_size == 1 parsed_box = next(Parser.parse(bs)) parsed_box.load(bs) assert bytes(parsed_box) == bs.bytes assert bytes(box) == bs.bytes
def test_mvhd_box_v1(): bs = 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", 3596199850, 3596199850, 48000, 6720608, 1, 0, 1, 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, 3) box_header = FullBoxHeader() mvhd = bx_def.MVHD(box_header) mvhd.header.type = b"mvhd" mvhd.header.version = 1 mvhd.header.flags = b"\x00\x00\x00" mvhd.creation_time = 3596199850 mvhd.modification_time = 3596199850 mvhd.timescale = 48000 mvhd.duration = 6720608 mvhd.rate = [1, 0] mvhd.volume = [1, 0] mvhd.matrix = [65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824] mvhd.pre_defined = [b"\x00" * 4] * 6 mvhd.next_track_id = 3 mvhd.refresh_box_size() box = mvhd assert box.header.type == b"mvhd" assert box.header.box_size == 120 assert box.header.version == 1 assert box.header.flags == b"\x00\x00\x00" assert box.creation_time == 3596199850 assert box.modification_time == 3596199850 assert box.timescale == 48000 assert box.duration == 6720608 assert box.rate == [1, 0] assert box.volume == [1, 0] assert box.matrix == [65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824] assert box.pre_defined == [b"\x00" * 4] * 6 assert box.next_track_id == 3 assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def test_ftyp_box_w_no_type(): bs = pack("uintbe:32, bytes:4, " "bytes:4, uintbe:32, bytes:8", 24, b"ftyp", b"bzna", 10, b"mp42mp41") box_header = BoxHeader() ftyp = bx_def.FTYP(box_header) ftyp.header.type = b"ftyp" ftyp.major_brand = (1652190817,) # b"bzna" ftyp.minor_version = (10,) ftyp.compatible_brands = ([1836069938, # b"mp42" 1836069937],) # b"mp41" ftyp.refresh_box_size() box = ftyp assert box.header.type == b"ftyp" assert box.header.box_size == 24 assert box.major_brand == 1652190817 # b"bzna" assert box.minor_version == 10 assert box.compatible_brands == [1836069938, # b"mp42" 1836069937] # b"mp41" assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def tune_video(filename, im_width, im_height): bstr = ConstBitStream(filename=filename) boxes = [box for box in Parser.parse(bstr)] # skip 'free' box boxes = boxes[:1] + boxes[2:] ftyp = boxes[0] mdat = boxes[1] moov = boxes[2] # pop 'udta' box moov.boxes.pop() trak = moov.boxes[-1] # remove edts mdia = trak.pop() trak.pop() trak.append(mdia) for box in boxes: box.load(bstr) box.refresh_box_size() ftyp.major_brand = 1769172845 # b"isom" ftyp.minor_version = 0 ftyp.compatible_brands = [1769172845] # b"isom" ftyp.refresh_box_size() # moov.trak.mdia.minf.stbl stbl = moov.boxes[-1].boxes[-1].boxes[-1].boxes[-1] # moov.trak.mdia.minf.stbl.stsd.hvc1 hvc1 = stbl.boxes[0].boxes[0] clap = bx_def.CLAP(BoxHeader()) clap.header.type = b"clap" clap.clean_aperture_width_n = im_width clap.clean_aperture_width_d = 1 clap.clean_aperture_height_n = im_height clap.clean_aperture_height_d = 1 clap.horiz_off_n = im_width - 512 clap.horiz_off_d = 2 clap.vert_off_n = im_height - 512 clap.vert_off_d = 2 # insert clap before pasp pasp = hvc1.pop() hvc1.append(clap) hvc1.append(pasp) stco = stbl.boxes[-1] stco.entries[ 0].chunk_offset = ftyp.header.box_size + mdat.header.header_size moov.refresh_box_size() return b''.join(bytes(box) for box in boxes)
def test_video_bytes(): bstr = ConstBitStream(filename="tests/data/small_vid.mp4") boxes = [box for box in Parser.parse(bstr)] assert b''.join([bytes(box) for box in boxes]) != bstr.bytes for box in boxes: box.load(bstr) assert b''.join([bytes(box) for box in boxes]) == bstr.bytes
def test_photo_heic_bytes(): bstr = ConstBitStream(filename="data/photo.heic") boxes = [box for box in Parser.parse(bstr)] assert b''.join([bytes(box) for box in boxes]) != bstr.bytes for box in boxes: box.load(bstr) assert b''.join([bytes(box) for box in boxes]) == bstr.bytes
def test_avc1_box(): bs = pack("uintbe:32, bytes:4, " "uintbe:8, uintbe:8, uintbe:8, uintbe:8, uintbe:8, uintbe:8, " "uintbe:16, " "uintbe:16, uintbe:16, uintbe:32, uintbe:32, uintbe:32, " "uintbe:16, uintbe:16, uintbe:16, uintbe:16, uintbe:16, uintbe:16, " "uintbe:32, " "uintbe:16, bytes:32, uintbe:16, " "intbe:16", 86, b"avc1", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 1, 0x0, 0x0, 0x0, 0x0, 0x0, 512, 512, 72, 0, 72, 0, 0x0, 1, b'\0' * 32, 24, -1) box_header = BoxHeader() avc1 = bx_def.AVC1(box_header) avc1.header.type = b"avc1" avc1.data_reference_index = 1 avc1.width = 512 avc1.height = 512 avc1.horizresolution = [72, 0] avc1.vertresolution = [72, 0] avc1.frame_count = 1 avc1.compressorname = b'\0' * 32 avc1.depth = 24 avc1.refresh_box_size() box = avc1 assert box.header.type == b"avc1" assert box.header.box_size == 86 assert box.data_reference_index == 1 assert box.width == 512 assert box.height == 512 assert box.horizresolution == [72, 0] assert box.vertresolution == [72, 0] assert box.frame_count == 1 assert box.compressorname == b'\0' * 32 assert box.depth == 24 assert len(box.boxes) == 0 assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def test_mdhd_box_v1(): bs = 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", 3596199850, 3596199850, 30000, 4200196, 0x1, 21, 14, 4, b"\x00" * 2) box_header = FullBoxHeader() mdhd = bx_def.MDHD(box_header) mdhd.header.type = b"mdhd" mdhd.header.version = 1 mdhd.header.flags = b"\x00\x00\x00" mdhd.creation_time = 3596199850 mdhd.modification_time = 3596199850 mdhd.timescale = 30000 mdhd.duration = 4200196 mdhd.language = [21, 14, 4] mdhd.pre_defined = 0 mdhd.refresh_box_size() box = mdhd assert box.header.type == b"mdhd" assert box.header.box_size == 44 assert box.header.version == 1 assert box.header.flags == b"\x00\x00\x00" assert box.creation_time == 3596199850 assert box.modification_time == 3596199850 assert box.timescale == 30000 assert box.duration == 4200196 assert box.language == [21, 14, 4] assert box.pre_defined == 0 assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def test_co64_box(): bs = 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, 0, 1, 2) box_header = FullBoxHeader() stco = bx_def.CO64(box_header) stco.header.type = b"co64" stco.header.version = 0 stco.header.flags = b"\x00\x00\x00" entry = stco.append_and_return() entry.chunk_offset = 0 entry = stco.append_and_return() entry.chunk_offset = 1 entry = stco.append_and_return() entry.chunk_offset = 2 stco.refresh_box_size() box = stco assert box.header.type == b"co64" assert box.header.box_size == 40 assert box.header.version == 0 assert box.header.flags == b"\x00\x00\x00" assert box.entry_count == 3 assert len(box.entries) == 3 assert box.entries[0].chunk_offset == 0 assert box.entries[1].chunk_offset == 1 assert box.entries[2].chunk_offset == 2 parsed_box = next(Parser.parse(bs)) parsed_box.load(bs) assert bytes(parsed_box) == bs.bytes assert bytes(box) == bs.bytes
def test_nmhd_box(): bs = pack("uintbe:32, bytes:4, uintbe:8, bits:24", 12, b"nmhd", 0, b"\x00\x00\x00") box_header = FullBoxHeader() nmhd = bx_def.NMHD(box_header) nmhd.header.type = b"nmhd" nmhd.header.version = 0 nmhd.header.flags = b"\x00\x00\x00" nmhd.refresh_box_size() box = nmhd assert box.header.type == b"nmhd" assert box.header.box_size == 12 assert box.header.version == 0 assert box.header.flags == b"\x00\x00\x00" assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def test_elst_box_v1(): bs = pack("uintbe:32, bytes:4, uintbe:8, bits:24, " "uintbe:32, uintbe:64, uintbe:64, uintbe:16, uintbe:16", 36, b"elst", 1, b"\x00\x00\x00", 1, 3000, 0, 1, 0) box_header = FullBoxHeader() elst = bx_def.ELST(box_header) elst.header.type = b"elst" elst.header.version = 1 elst.header.flags = b"\x00\x00\x00" entry = elst.append_and_return() entry.segment_duration = 3000 entry.media_time = 0 entry.media_rate_integer = 1 entry.media_rate_fraction = 0 elst.refresh_box_size() box = elst assert box.header.type == b"elst" assert box.header.box_size == 36 assert box.header.version == 1 assert box.header.flags == b"\x00\x00\x00" assert box.entry_count == 1 assert len(box.entries) == 1 assert box.entries[0].segment_duration == 3000 assert box.entries[0].media_time == 0 assert box.entries[0].media_rate_integer == 1 assert box.entries[0].media_rate_fraction == 0 parsed_box = next(Parser.parse(bs)) parsed_box.load(bs) assert bytes(parsed_box) == bs.bytes assert bytes(box) == bs.bytes
def test_pasp_box(): bs = pack("uintbe:32, bytes:4, uintbe:32, uintbe:32", 16, b"pasp", 150, 157) box_header = BoxHeader() pasp = bx_def.PASP(box_header) pasp.header.type = b"pasp" pasp.h_spacing = 150 pasp.v_spacing = 157 pasp.refresh_box_size() box = pasp assert box.header.type == b"pasp" assert box.header.box_size == 16 assert box.h_spacing == 150 assert box.v_spacing == 157 assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def test_clap_box(): bs = pack("uintbe:32, bytes:4, " "uintbe:32, uintbe:32, uintbe:32, uintbe:32, " "intbe:32, uintbe:32, intbe:32, uintbe:32", 40, b"clap", 500, 1, 333, 1, -12, 2, -179, 2) box_header = BoxHeader() clap = bx_def.CLAP(box_header) clap.header.type = b"clap" clap.clean_aperture_width_n = 500 clap.clean_aperture_width_d = 1 clap.clean_aperture_height_n = 333 clap.clean_aperture_height_d = 1 clap.horiz_off_n = -12 clap.horiz_off_d = 2 clap.vert_off_n = -179 clap.vert_off_d = 2 clap.refresh_box_size() box = clap assert box.header.type == b"clap" assert box.header.box_size == 40 assert box.clean_aperture_width_n == 500 assert box.clean_aperture_width_d == 1 assert box.clean_aperture_height_n == 333 assert box.clean_aperture_height_d == 1 assert box.horiz_off_n == -12 assert box.horiz_off_d == 2 assert box.vert_off_n == -179 assert box.vert_off_d == 2 assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def test_stsc_box(): bs = 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) box_header = FullBoxHeader() stsc = bx_def.STSC(box_header) stsc.header.type = b"stsc" stsc.header.version = 0 stsc.header.flags = b"\x00\x00\x00" entry = stsc.append_and_return() entry.first_chunk = 1 entry.samples_per_chunk = 1 entry.sample_description_index = 1 stsc.refresh_box_size() box = stsc assert box.header.type == b"stsc" assert box.header.box_size == 28 assert box.header.version == 0 assert box.header.flags == b"\x00\x00\x00" assert box.entry_count == 1 assert len(box.entries) == 1 assert box.entries[0].first_chunk == 1 assert box.entries[0].samples_per_chunk == 1 assert box.entries[0].sample_description_index == 1 parsed_box = next(Parser.parse(bs)) parsed_box.load(bs) assert bytes(parsed_box) == bs.bytes assert bytes(box) == bs.bytes
def test_url__box(): bs = pack("uintbe:32, bytes:4, uintbe:8, bits:24", 12, b"url ", 0, b"\x00\x00\x01") box_header = FullBoxHeader() url_ = bx_def.URL_(box_header) url_.header.type = b"url " url_.header.version = 0 url_.header.flags = b"\x00\x00\x01" url_.refresh_box_size() box = url_ assert box.header.type == b"url " assert box.header.box_size == 12 assert box.header.version == 0 assert box.header.flags == b"\x00\x00\x01" assert box.location is None assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
def test_photo_heic_parsing(): bstr = ConstBitStream(filename="data/photo.heic") meta = None for i, box in enumerate(Parser.parse(bstr)): if i == 0: # ftyp ftyp = box assert isinstance(ftyp, parse.FTYP) assert ftyp.header.start_pos == 0 assert ftyp.header.type == b"ftyp" assert ftyp.header.box_size == 24 assert ftyp.major_brand == 1751476579 # b"heic" assert ftyp.minor_version == 0 assert ftyp.compatible_brands == [1835623985, # b"mif1" 1751476579] # b"heic" assert ftyp.padding == b'' elif i == 1: # meta meta = box assert isinstance(meta, parse.META) assert meta.header.start_pos == 24 assert meta.header.type == b"meta" assert meta.header.box_size == 3955 assert meta.header.version == 0 assert meta.header.flags == b"\x00\x00\x00" assert len(meta.boxes) == 8 assert meta.padding == b'' elif i == 2: # mdat mdat = box assert isinstance(mdat, parse.MDAT) assert mdat.header.start_pos == 3979 assert mdat.header.type == b"mdat" assert mdat.header.box_size == 1350049 assert mdat.padding == b'' assert i < 3 # meta/hdlr hdlr = meta.boxes[0] assert isinstance(hdlr, parse.HDLR) assert hdlr.header.start_pos == 36 assert hdlr.header.type == b"hdlr" assert hdlr.header.box_size == 34 assert hdlr.header.version == 0 assert hdlr.header.flags == b"\x00\x00\x00" assert hdlr.pre_defined == 0 assert hdlr.handler_type == b"pict" assert hdlr.name == b'\0' assert hdlr.padding == b'\0' # meta/dinf dinf = meta.boxes[1] assert isinstance(dinf, parse.DINF) assert dinf.header.start_pos == 70 assert dinf.header.type == b"dinf" assert dinf.header.box_size == 36 assert len(dinf.boxes) == 1 assert dinf.padding == b'' # meta/dinf/dref dref = dinf.boxes[0] assert isinstance(dref, parse.DREF) assert dref.header.start_pos == 78 assert dref.header.type == b"dref" assert dref.header.box_size == 28 assert dref.header.version == 0 assert dref.header.flags == b"\x00\x00\x00" assert dref.entry_count == 1 assert len(dref.boxes) == 1 assert dref.padding == b'' # meta/dinf/dref/url_ url = dref.boxes[0] assert isinstance(url, parse.URL_) assert url.header.start_pos == 94 assert url.header.type == b"url " assert url.header.box_size == 12 assert url.location is None assert url.padding == b'' # meta/pitm pitm = meta.boxes[2] assert isinstance(pitm, parse.PITM) assert pitm.header.start_pos == 106 assert pitm.header.type == b"pitm" assert pitm.header.box_size == 14 assert pitm.padding == b'' # meta/iinf iinf = meta.boxes[3] assert isinstance(iinf, parse.IINF) assert iinf.header.start_pos == 120 assert iinf.header.type == b"iinf" assert iinf.header.box_size == 1085 assert iinf.entry_count == 51 assert len(iinf.boxes) == 51 assert iinf.padding == b'' for i, infe in enumerate(iinf.boxes): # meta/iinf/infe assert isinstance(infe, parse.INFE) if infe.item_id == 49: assert infe.header.start_pos == 134 + 48 * 21 assert infe.header.type == b"infe" assert infe.header.box_size == 21 assert infe.header.version == 2 assert infe.header.flags == b"\x00\x00\x00" assert infe.item_id == 49 assert infe.item_protection_index == 0 assert infe.item_type == 1735551332 # b"grid" assert infe.item_name == b'\0' assert infe.content_type is None assert infe.content_encoding is None assert infe.item_uri_type is None assert infe.extension_type is None assert infe.padding == b'' elif infe.item_id == 50: assert infe.header.start_pos == 134 + 49 * 21 assert infe.header.type == b"infe" assert infe.header.box_size == 21 assert infe.header.version == 2 assert infe.header.flags == b"\x00\x00\x00" assert infe.item_id == 50 assert infe.item_protection_index == 0 assert infe.item_type == 1752589105 # b"hvc1" assert infe.item_name == b'\0' assert infe.content_type is None assert infe.content_encoding is None assert infe.item_uri_type is None assert infe.extension_type is None assert infe.padding == b'' elif infe.item_id == 51: assert infe.header.start_pos == 134 + 50 * 21 assert infe.header.type == b"infe" assert infe.header.box_size == 21 assert infe.header.version == 2 assert infe.header.flags == b"\x00\x00\x01" assert infe.item_id == 51 assert infe.item_protection_index == 0 assert infe.item_type == 1165519206 # b"Exif" assert infe.item_name == b'\0' assert infe.content_type is None assert infe.content_encoding is None assert infe.item_uri_type is None assert infe.extension_type is None assert infe.padding == b'' else: assert infe.header.start_pos == 134 + i * 21 assert infe.header.type == b"infe" assert infe.header.box_size == 21 assert infe.header.version == 2 assert infe.header.flags == b"\x00\x00\x01" assert infe.item_id == i + 1 assert infe.item_protection_index == 0 assert infe.item_type == 1752589105 # b"hvc1" assert infe.item_name == b'\0' assert infe.content_type is None assert infe.content_encoding is None assert infe.item_uri_type is None assert infe.extension_type is None assert infe.padding == b'' # meta/iref iref = meta.boxes[4] assert isinstance(iref, parse.IREF) assert iref.header.start_pos == 1205 assert iref.header.type == b"iref" assert iref.header.box_size == 148 assert iref.header.version == 0 assert iref.header.flags == b"\x00\x00\x00" assert len(iref.boxes) == 3 assert iref.padding == b'' # meta/iref/dimg dimg = iref.boxes[0] assert dimg.header.start_pos == 1217 assert dimg.header.type == b"dimg" assert dimg.header.box_size == 108 assert dimg.from_item_id == 49 assert dimg.reference_count == 48 assert dimg.to_item_ids == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48] assert dimg.padding == b'' # meta/iref/thmb thmb = iref.boxes[1] assert thmb.header.start_pos == 1325 assert thmb.header.type == b"thmb" assert thmb.header.box_size == 14 assert thmb.from_item_id == 50 assert thmb.reference_count == 1 assert thmb.to_item_ids == [49] assert thmb.padding == b'' # meta/iref/cdsc cdsc = iref.boxes[2] assert cdsc.header.start_pos == 1339 assert cdsc.header.type == b"cdsc" assert cdsc.header.box_size == 14 assert cdsc.from_item_id == 51 assert cdsc.reference_count == 1 assert cdsc.to_item_ids == [49] assert cdsc.padding == b'' # meta/iprp iprp = meta.boxes[5] assert isinstance(iprp, parse.IPRP) assert iprp.header.start_pos == 1353 assert iprp.header.type == b"iprp" assert iprp.header.box_size == 1778 assert len(iprp.boxes) == 2 assert iprp.padding == b'' # meta/iprp/ipco ipco = iprp.boxes[0] assert isinstance(ipco, parse.IPCO) assert ipco.header.start_pos == 1361 assert ipco.header.type == b"ipco" assert ipco.header.box_size == 1452 assert len(ipco.boxes) == 10 assert ipco.padding == b'' # meta/iprp/ipco/colr colr = ipco.boxes[0] assert colr.header.start_pos == 1369 assert colr.header.type == b"colr" assert colr.header.box_size == 560 assert colr.padding == b'' # meta/iprp/ipco/hvcC hvcC = ipco.boxes[1] assert hvcC.header.start_pos == 1929 assert hvcC.header.type == b"hvcC" assert hvcC.header.box_size == 112 assert hvcC.padding == b'' # meta/iprp/ipco/ispe ispe = ipco.boxes[2] assert ispe.header.start_pos == 2041 assert ispe.header.type == b"ispe" assert ispe.header.box_size == 20 assert ispe.padding == b'' # meta/iprp/ipco/ispe ispe = ipco.boxes[3] assert ispe.header.start_pos == 2061 assert ispe.header.type == b"ispe" assert ispe.header.box_size == 20 assert ispe.padding == b'' # meta/iprp/ipco/irot irot = ipco.boxes[4] assert irot.header.start_pos == 2081 assert irot.header.type == b"irot" assert irot.header.box_size == 9 assert irot.padding == b'' # meta/iprp/ipco/pixi pixi = ipco.boxes[5] assert pixi.header.start_pos == 2090 assert pixi.header.type == b"pixi" assert pixi.header.box_size == 16 assert pixi.padding == b'' # meta/iprp/ipco/colr colr = ipco.boxes[6] assert colr.header.start_pos == 2106 assert colr.header.type == b"colr" assert colr.header.box_size == 560 assert colr.padding == b'' # meta/iprp/ipco/hvcC hvcC = ipco.boxes[7] assert hvcC.header.start_pos == 2666 assert hvcC.header.type == b"hvcC" assert hvcC.header.box_size == 111 assert hvcC.padding == b'' # meta/iprp/ipco/ispe ispe = ipco.boxes[8] assert ispe.header.start_pos == 2777 assert ispe.header.type == b"ispe" assert ispe.header.box_size == 20 assert ispe.padding == b'' # meta/iprp/ipco/pixi pixi = ipco.boxes[9] assert pixi.header.start_pos == 2797 assert pixi.header.type == b"pixi" assert pixi.header.box_size == 16 assert pixi.padding == b'' # meta/iprp/ipma ipma = iprp.boxes[1] assert isinstance(ipma, parse.IPMA) assert ipma.header.start_pos == 2813 assert ipma.header.type == b"ipma" assert ipma.header.box_size == 318 assert ipma.header.version == 0 assert ipma.header.flags == b"\x00\x00\x00" assert ipma.entry_count == 50 assert len(ipma.entries) == 50 assert ipma.padding == b'' entry = ipma.entries[0] assert entry.item_id == 1 assert entry.association_count == 3 assert len(entry.associations) == 3 association = entry.associations[0] assert association.essential == 1 assert association.property_index == 3 association = entry.associations[1] assert association.essential == 1 assert association.property_index == 1 association = entry.associations[2] assert association.essential == 1 assert association.property_index == 2 entry = ipma.entries[1] assert entry.item_id == 2 assert entry.association_count == 3 assert len(entry.associations) == 3 association = entry.associations[0] assert association.essential == 1 assert association.property_index == 3 association = entry.associations[1] assert association.essential == 1 assert association.property_index == 1 association = entry.associations[2] assert association.essential == 1 assert association.property_index == 2 entry = ipma.entries[48] assert entry.item_id == 49 assert entry.association_count == 3 assert len(entry.associations) == 3 association = entry.associations[0] assert association.essential == 0 assert association.property_index == 4 association = entry.associations[1] assert association.essential == 1 assert association.property_index == 5 association = entry.associations[2] assert association.essential == 0 assert association.property_index == 6 entry = ipma.entries[49] assert entry.item_id == 50 assert entry.association_count == 5 assert len(entry.associations) == 5 association = entry.associations[0] assert association.essential == 1 assert association.property_index == 7 association = entry.associations[1] assert association.essential == 1 assert association.property_index == 8 association = entry.associations[2] assert association.essential == 0 assert association.property_index == 9 association = entry.associations[3] assert association.essential == 1 assert association.property_index == 5 association = entry.associations[4] assert association.essential == 0 assert association.property_index == 10 # meta/idat idat = meta.boxes[6] assert isinstance(idat, parse.IDAT) assert idat.header.start_pos == 3131 assert idat.header.type == b"idat" assert idat.header.box_size == 16 assert idat.padding == b'' # meta/iloc iloc = meta.boxes[7] assert isinstance(iloc, parse.ILOC) assert iloc.header.start_pos == 3147 assert iloc.header.type == b"iloc" assert iloc.header.box_size == 832 assert iloc.header.version == 1 assert iloc.header.flags == b"\x00\x00\x00" assert iloc.offset_size == 4 assert iloc.length_size == 4 assert iloc.base_offset_size == 0 assert iloc.index_size == 0 assert iloc.item_count == 51 assert len(iloc.items) == 51 assert iloc.padding == b'' item = iloc.items[0] assert item.item_id == 1 assert item.construction_method == 0 assert item.data_reference_index == 0 assert item.base_offset is None assert item.extent_count == 1 assert len(item.extents) == 1 extent = item.extents[0] assert extent.extent_index is None assert extent.extent_offset == 14854 assert extent.extent_length == 33763 item = iloc.items[1] assert item.item_id == 2 assert item.construction_method == 0 assert item.data_reference_index == 0 assert item.base_offset is None assert item.extent_count == 1 assert len(item.extents) == 1 extent = item.extents[0] assert extent.extent_index is None assert extent.extent_offset == 48617 assert extent.extent_length == 35158 item = iloc.items[49] assert item.item_id == 50 assert item.construction_method == 0 assert item.data_reference_index == 0 assert item.base_offset is None assert item.extent_count == 1 assert len(item.extents) == 1 extent = item.extents[0] assert extent.extent_index is None assert extent.extent_offset == 3995 assert extent.extent_length == 8651 item = iloc.items[50] assert item.item_id == 51 assert item.construction_method == 0 assert item.data_reference_index == 0 assert item.base_offset is None assert item.extent_count == 1 assert len(item.extents) == 1 extent = item.extents[0] assert extent.extent_index is None assert extent.extent_offset == 12646 assert extent.extent_length == 2208
def test_tkhd_box_v1(): bs = 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\x07", 3596199850, 3596199850, 1, b"\x00" * 4, 6720313, b"\x00" * 4, b"\x00" * 4, 0, 0, 0, 0, b"\x00" * 2, 65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824, 318, 0, 180, 0) box_header = FullBoxHeader() tkhd = bx_def.TKHD(box_header) tkhd.header.type = b"tkhd" tkhd.header.version = 1 tkhd.header.flags = b"\x00\x00\x07" tkhd.creation_time = 3596199850 tkhd.modification_time = 3596199850 tkhd.track_id = 1 tkhd.duration = 6720313 tkhd.layer = 0 tkhd.alternate_group = 0 tkhd.volume = [0, 0] tkhd.matrix = [65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824] tkhd.width = [318, 0] tkhd.height = [180, 0] tkhd.refresh_box_size() box = tkhd assert box.header.type == b"tkhd" assert box.header.box_size == 104 assert box.header.version == 1 assert box.header.flags == b"\x00\x00\x07" assert box.creation_time == 3596199850 assert box.modification_time == 3596199850 assert box.track_id == 1 assert box.duration == 6720313 assert box.layer == 0 assert box.alternate_group == 0 assert box.volume == [0, 0] assert box.matrix == [65536, 0, 0, 0, 65536, 0, 0, 0, 1073741824] assert box.width == 318 assert box.height == 180 assert box.is_audio is False assert bytes(next(Parser.parse(bs))) == bs.bytes assert bytes(box) == bs.bytes
import argparse from bitstring import BitStream, ConstBitStream from pybzparse import Parser, boxes as bx_def parser = argparse.ArgumentParser() parser.add_argument("input") args = parser.parse_args() bstr = ConstBitStream(filename=args.input) _, _, moov = Parser.parse(bstr, recursive=False) moov.parse_boxes(bstr, recursive=False) for moov_subbox in moov.boxes: if moov_subbox.header.type != b"trak": if isinstance(moov_subbox, bx_def.ContainerBox): moov_subbox.parse_boxes(bstr) moov_subbox.load(bstr) continue trak = moov_subbox trak.parse_boxes(bstr, recursive=False) mdia = None for trak_subbox in trak.boxes: if trak_subbox.header.type == b"mdia": mdia = trak_subbox
def test_hvcc_box(): bs = pack("uintbe:32, bytes:4, " "uintbe:8, " "int:2, int:1, int:5, uintbe:32, uintbe:48, uintbe:8, " "bits:4, int:12, bits:6, int:2, bits:6, int:2, bits:5, int:3, bits:5, int:3, " "uintbe:16, uint:2, uint:3, uint:1, uint:2, uint:8, " "uint:1, bits:1, uint:6, uintbe:16, " "uint:16, bytes:3", 39, b"hvcc", 1, 0, 0, 3, 1879048192, 193514046488576, 90, '0b1111', 0, '0b111111', 0, '0b111111', 1, '0b11111', 0, '0b11111', 0, 0, 0, 1, 0, 3, 1, 1, '0b0', 32, 1, 3, b"321") box_header = BoxHeader() hvcc = bx_def.HVCC(box_header) hvcc.header.type = b"hvcc" hvcc.header.box_size = 39 hvcc.configuration_version = 1 hvcc.general_profile_space = 0 hvcc.general_tier_flag = 0 hvcc.general_profile_idc = 3 hvcc.general_profile_compatibility_flags = 1879048192 hvcc.general_constraint_indicator_flags = 193514046488576 hvcc.general_level_idc = 90 hvcc.min_spatial_segmentation_idc = 0 hvcc.parallelism_type = 0 hvcc.chroma_format = 1 hvcc.bit_depth_luma_minus_8 = 0 hvcc.bit_depth_chroma_minus_8 = 0 hvcc.avg_frame_rate = 0 hvcc.constant_frame_rate = 0 hvcc.num_temporal_layers = 1 hvcc.temporal_id_nested = 0 hvcc.length_size_minus_one = 3 array = hvcc.append_and_return() array.array_completeness = 1 array.nal_unit_type = 32 nalu = array.append_and_return() nalu.nal_unit_length = 3 nalu.nal_unit = (b"321", "bytes:3") box = hvcc assert box.header.type == b"hvcc" assert box.header.box_size == 39 assert box.configuration_version == 1 assert box.general_profile_space == 0 assert box.general_tier_flag == 0 assert box.general_profile_idc == 3 assert box.general_profile_compatibility_flags == 1879048192 assert box.general_constraint_indicator_flags == 193514046488576 assert box.general_level_idc == 90 assert box.min_spatial_segmentation_idc == 0 assert box.parallelism_type == 0 assert box.chroma_format == 1 assert box.bit_depth_luma_minus_8 == 0 assert box.bit_depth_chroma_minus_8 == 0 assert box.avg_frame_rate == 0 assert box.constant_frame_rate == 0 assert box.num_temporal_layers == 1 assert box.temporal_id_nested == 0 assert box.length_size_minus_one == 3 assert box.num_of_arrays == 1 assert len(box.arrays) == 1 array = box.arrays[0] assert array.array_completeness == 1 assert array.nal_unit_type == 32 assert array.num_nalus == 1 assert len(array.nalus) == 1 nalu = array.nalus[0] assert nalu.nal_unit_length == 3 assert nalu.nal_unit == b"321" parsed_box = next(Parser.parse(bs)) parsed_box.load(bs) assert bytes(parsed_box) == bs.bytes assert bytes(box) == bs.bytes