code wiki / (root) / nx_hevc_parse.nx

nx_hevc_parse.nx source

↩ module page · 98 lines · 7092 B

1// nx_hevc_parse.nx -- SOVEREIGN HEVC(H.265) bitstream parser, RUNG 1 of the sovereign HEVC decoder. 2// Pulls the hvcC (CodecPrivate) from a .mkv, splits out VPS/SPS/PPS, de-emulates the SPS RBSP, and 3// Exp-Golomb-decodes the SPS to recover the real stream params (size, chroma, bit depth, profile/level). 4// No third party: this is the foundation the CABAC + reconstruction rungs build on. Usage: nx_hevc_parse <in.mkv> 5// license_tier: ORIGINAL 6import "nx_syscalls.nx" 7const K_MAGIC_8388608: i64 = 8388608 8const K_MAGIC_8192: i64 = 8192 9 10func pe(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return sys_write(1,s,n) } 11func pn(v: i64) -> i64 { var m: i64=v; if m<0{m=0-m} let b: *u8=sys_mmap(32); var i: i64=32; if m==0{i=i-1;b[i]=(48 as u8)} while m>0{let q: i64=m/10; i=i-1; b[i]=((48+(m-q*10)) as u8); m=q} return sys_write(1,((b as i64)+i) as *u8,32-i) } 12// ---- EBML (to fetch CodecPrivate=hvcC) ---- 13func vlen(b0: i64) -> i64 { if (b0&0x80)!=0{return 1} if (b0&0x40)!=0{return 2} if (b0&0x20)!=0{return 3} if (b0&0x10)!=0{return 4} if (b0&0x08)!=0{return 5} if (b0&0x04)!=0{return 6} if (b0&0x02)!=0{return 7} return 8 } 14func rid(b: *u8, i: i64, lo: *i64) -> i64 { let L: i64=vlen(b[i] as i64); var v: i64=0; var k: i64=0; while k<L {v=(v<<8)|(b[i+k] as i64); k=k+1} lo[0]=L; return v } 15func rsz(b: *u8, i: i64, lo: *i64) -> i64 { let L: i64=vlen(b[i] as i64); var v: i64=(b[i] as i64)&(0xff>>L); var k: i64=1; while k<L {v=(v<<8)|(b[i+k] as i64); k=k+1} lo[0]=L; return v } 16// ---- bit reader over an RBSP (bs[0]=ptr bs[1]=bitpos bs[2]=len) ---- 17func bget1(bs: *i64) -> i64 { let p: *u8=bs[0] as *u8; let bp: i64=bs[1]; let byte: i64=p[bp>>3] as i64; let bit: i64=(byte>>(7-(bp&7)))&1; bs[1]=bp+1; return bit } 18func bget(bs: *i64, n: i64) -> i64 { var v: i64=0; var i: i64=0; while i<n { v=(v<<1)|bget1(bs); i=i+1 } return v } 19func bue(bs: *i64) -> i64 { var lz: i64=0; while bget1(bs)==0 { lz=lz+1; if lz>40 {return 0} } if lz==0 {return 0} return ((1<<lz)-1) + bget(bs,lz) } 20 21func main(argc: i64, argv: *i64) -> i64 { 22 if argc<2 { pe("usage: nx_hevc_parse <in.mkv>\n" as *u8); return 2 } 23 let fd: i64=sys_openat_rd(argv[1] as *u8); if fd<0 { pe("ERROR open\n" as *u8); return 1 } 24 let cap: i64=K_MAGIC_8388608; let b: *u8=sys_mmap(cap+16) 25 var off: i64=0; while off<cap { let r: i64=sys_read(fd, ((b as i64)+off) as *u8, cap-off); if r<=0 {off=off; break} off=off+r } 26 sys_close(fd); let n: i64=off 27 let lo: *i64=sys_mmap(16) as *i64 28 // skip EBML header, find Segment, walk to Tracks, find the video TrackEntry's CodecPrivate 29 var i: i64=0 30 let id0: i64=rid(b,i,lo); let idl0: i64=lo[0]; let sz0: i64=rsz(b,i+idl0,lo); let szl0: i64=lo[0] 31 if id0!=0x1A45DFA3 { pe("not EBML\n" as *u8); return 1 } 32 i=i+idl0+szl0+sz0 33 let sid: i64=rid(b,i,lo); let sidl: i64=lo[0]; let ssz: i64=rsz(b,i+sidl,lo); let sszl: i64=lo[0] 34 if sid!=0x18538067 { pe("no Segment\n" as *u8); return 1 } 35 let cp: *u8=sys_mmap(K_MAGIC_8192); var cpn: i64=0 36 var p: i64=i+sidl+sszl 37 while p+2<n { 38 let eid: i64=rid(b,p,lo); let eidl: i64=lo[0]; let esz: i64=rsz(b,p+eidl,lo); let eszl: i64=lo[0]; let ed: i64=p+eidl+eszl 39 if eid==0x1654AE6B { 40 var q: i64=ed 41 while q+2<=ed+esz { 42 let tid: i64=rid(b,q,lo); let tidl: i64=lo[0]; let tsz: i64=rsz(b,q+tidl,lo); let tszl: i64=lo[0]; let td: i64=q+tidl+tszl 43 if tid==0xAE { 44 var ttype: i64=0; var hashevc: i64=0; let lcp: *u8=sys_mmap(K_MAGIC_8192); var lcpn: i64=0 45 var r2: i64=td 46 while r2+2<=td+tsz { 47 let fid: i64=rid(b,r2,lo); let fidl: i64=lo[0]; let fsz: i64=rsz(b,r2+fidl,lo); let fszl: i64=lo[0]; let fd2: i64=r2+fidl+fszl 48 if fid==0x83 { ttype=(b[fd2] as i64) } 49 if fid==0x86 { if fsz>=14 { if b[fd2+2]==(77 as u8) { if b[fd2+6]==(72 as u8) { hashevc=1 } } } } 50 if fid==0x63A2 { lcpn=fsz; var c: i64=0; while c<fsz { if c<K_MAGIC_8192 { lcp[c]=b[fd2+c] } c=c+1 } } 51 r2=fd2+fsz 52 } 53 if ttype==1 { if hashevc==1 { cpn=lcpn; var c2: i64=0; while c2<lcpn { cp[c2]=lcp[c2]; c2=c2+1 } } } 54 } 55 q=td+tsz 56 } 57 } 58 if eid==0x1F43B675 { p=n } else { if esz>n { p=n } else { p=ed+esz } } 59 } 60 if cpn==0 { pe("no HEVC track / CodecPrivate found\n" as *u8); return 1 } 61 pe("hvcC bytes=" as *u8); pn(cpn); pe("\n" as *u8) 62 // hvcC fixed header is 22 bytes, then numOfArrays at [22] 63 let lenSize: i64=((cp[21] as i64)&3)+1 64 let numArr: i64=cp[22] as i64 65 pe("lengthSize=" as *u8); pn(lenSize); pe(" numArrays=" as *u8); pn(numArr); pe("\n" as *u8) 66 var ap: i64=23; var spsoff: i64=0; var spslen: i64=0 67 var a: i64=0 68 while a<numArr { 69 let natype: i64=(cp[ap] as i64)&0x3f; let numNal: i64=((cp[ap+1] as i64)<<8)|(cp[ap+2] as i64); ap=ap+3 70 var k: i64=0 71 while k<numNal { 72 let nl: i64=((cp[ap] as i64)<<8)|(cp[ap+1] as i64); ap=ap+2 73 if natype==33 { if spslen==0 { spsoff=ap; spslen=nl } } // 33 = SPS 74 pe(" array type=" as *u8); pn(natype); pe(" nal_len=" as *u8); pn(nl); pe("\n" as *u8) 75 ap=ap+nl; k=k+1 76 } 77 a=a+1 78 } 79 if spslen==0 { pe("no SPS in hvcC\n" as *u8); return 1 } 80 // de-emulate the SPS RBSP (drop 0x03 in 00 00 03), skipping the 2-byte NAL header 81 let rb: *u8=sys_mmap(spslen+16); var rn: i64=0; var z: i64=0; var s: i64=spsoff+2 82 while s<spsoff+spslen { let cur: i64=cp[s] as i64; if z>=2 { if cur==3 { z=0; s=s+1 } else { rb[rn]=cur as u8; rn=rn+1; if cur==0 {z=z+1} else {z=0} s=s+1 } } else { rb[rn]=cur as u8; rn=rn+1; if cur==0 {z=z+1} else {z=0} s=s+1 } } 83 // parse SPS 84 let bs: *i64=sys_mmap(32) as *i64; bs[0]=rb as i64; bs[1]=0; bs[2]=rn 85 let vps_id: i64=bget(bs,4); let maxsub: i64=bget(bs,3); let nesting: i64=bget(bs,1) 86 // profile_tier_level (general): 8 + 32 + 4 + 44 + 8 = 96 bits; capture general_profile_idc + level_idc 87 let ptl0: i64=bget(bs,8); let prof_idc: i64=ptl0&0x1f 88 bget(bs,32); bget(bs,32); bget(bs,16) // compat(32) + 4flags+28 + 16 = 32+32+16 = 80 ... split: 32 compat, then 48 (4+44) 89 let level_idc: i64=bget(bs,8) 90 if maxsub>0 { pe("(note: max_sub_layers_minus1=" as *u8); pn(maxsub); pe(" >0; sub-layer PTL not parsed in R1)\n" as *u8) } 91 let sps_id: i64=bue(bs); let chroma: i64=bue(bs) 92 if chroma==3 { bget(bs,1) } 93 let width: i64=bue(bs); let height: i64=bue(bs) 94 let confwin: i64=bget(bs,1); if confwin==1 { bue(bs); bue(bs); bue(bs); bue(bs) } 95 let bd_luma: i64=bue(bs)+8; let bd_chroma: i64=bue(bs)+8 96 pe("SPS: " as *u8); pn(width); pe("x" as *u8); pn(height); pe(" chroma_idc=" as *u8); pn(chroma); pe(" (1=4:2:0) bitdepth=" as *u8); pn(bd_luma); pe("/" as *u8); pn(bd_chroma); pe(" profile_idc=" as *u8); pn(prof_idc); pe(" level=" as *u8); pn(level_idc/30); pe(".x vps=" as *u8); pn(vps_id); pe(" sps=" as *u8); pn(sps_id); pe("\n" as *u8) 97 return 0 98}