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}