code wiki / (root) / nx_h264_pframe_walk.nx

nx_h264_pframe_walk.nx source

↩ module page · 328 lines · 15667 B

1// nx_h264_pframe_walk.nx -- P-R1c: ENTROPY-WALK the entire P-frame (frame 1) of realtest.mp4. 2// Consumes every bit of the P-slice exactly: mb_skip_run runs, P mb_types (incl P_8x8 sub_mb_types), 3// mvd se-pairs, ref_idx (te(v) only if num_ref>1), inter CBP (Table 9-4 inter), residual (nC-tracked), 4// and intra-in-P MBs (mb_type>=5 -> I path). Proof of correct P syntax = all MBs parsed + reader lands 5// at the rbsp end (same bar as the I-frame walk). No reconstruction yet (P-R2..R4). license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_mp4_demux.nx" 8import "nx_mp4_stbl.nx" 9import "nx_h264_bits.nx" 10import "nx_h264_sps.nx" 11import "nx_h264_pps.nx" 12import "nx_h264_nal.nx" 13import "nx_h264_slice.nx" 14import "nx_h264_mb.nx" 15import "nx_h264_mb_pred.nx" 16import "nx_h264_coeff_token.nx" 17import "nx_h264_cavlc_level.nx" 18import "nx_h264_residual.nx" 19import "nx_h264_nc.nx" 20import "nx_h264_pmb.nx" 21 22func gp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 23func gn(v: i64) -> i64 { 24 let bb: *u8 = sys_mmap(28); var m: i64 = v 25 if m < 0 { sys_write(1, "-\x00" as *u8, 1); m = 0 - m } 26 let t: *u8 = sys_mmap(28); var k: i64 = 0 27 if m == 0 { t[0] = 48 as u8; k = 1 } 28 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 29 var i: i64 = 0 30 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 31 sys_write(1, bb, k); return 0 32} 33func find_tag(b: *u8, start: i64, end: i64, s: *u8) -> i64 { 34 var i: i64 = start 35 while i + 4 <= end { if mp4_t4(b, i, s) == 1 { return i - 4 } i = i + 1 } 36 return 0 - 1 37} 38func dec_luma(br: *BitReader, lumaTC: *i64, lbW: i64, bx: i64, by: i64, maxc: i64, coeff: *i64) -> i64 { 39 var nA: i64 = 0 40 var avA: i64 = 0 41 if bx > 0 { nA = lumaTC[by * lbW + (bx - 1)]; avA = 1 } 42 var nB: i64 = 0 43 var avB: i64 = 0 44 if by > 0 { nB = lumaTC[(by - 1) * lbW + bx]; avB = 1 } 45 let nC: i64 = nx_h264_nc_luma(nA, avA, nB, avB) 46 let tc: i64 = nx_h264_residual_decode(br, maxc, nC, coeff) 47 lumaTC[by * lbW + bx] = tc 48 return tc 49} 50func dec_cac(br: *BitReader, cTC: *i64, cbW: i64, cbx: i64, cby: i64, coeff: *i64) -> i64 { 51 var nA: i64 = 0 52 var avA: i64 = 0 53 if cbx > 0 { nA = cTC[cby * cbW + (cbx - 1)]; avA = 1 } 54 var nB: i64 = 0 55 var avB: i64 = 0 56 if cby > 0 { nB = cTC[(cby - 1) * cbW + cbx]; avB = 1 } 57 let nC: i64 = nx_h264_nc_luma(nA, avA, nB, avB) 58 let tc: i64 = nx_h264_residual_decode(br, 15, nC, coeff) 59 cTC[cby * cbW + cbx] = tc 60 return tc 61} 62 63func main() -> i64 { 64 let szp: *i64 = sys_mmap(16) as *i64 65 let b: *u8 = sys_read_file("knowledge/staging/media/realtest.mp4\x00" as *u8, szp) 66 if (b as i64) == 0 { gp("no realtest.mp4\n\x00" as *u8); return 1 } 67 let len: i64 = szp[0] 68 let avcc: i64 = find_tag(b, 0, len, "avcC\x00" as *u8) 69 let pay: i64 = avcc + 8 70 let spsLen: i64 = (b[pay + 6] as i64) * 256 + (b[pay + 7] as i64) 71 let spsdst: *u8 = sys_mmap(spsLen + 16) 72 let spsrbsp: i64 = nx_h264_unescape_rbsp((b as i64 + pay + 9) as *u8, spsLen - 1, spsdst) 73 let sps: *i64 = sys_mmap(128) as *i64 74 nx_h264_parse_sps(spsdst, spsrbsp, sps) 75 let ppspos: i64 = pay + 8 + spsLen 76 let ppsLen: i64 = (b[ppspos + 1] as i64) * 256 + (b[ppspos + 2] as i64) 77 let ppsdst: *u8 = sys_mmap(ppsLen + 16) 78 let ppsrbsp: i64 = nx_h264_unescape_rbsp((b as i64 + ppspos + 3 + 1) as *u8, ppsLen - 1, ppsdst) 79 let pps: *i64 = sys_mmap(128) as *i64 80 nx_h264_parse_pps(ppsdst, ppsrbsp, pps) 81 let W: i64 = sps[2] 82 let H: i64 = sps[3] 83 let mbW: i64 = W / 16 84 let mbH: i64 = H / 16 85 let totalMB: i64 = mbW * mbH 86 87 // locate sample 1 via stco (one chunk per sample) 88 let vi: *i64 = sys_mmap(64) as *i64 89 nx_mp4_video_info(b, len, vi) 90 let rco: *i64 = sys_mmap(16) as *i64 91 mp4_find_box(b, vi[5], vi[6], "stco\x00" as *u8, rco) 92 let s1off: i64 = mp4_be32(b, rco[0] + 12) // chunk1 = sample1 93 let rsz: *i64 = sys_mmap(16) as *i64 94 mp4_find_box(b, vi[5], vi[6], "stsz\x00" as *u8, rsz) 95 var samp1: i64 = mp4_be32(b, rsz[0] + 4) 96 if samp1 == 0 { samp1 = mp4_be32(b, rsz[0] + 16) } 97 let offs: *i64 = sys_mmap(256 * 8) as *i64 98 let types: *i64 = sys_mmap(256 * 8) as *i64 99 let nc: i64 = nx_nal_split_avcc(b, s1off, s1off + samp1, 4, offs, types, 256) 100 var sidx: i64 = 0 - 1 101 var i: i64 = 0 102 while i < nc { if types[i] == 1 { if sidx < 0 { sidx = i } } i = i + 1 } 103 if sidx < 0 { gp("no P-slice in sample1\n\x00" as *u8); return 2 } 104 let noff: i64 = offs[sidx] 105 let ntype: i64 = b[noff] as i64 106 let nlen: i64 = mp4_be32(b, noff - 4) 107 let sl_dst: *u8 = sys_mmap(nlen + 64) 108 let sl_rbsp: i64 = nx_h264_unescape_rbsp((b as i64 + noff + 1) as *u8, nlen - 1, sl_dst) 109 let sh: *i64 = sys_mmap(64) as *i64 110 let sbr: *BitReader = sys_mmap(NX_BR_BYTES) as *BitReader 111 br_init(sbr, sl_dst, sl_rbsp) 112 nx_h264_parse_slice_header_br(sbr, ntype & 31, (ntype >> 5) & 3, sps[9], sps[11], sps[10], sps[6], pps[3], pps[6], sh) 113 let num_ref: i64 = sh[12] + 1 114 gp(" P-slice QP=\x00" as *u8); gn(sh[7]); gp(" num_ref=\x00" as *u8); gn(num_ref); gp(" rbsp_bytes=\x00" as *u8); gn(sl_rbsp); gp("\n\x00" as *u8) 115 116 // nC maps + block scan 117 let lbW: i64 = mbW * 4 118 let lbH: i64 = mbH * 4 119 let lumaTC: *i64 = sys_mmap(lbW * lbH * 8) as *i64 120 let cbW: i64 = mbW * 2 121 let cbH: i64 = mbH * 2 122 let uTC: *i64 = sys_mmap(cbW * cbH * 8) as *i64 123 let vTC: *i64 = sys_mmap(cbW * cbH * 8) as *i64 124 var z: i64 = 0 125 while z < lbW * lbH { lumaTC[z] = 0; z = z + 1 } 126 z = 0 127 while z < cbW * cbH { uTC[z] = 0; vTC[z] = 0; z = z + 1 } 128 let bx4: *i64 = sys_mmap(16 * 8) as *i64 129 let by4: *i64 = sys_mmap(16 * 8) as *i64 130 bx4[0]=0; by4[0]=0; bx4[1]=1; by4[1]=0; bx4[2]=0; by4[2]=1; bx4[3]=1; by4[3]=1 131 bx4[4]=2; by4[4]=0; bx4[5]=3; by4[5]=0; bx4[6]=2; by4[6]=1; bx4[7]=3; by4[7]=1 132 bx4[8]=0; by4[8]=2; bx4[9]=1; by4[9]=2; bx4[10]=0; by4[10]=3; bx4[11]=1; by4[11]=3 133 bx4[12]=2; by4[12]=2; bx4[13]=3; by4[13]=2; bx4[14]=2; by4[14]=3; bx4[15]=3; by4[15]=3 134 135 let coeff: *i64 = sys_mmap(32 * 8) as *i64 136 var qp: i64 = sh[7] 137 var nskip: i64 = 0 138 var ninter: i64 = 0 139 var nintra: i64 = 0 140 var nmvd: i64 = 0 141 var ok: i64 = 1 142 var mbAddr: i64 = 0 143 while mbAddr < totalMB { 144 if ok == 0 { mbAddr = totalMB } else { 145 let skip_run: i64 = br_read_ue(sbr) 146 var s2: i64 = 0 147 while s2 < skip_run { 148 if mbAddr < totalMB { 149 // P_Skip: all blocks TC=0 150 let mbX: i64 = mbAddr % mbW 151 let mbY: i64 = mbAddr / mbW 152 var bl: i64 = 0 153 while bl < 16 { lumaTC[(mbY*4 + by4[bl]) * lbW + (mbX*4 + bx4[bl])] = 0; bl = bl + 1 } 154 var cc: i64 = 0 155 while cc < 4 { uTC[(mbY*2 + cc/2) * cbW + (mbX*2 + cc%2)] = 0; vTC[(mbY*2 + cc/2) * cbW + (mbX*2 + cc%2)] = 0; cc = cc + 1 } 156 nskip = nskip + 1 157 mbAddr = mbAddr + 1 158 } 159 s2 = s2 + 1 160 } 161 if mbAddr < totalMB { 162 let mbX: i64 = mbAddr % mbW 163 let mbY: i64 = mbAddr / mbW 164 let bx0: i64 = mbX * 4 165 let by0: i64 = mbY * 4 166 let mb_type: i64 = br_read_ue(sbr) 167 let kind: i64 = nx_h264_pmb_kind(mb_type) 168 if kind >= 0 { 169 // ---- INTER P macroblock ---- 170 ninter = ninter + 1 171 var nmv: i64 = nx_h264_pmb_nparts(kind) 172 if nx_h264_pmb_is_8x8(kind) == 1 { 173 // 4 sub_mb_types, then total sub-MVs 174 let subs: *i64 = sys_mmap(8 * 8) as *i64 175 var si: i64 = 0 176 while si < 4 { subs[si] = br_read_ue(sbr); si = si + 1 } 177 nmv = 0 178 si = 0 179 while si < 4 { nmv = nmv + nx_h264_psub_nparts(subs[si]); si = si + 1 } 180 } 181 // ref_idx: only coded if num_ref>1 AND kind codes ref 182 if num_ref > 1 { 183 if nx_h264_pmb_codes_ref(kind) == 1 { 184 var rp: i64 = 0 185 let nrefparts: i64 = nx_h264_pmb_nparts(kind) 186 while rp < nrefparts { 187 // te(v): range [0,num_ref-1]; >1 -> ue; ==1 (num_ref==2) -> 1 bit inverted 188 if num_ref == 2 { br_read_bit(sbr) } else { br_read_ue(sbr) } 189 rp = rp + 1 190 } 191 } 192 } 193 // mvd: nmv pairs of (se,se) 194 var mv: i64 = 0 195 while mv < nmv { br_read_se(sbr); br_read_se(sbr); nmvd = nmvd + 1; mv = mv + 1 } 196 // CBP (inter map) + residual 197 let cbp: i64 = nx_h264_decode_cbp_inter(sbr) 198 let cbpL: i64 = cbp & 15 199 let cbpC: i64 = (cbp >> 4) & 3 200 if cbp != 0 { let mqd: i64 = br_read_se(sbr); qp = (qp + mqd + 52) % 52 } 201 // luma: per 8x8 cbp bit, 4 blocks each, full maxCoeff=16 202 var bl: i64 = 0 203 while bl < 16 { 204 let abx: i64 = bx0 + bx4[bl] 205 let aby: i64 = by0 + by4[bl] 206 let i8: i64 = bl / 4 207 if ((cbpL >> i8) & 1) != 0 { dec_luma(sbr, lumaTC, lbW, abx, aby, 16, coeff) } 208 if ((cbpL >> i8) & 1) == 0 { lumaTC[aby * lbW + abx] = 0 } 209 bl = bl + 1 210 } 211 if cbpC != 0 { 212 let ucdc: *i64 = sys_mmap(8 * 8) as *i64 213 nx_h264_residual_decode_cdc(sbr, ucdc) 214 let vcdc: *i64 = sys_mmap(8 * 8) as *i64 215 nx_h264_residual_decode_cdc(sbr, vcdc) 216 if cbpC == 2 { 217 var cc: i64 = 0 218 while cc < 4 { dec_cac(sbr, uTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); cc = cc + 1 } 219 cc = 0 220 while cc < 4 { dec_cac(sbr, vTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); cc = cc + 1 } 221 } 222 } 223 if cbpC == 0 { 224 var cc: i64 = 0 225 while cc < 4 { uTC[(mbY*2 + cc/2) * cbW + (mbX*2 + cc%2)] = 0; vTC[(mbY*2 + cc/2) * cbW + (mbX*2 + cc%2)] = 0; cc = cc + 1 } 226 } 227 } 228 if kind < 0 { 229 // ---- INTRA macroblock inside a P-slice (mb_type-5) ---- 230 nintra = nintra + 1 231 let it: i64 = mb_type - 5 232 let cls: i64 = nx_h264_mb_type_class(it) 233 if cls == 1 { 234 let der: *i64 = sys_mmap(32) as *i64 235 nx_h264_i16x16_derive(it, der) 236 let cbpL: i64 = der[2] 237 let cbpC: i64 = der[1] 238 br_read_ue(sbr) // intra_chroma_pred_mode 239 let mqd: i64 = br_read_se(sbr); qp = (qp + mqd + 52) % 52 240 // luma DC at block 0 context 241 var nA: i64 = 0 242 var avA: i64 = 0 243 if bx0 > 0 { nA = lumaTC[by0 * lbW + (bx0 - 1)]; avA = 1 } 244 var nB: i64 = 0 245 var avB: i64 = 0 246 if by0 > 0 { nB = lumaTC[(by0 - 1) * lbW + bx0]; avB = 1 } 247 let nCdc: i64 = nx_h264_nc_luma(nA, avA, nB, avB) 248 nx_h264_residual_decode(sbr, 16, nCdc, coeff) 249 var bl: i64 = 0 250 while bl < 16 { 251 let abx: i64 = bx0 + bx4[bl] 252 let aby: i64 = by0 + by4[bl] 253 if cbpL != 0 { dec_luma(sbr, lumaTC, lbW, abx, aby, 15, coeff) } 254 if cbpL == 0 { lumaTC[aby * lbW + abx] = 0 } 255 bl = bl + 1 256 } 257 if cbpC != 0 { 258 let u2: *i64 = sys_mmap(8*8) as *i64 259 nx_h264_residual_decode_cdc(sbr, u2) 260 let v2: *i64 = sys_mmap(8*8) as *i64 261 nx_h264_residual_decode_cdc(sbr, v2) 262 if cbpC == 2 { 263 var cc: i64 = 0 264 while cc < 4 { dec_cac(sbr, uTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); cc = cc + 1 } 265 cc = 0 266 while cc < 4 { dec_cac(sbr, vTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); cc = cc + 1 } 267 } 268 } 269 } 270 if cls == 0 { 271 let modes: *i64 = sys_mmap(24 * 8) as *i64 272 nx_h264_parse_inxn_predmodes(sbr, modes) 273 let cbp: i64 = nx_h264_decode_cbp_intra(sbr) 274 let cbpL: i64 = cbp & 15 275 let cbpC: i64 = (cbp >> 4) & 3 276 if cbp != 0 { let mqd: i64 = br_read_se(sbr); qp = (qp + mqd + 52) % 52 } 277 var bl: i64 = 0 278 while bl < 16 { 279 let abx: i64 = bx0 + bx4[bl] 280 let aby: i64 = by0 + by4[bl] 281 let i8: i64 = bl / 4 282 if ((cbpL >> i8) & 1) != 0 { dec_luma(sbr, lumaTC, lbW, abx, aby, 16, coeff) } 283 if ((cbpL >> i8) & 1) == 0 { lumaTC[aby * lbW + abx] = 0 } 284 bl = bl + 1 285 } 286 if cbpC != 0 { 287 let u3: *i64 = sys_mmap(8*8) as *i64 288 nx_h264_residual_decode_cdc(sbr, u3) 289 let v3: *i64 = sys_mmap(8*8) as *i64 290 nx_h264_residual_decode_cdc(sbr, v3) 291 if cbpC == 2 { 292 var cc: i64 = 0 293 while cc < 4 { dec_cac(sbr, uTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); cc = cc + 1 } 294 cc = 0 295 while cc < 4 { dec_cac(sbr, vTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); cc = cc + 1 } 296 } 297 } 298 } 299 if cls == 2 { 300 // I_PCM in P (rare): byte-align + 384 bytes 301 br_align(sbr) 302 var pp: i64 = 0 303 while pp < 384 { br_read_bits(sbr, 8); pp = pp + 1 } 304 } 305 if cls < 0 { ok = 0; gp(" DESYNC bad intra mb_type at \x00" as *u8); gn(mbAddr); gp("\n\x00" as *u8) } 306 if mb_type > 30 { ok = 0; gp(" DESYNC mb_type>30 (\x00" as *u8); gn(mb_type); gp(") at \x00" as *u8); gn(mbAddr); gp("\n\x00" as *u8) } 307 } 308 mbAddr = mbAddr + 1 309 } 310 } 311 } 312 313 gp(" parsed MBs=\x00" as *u8); gn(mbAddr); gp("/\x00" as *u8); gn(totalMB) 314 gp(" (skip=\x00" as *u8); gn(nskip); gp(" inter=\x00" as *u8); gn(ninter); gp(" intra=\x00" as *u8); gn(nintra); gp(" mvd_pairs=\x00" as *u8); gn(nmvd); gp(")\n\x00" as *u8) 315 gp(" reader byte_pos=\x00" as *u8); gn(sbr.byte_pos); gp("/\x00" as *u8); gn(sl_rbsp); gp(" bit_pos=\x00" as *u8); gn(sbr.bit_pos); gp("\n\x00" as *u8) 316 if ok == 1 { 317 if mbAddr == totalMB { 318 if sbr.byte_pos >= sl_rbsp - 2 { 319 gp(" *** P-FRAME ENTROPY SYNC: all MBs parsed, reader at rbsp end -> P-R1 GREEN ***\n\x00" as *u8) 320 return 0 321 } 322 gp(" all MBs parsed but reader NOT at rbsp end (over/under-read)\n\x00" as *u8) 323 return 5 324 } 325 } 326 gp(" DESYNC: did not cleanly parse all P-MBs\n\x00" as *u8) 327 return 6 328}