import struct
def find_in_container(data, offset, size, target_type, recursive=False):
results = []
current = offset + 8
end = offset + size
while current < end:
if current + 8 > end:
break
box_size = struct.unpack('>I', data[current:current+4])[0]
box_type = data[current+4:current+8]
if box_type == target_type:
results.append((current, box_size))
if recursive and box_type in [b'mvex', b'trak', b'mdia']:
results.extend(find_in_container(data, current, box_size, target_type, True))
if box_size == 0 or current + box_size > end:
break
current += box_size
return results
def parse_mehd(data, offset):
version = data[offset+8]
if version == 1:
duration = struct.unpack('>Q', data[offset+12:offset+20])[0]
else:
duration = struct.unpack('>I', data[offset+12:offset+16])[0]
return version, duration
for filename in ['input-5mb.mp4', 'fixed-5mb.mp4']:
print(f"\n{filename}:")
print("="*60)
with open(filename, 'rb') as f:
data = f.read()
offset = 0
while offset < len(data):
if offset + 8 > len(data):
break
size = struct.unpack('>I', data[offset:offset+4])[0]
box_type = data[offset+4:offset+8]
if box_type == b'moov':
mvexs = find_in_container(data, offset, size, b'mvex', False)
if mvexs:
print(" Found mvex box")
mvex_offset, mvex_size = mvexs[0]
mehds = find_in_container(data, mvex_offset, mvex_size, b'mehd', False)
if mehds:
mehd_offset, mehd_size = mehds[0]
version, duration = parse_mehd(data, mehd_offset)
print(f" mehd: version={version}, fragment_duration={duration}")
else:
print(" No mehd found (duration unspecified)")
else:
print(" No mvex box (not a fragmented MP4)")
break
if size == 0 or offset + size > len(data):
break
offset += size