code wiki / (root) / nx_hevc_slice.nx

nx_hevc_slice.nx source

↩ module page · 139 lines · 10166 B

1// nx_hevc_slice.nx -- SOVEREIGN HEVC headers, RUNG 3a of the HEVC decoder. 2// Parses SPS (extended: CTB/transform sizes, SAO), PPS (init_qp, slice-header bits), and pulls the FIRST 3// IDR slice NAL out of the .mkv's first keyframe to read its slice_type. This + the CABAC engine (R2) are 4// everything needed before the CTU/residual parse (R3b). No third party. Usage: nx_hevc_slice <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} if v<0{i=i-1;b[i]=(45 as u8)} return sys_write(1,((b as i64)+i) as *u8,32-i) } 12func 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 } 13func 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 } 14func 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 } 15func ruint(b: *u8, o: i64, len: i64) -> i64 { var v: i64=0; var k: i64=0; while k<len {v=(v<<8)|(b[o+k] as i64); k=k+1} return v } 16// de-emulate a NAL payload [src+off, +len) (skipping nhdr header bytes) into out; returns rbsp byte count 17func deemul(src: *u8, off: i64, len: i64, nhdr: i64, out: *u8) -> i64 { 18 var rn: i64=0; var z: i64=0; var s: i64=off+nhdr 19 while s<off+len { let c: i64=src[s] as i64; if z>=2 { if c==3 { z=0 } else { out[rn]=c as u8; rn=rn+1; if c==0 {z=z+1} else {z=0} } } else { out[rn]=c as u8; rn=rn+1; if c==0 {z=z+1} else {z=0} } s=s+1 } 20 return rn 21} 22// bit reader bs[0]=ptr bs[1]=bitpos bs[2]=len 23func bget1(bs: *i64) -> i64 { let p: *u8=bs[0] as *u8; let bp: i64=bs[1]; let byte: i64=p[bp>>3] as i64; bs[1]=bp+1; return (byte>>(7-(bp&7)))&1 } 24func 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 } 25func 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) } 26func bse(bs: *i64) -> i64 { let k: i64=bue(bs); if (k&1)==1 { return (k+1)/2 } return 0-(k/2) } 27 28func main(argc: i64, argv: *i64) -> i64 { 29 if argc<2 { pe("usage: nx_hevc_slice <in.mkv>\n" as *u8); return 2 } 30 let fd: i64=sys_openat_rd(argv[1] as *u8); if fd<0 { pe("ERROR open\n" as *u8); return 1 } 31 let cap: i64=K_MAGIC_8388608; let b: *u8=sys_mmap(cap+16) 32 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 } 33 sys_close(fd); let n: i64=off 34 let lo: *i64=sys_mmap(16) as *i64 35 var i: i64=0 36 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] 37 if id0!=0x1A45DFA3 { pe("not EBML\n" as *u8); return 1 } 38 i=i+idl0+szl0+sz0 39 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] 40 if sid!=0x18538067 { pe("no Segment\n" as *u8); return 1 } 41 let cp: *u8=sys_mmap(K_MAGIC_8192); var cpn: i64=0; var vtrk: i64=0; var clustart: i64=0 42 var p: i64=i+sidl+sszl 43 while p+2<n { 44 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 45 if eid==0x1654AE6B { 46 var q: i64=ed 47 while q+2<=ed+esz { 48 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 49 if tid==0xAE { 50 var ttype: i64=0; var tnum: i64=0; var hev: i64=0; let lcp: *u8=sys_mmap(K_MAGIC_8192); var lcpn: i64=0 51 var r2: i64=td 52 while r2+2<=td+tsz { 53 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 54 if fid==0xD7 { tnum=ruint(b,fd2,fsz) } 55 if fid==0x83 { ttype=ruint(b,fd2,fsz) } 56 if fid==0x86 { if fsz>=14 { if b[fd2+2]==(77 as u8) { if b[fd2+6]==(72 as u8) { hev=1 } } } } 57 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 } } 58 r2=fd2+fsz 59 } 60 if ttype==1 { if hev==1 { vtrk=tnum; cpn=lcpn; var c2: i64=0; while c2<lcpn {cp[c2]=lcp[c2]; c2=c2+1} } } 61 } 62 q=td+tsz 63 } 64 } 65 if eid==0x1F43B675 { clustart=p; p=n } else { if esz>n {p=n} else {p=ed+esz} } 66 } 67 if cpn==0 { pe("no HEVC track\n" as *u8); return 1 } 68 // extract SPS(33) + PPS(34) NALs from hvcC arrays 69 let numArr: i64=cp[22] as i64; var ap: i64=23 70 var spso: i64=0; var spsl: i64=0; var ppso: i64=0; var ppsl: i64=0 71 var a: i64=0 72 while a<numArr { let nt: i64=(cp[ap] as i64)&0x3f; let nn: i64=((cp[ap+1] as i64)<<8)|(cp[ap+2] as i64); ap=ap+3; var k: i64=0; while k<nn { let nl: i64=((cp[ap] as i64)<<8)|(cp[ap+1] as i64); ap=ap+2; if nt==33 { if spsl==0 {spso=ap; spsl=nl} } if nt==34 { if ppsl==0 {ppso=ap; ppsl=nl} } ap=ap+nl; k=k+1 } a=a+1 } 73 // ---- SPS ---- 74 let rb: *u8=sys_mmap(spsl+16); let rn: i64=deemul(cp,spso,spsl,2,rb) 75 let bs: *i64=sys_mmap(32) as *i64; bs[0]=rb as i64; bs[1]=0; bs[2]=rn 76 bget(bs,4); let maxsub: i64=bget(bs,3); bget(bs,1) 77 bget(bs,8); bget(bs,32); bget(bs,32); bget(bs,16); bget(bs,8) // profile_tier_level general (96 bits) 78 bue(bs); let chroma: i64=bue(bs); if chroma==3 {bget(bs,1)} 79 let width: i64=bue(bs); let height: i64=bue(bs) 80 if bget(bs,1)==1 { bue(bs); bue(bs); bue(bs); bue(bs) } 81 let bd_luma: i64=bue(bs)+8; bue(bs) 82 bue(bs) // log2_max_poc_lsb_minus4 83 let subord: i64=bget(bs,1); var si: i64=maxsub; if subord==1 {si=0} while si<=maxsub { bue(bs); bue(bs); bue(bs); si=si+1 } 84 let mincb: i64=bue(bs)+3; let diffcb: i64=bue(bs); let ctblog2: i64=mincb+diffcb; let ctbsize: i64=1<<ctblog2 85 let mintb: i64=bue(bs)+2; let difftb: i64=bue(bs) 86 bue(bs); bue(bs) // max_transform_hierarchy inter/intra 87 if bget(bs,1)==1 { if bget(bs,1)==1 { pe("(scaling_list_data present - not parsed in R3a)\n" as *u8) } } 88 let amp: i64=bget(bs,1); let sao: i64=bget(bs,1) 89 pe("SPS: " as *u8); pn(width); pe("x" as *u8); pn(height); pe(" CtbSizeY=" as *u8); pn(ctbsize); pe(" MinTbLog2=" as *u8); pn(mintb); pe(" MaxTbLog2=" as *u8); pn(mintb+difftb); pe(" amp=" as *u8); pn(amp); pe(" SAO=" as *u8); pn(sao); pe(" bd=" as *u8); pn(bd_luma); pe("\n" as *u8) 90 // ---- PPS ---- 91 let pb: *u8=sys_mmap(ppsl+16); let pn2: i64=deemul(cp,ppso,ppsl,2,pb) 92 let ps: *i64=sys_mmap(32) as *i64; ps[0]=pb as i64; ps[1]=0; ps[2]=pn2 93 bue(ps); bue(ps) // pps_id, sps_id 94 let dep_en: i64=bget(ps,1); let outfp: i64=bget(ps,1); let nehb: i64=bget(ps,3) 95 bget(ps,1); let cabac_init: i64=bget(ps,1) 96 bue(ps); bue(ps) // num_ref_idx default l0/l1 97 let initqp: i64=26+bse(ps) 98 pe("PPS: init_qp=" as *u8); pn(initqp); pe(" num_extra_slice_hdr_bits=" as *u8); pn(nehb); pe(" output_flag_present=" as *u8); pn(outfp); pe(" dependent_slices=" as *u8); pn(dep_en); pe(" cabac_init_present=" as *u8); pn(cabac_init); pe("\n" as *u8) 99 // ---- first slice NAL from first keyframe block ---- 100 if clustart==0 { pe("no cluster\n" as *u8); return 1 } 101 var slo: i64=0; var sll: i64=0; var ntype: i64=0 102 var cp2: i64=clustart 103 while cp2+2<n { if sll>0 { cp2=n } else { 104 let cid: i64=rid(b,cp2,lo); let cidl: i64=lo[0]; let csz: i64=rsz(b,cp2+cidl,lo); let cszl: i64=lo[0]; let cd: i64=cp2+cidl+cszl 105 if cid==0x1F43B675 { 106 var q2: i64=cd; var cend: i64=cd+csz; if cend>n {cend=n} 107 while q2+2<=cend { if sll>0 {q2=cend} else { 108 let bid: i64=rid(b,q2,lo); let bidl: i64=lo[0]; let bsz: i64=rsz(b,q2+bidl,lo); let bszl: i64=lo[0]; let bd: i64=q2+bidl+bszl 109 if bid==0xA3 { let tl: i64=vlen(b[bd] as i64); let trk: i64=rsz(b,bd,lo); let flg: i64=b[bd+tl+2] as i64; let foff: i64=bd+tl+3; let flen: i64=bsz-tl-3 110 if trk==vtrk { if (flg>>7)==1 { 111 // walk length-prefixed NALs (4-byte len), find first VCL (type<32) 112 var w: i64=foff 113 while w+4<=foff+flen { if sll>0 {w=foff+flen} else { 114 let nl: i64=((b[w] as i64)<<24)|((b[w+1] as i64)<<16)|((b[w+2] as i64)<<8)|(b[w+3] as i64) 115 let nt: i64=((b[w+4] as i64)>>1)&0x3f 116 if nt<32 { ntype=nt; slo=w+4; sll=nl } 117 w=w+4+nl 118 } } 119 } } 120 } 121 q2=bd+bsz 122 } } 123 cp2=cd+csz 124 } else { if csz>n {cp2=n} else {cp2=cd+csz} } 125 } } 126 if sll==0 { pe("no VCL slice NAL found\n" as *u8); return 1 } 127 pe("slice NAL type=" as *u8); pn(ntype); pe(" (19/20=IDR 21=CRA) len=" as *u8); pn(sll); pe("\n" as *u8) 128 // ---- slice header: first_slice + (IRAP)no_output + pps_id + extra bits + slice_type ---- 129 let sb: *u8=sys_mmap(sll+16); let sbn: i64=deemul(b,slo,sll,2,sb) 130 let hs: *i64=sys_mmap(32) as *i64; hs[0]=sb as i64; hs[1]=0; hs[2]=sbn 131 let first: i64=bget(hs,1) 132 if ntype>=16 { if ntype<=23 { bget(hs,1) } } // no_output_of_prior_pics_flag 133 bue(hs) // slice_pic_parameter_set_id 134 var eb: i64=0; while eb<nehb { bget(hs,1); eb=eb+1 } 135 let stype: i64=bue(hs) 136 pe("slice: first=" as *u8); pn(first); pe(" slice_type=" as *u8); pn(stype); pe(" (0=B 1=P 2=I)\n" as *u8) 137 if stype==2 { pe("R3a OK: I-slice header reached; CtbSize+SAO+init_qp known -> ready for R3b CTU parse\n" as *u8) } 138 return 0 139}