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}