code wiki / (root) / nx_mp4_probe.nx

nx_mp4_probe.nx source

↩ module page · 92 lines · 5015 B

1// nx_mp4_probe.nx -- SOVEREIGN MP4/fMP4 box-tree validator (no ffmpeg, no strings|grep). Walks the 2// ISO-BMFF box tree in the header region of a file, printing type/size/offset per box and recursing 3// into containers (moov/trak/mdia/minf/stbl/mvex/moof/traf) + the sample-entry boxes (stsd/avc1/mp4a), 4// flagging any box whose declared size is malformed. Stops at the first mdat (its payload is opaque). 5// Confirms track count + codec boxes (avc1/avcC, mp4a/esds) + first-fragment traf count. Used to verify 6// nx_ts2fmp4 output. Usage: nx_mp4_probe <file.mp4>. license_tier: ORIGINAL 7import "nx_syscalls.nx" 8 9const RDCAP: i64 = 2097152 10 11func mp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 12func mn(v: i64) -> i64 { 13 var m: i64=v; var neg: i64=0; if m<0 { neg=1; m=0-m } 14 let b: *u8=sys_mmap(32); var i: i64=32 15 if m==0 { i=i-1; b[i]=(48 as u8) } 16 while m>0 { let q: i64=m/10; i=i-1; b[i]=((48+(m-q*10)) as u8); m=q } 17 if neg==1 { i=i-1; b[i]=(45 as u8) } 18 return sys_write(1, ((b as i64)+i) as *u8, 32-i) 19} 20func mind(d: i64) -> i64 { var k: i64=0; while k<d { mp(" " as *u8); k=k+1 } return 0 } 21func be32(b: *u8, o: i64) -> i64 { return ((b[o] as i64)<<24)|((b[o+1] as i64)<<16)|((b[o+2] as i64)<<8)|(b[o+3] as i64) } 22func is4(b: *u8, o: i64, s: *u8) -> i64 { if b[o]==s[0] { if b[o+1]==s[1] { if b[o+2]==s[2] { if b[o+3]==s[3] { return 1 } } } } return 0 } 23func ptype(b: *u8, o: i64) -> i64 { sys_write(1, ((b as i64)+o) as *u8, 4); return 0 } 24func iscont(b: *u8, o: i64) -> i64 { 25 if is4(b,o,"moov" as *u8)==1 { return 1 } 26 if is4(b,o,"trak" as *u8)==1 { return 1 } 27 if is4(b,o,"mdia" as *u8)==1 { return 1 } 28 if is4(b,o,"minf" as *u8)==1 { return 1 } 29 if is4(b,o,"stbl" as *u8)==1 { return 1 } 30 if is4(b,o,"mvex" as *u8)==1 { return 1 } 31 if is4(b,o,"moof" as *u8)==1 { return 1 } 32 if is4(b,o,"traf" as *u8)==1 { return 1 } 33 if is4(b,o,"dinf" as *u8)==1 { return 1 } 34 return 0 35} 36 37// st[0]=trak st[1]=avc1 st[2]=mp4a st[3]=esds st[4]=moof st[5]=traf st[6]=bad 38// ISO-BMFF largesize: a 64-bit box length. Needed by every file over 4GB. 39func be64(b: *u8, o: i64) -> i64 { 40 var v: i64 = 0 41 var i: i64 = 0 42 while i < 8 { v = (v << 8) | (b[o+i] as i64); i = i + 1 } 43 return v 44} 45func walk(b: *u8, start: i64, end: i64, depth: i64, st: *i64) -> i64 { 46 var o: i64 = start 47 var stop: i64 = 0 48 while stop==0 { 49 if o + 8 > end { stop=1 } else { 50 var sz: i64 = be32(b, o) 51 var hdr: i64 = 8 52 if sz == 1 { if o + 16 <= end { sz = be64(b, o + 8); hdr = 16 } } 53 if sz == 0 { sz = end - o } 54 if sz < hdr { 55 mind(depth); mp("BAD-size(" as *u8); mn(sz); mp(") " as *u8); ptype(b,o+4); mp("\n" as *u8); st[6]=st[6]+1; stop=1 56 } else { 57 let cend: i64 = o + sz 58 mind(depth); ptype(b, o+4); mp(" size=" as *u8); mn(sz); mp(" @" as *u8); mn(o); mp("\n" as *u8) 59 if is4(b,o+4,"trak" as *u8)==1 { st[0]=st[0]+1 } 60 if is4(b,o+4,"avc1" as *u8)==1 { st[1]=st[1]+1 } 61 if is4(b,o+4,"mp4a" as *u8)==1 { st[2]=st[2]+1 } 62 if is4(b,o+4,"esds" as *u8)==1 { st[3]=st[3]+1 } 63 if is4(b,o+4,"moof" as *u8)==1 { st[4]=st[4]+1 } 64 if is4(b,o+4,"traf" as *u8)==1 { st[5]=st[5]+1 } 65 if is4(b,o+4,"mdat" as *u8)==1 { stop=1 } else { 66 if cend > end { mind(depth+1); mp("(beyond read window)\n" as *u8); stop=1 } else { 67 if iscont(b,o+4)==1 { walk(b, o+hdr, cend, depth+1, st) } else { if is4(b,o+4,"stsd" as *u8)==1 { walk(b, o+16, cend, depth+1, st) } else { if is4(b,o+4,"avc1" as *u8)==1 { walk(b, o+86, cend, depth+1, st) } else { if is4(b,o+4,"mp4a" as *u8)==1 { walk(b, o+36, cend, depth+1, st) } } } } 68 o = cend 69 } 70 } 71 } 72 } 73 } 74 return 0 75} 76 77func main(argc: i64, argv: *i64) -> i64 { 78 if argc < 2 { mp("usage: nx_mp4_probe <file.mp4>\n" as *u8); return 2 } 79 let path: *u8 = argv[1] as *u8 80 let fd: i64 = sys_openat_rd(path) 81 if fd < 0 { mp("ERROR open failed\n" as *u8); return 1 } 82 let b: *u8 = sys_mmap(RDCAP + 16) 83 var got: i64 = 0; var go: i64 = 1 84 while go==1 { if got>=RDCAP { go=0 } else { let r: i64=sys_read(fd, ((b as i64)+got) as *u8, RDCAP-got); if r<=0 { go=0 } else { got=got+r } } } 85 sys_close(fd) 86 let st: *i64 = sys_mmap(64) as *i64; var z: i64=0; while z<8 { st[z]=0; z=z+1 } 87 mp("=== " as *u8); mp(path); mp(" (read " as *u8); mn(got); mp(" bytes) ===\n" as *u8) 88 walk(b, 0, got, 0, st) 89 mp("SUMMARY trak=" as *u8); mn(st[0]); mp(" avc1=" as *u8); mn(st[1]); mp(" mp4a=" as *u8); mn(st[2]); mp(" esds=" as *u8); mn(st[3]); mp(" moof=" as *u8); mn(st[4]); mp(" traf=" as *u8); mn(st[5]); mp(" bad=" as *u8); mn(st[6]); mp("\n" as *u8) 90 if st[6]==0 { mp("STRUCTURE OK\n" as *u8) } else { mp("STRUCTURE BAD\n" as *u8) } 91 return 0 92}