nx_h264_brecon.nx source
↩ module page · 1393 lines · 79188 B
1// nx_h264_brecon.nx -- B-R3: reconstruct the EXPLICIT-MV B macroblocks (B_L0/L1/Bi 16x16/16x8/8x16/8x8)
2// of the first B-slice of bframe_test.264 and verify LUMA bit-exact vs ffmpeg ground truth. Proves the
3// two-reference-list MV reconstruction (per-list median predictor + mvd) + BI-PREDICTION MC
4// (pred=(L0+L1+1)>>1) + residual. Direct/Skip (derived MVs) = B-R4; chroma/deblock = B-R5/R6.
5// References = ffmpeg-decoded anchors (POC->display = POC/2 here); target = the B-frame (its POC/2).
6// Excludes direct/skip/intra MBs from the pixel count. Exit 0/1. license_tier: ORIGINAL
7import "nx_syscalls.nx"
8import "nx_h264_bits.nx"
9import "nx_h264_sps.nx"
10import "nx_h264_pps.nx"
11import "nx_h264_nal.nx"
12import "nx_h264_slice.nx"
13import "nx_h264_mb.nx"
14import "nx_h264_mb_pred.nx"
15import "nx_h264_coeff_token.nx"
16import "nx_h264_cavlc_level.nx"
17import "nx_h264_residual.nx"
18import "nx_h264_nc.nx"
19import "nx_h264_bmb.nx"
20import "nx_h264_poc.nx"
21import "nx_h264_mvpred.nx"
22import "nx_h264_mvgrid.nx"
23import "nx_h264_pmvfield.nx"
24import "nx_h264_idct.nx"
25import "nx_h264_dequant.nx"
26import "nx_h264_zigzag.nx"
27import "nx_h264_mc_luma.nx"
28import "nx_h264_deblock.nx"
29import "nx_h264_intra_recon.nx"
30import "nx_h264_chroma.nx"
31import "nx_h264_chroma_pred.nx"
32
33func gp(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); if fd > 0 { sys_write(fd, s, n) } return 0 }
34func gn(fd: i64, v: i64) -> i64 {
35 let bb: *u8 = sys_mmap(28); var m: i64 = v
36 if m < 0 { sys_write(1, "-\x00" as *u8, 1); if fd > 0 { sys_write(fd, "-\x00" as *u8, 1) } m = 0 - m }
37 let t: *u8 = sys_mmap(28); var k: i64 = 0
38 if m == 0 { t[0] = 48 as u8; k = 1 }
39 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
40 var i: i64 = 0
41 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
42 sys_write(1, bb, k); if fd > 0 { sys_write(fd, bb, k) }
43 return 0
44}
45func dec_luma(br: *BitReader, lumaTC: *i64, lbW: i64, bx: i64, by: i64, maxc: i64, coeff: *i64) -> i64 {
46 var nA: i64 = 0
47 var avA: i64 = 0
48 if bx > 0 { nA = lumaTC[by * lbW + (bx - 1)]; avA = 1 }
49 var nB: i64 = 0
50 var avB: i64 = 0
51 if by > 0 { nB = lumaTC[(by - 1) * lbW + bx]; avB = 1 }
52 let nC: i64 = nx_h264_nc_luma(nA, avA, nB, avB)
53 let tc: i64 = nx_h264_residual_decode(br, maxc, nC, coeff)
54 lumaTC[by * lbW + bx] = tc
55 return tc
56}
57func dec_cac(br: *BitReader, cTC: *i64, cbW: i64, cbx: i64, cby: i64, coeff: *i64) -> i64 {
58 var nA: i64 = 0
59 var avA: i64 = 0
60 if cbx > 0 { nA = cTC[cby * cbW + (cbx - 1)]; avA = 1 }
61 var nB: i64 = 0
62 var avB: i64 = 0
63 if cby > 0 { nB = cTC[(cby - 1) * cbW + cbx]; avB = 1 }
64 let nC: i64 = nx_h264_nc_luma(nA, avA, nB, avB)
65 let tc: i64 = nx_h264_residual_decode(br, 15, nC, coeff)
66 cTC[cby * cbW + cbx] = tc
67 return tc
68}
69func read_ref(br: *BitReader, num_ref: i64) -> i64 {
70 if num_ref == 1 { return 0 }
71 if num_ref == 2 { let bb: i64 = br_read_bit(br); return 1 - bb }
72 return br_read_ue(br)
73}
74// one luma MC sample from a reference Y plane at quarter-pel MV (mvx,mvy).
75func mc1(ref: *u8, W: i64, H: i64, px: i64, py: i64, mvx: i64, mvy: i64) -> i64 {
76 return nx_h264_mc_luma_sample(ref, W, H, px + asr(mvx, 2), py + asr(mvy, 2), mvx & 3, mvy & 3)
77}
78// reconstruct one 4x4 luma block by (bi-)prediction + residual into myY.
79func recon_b_4x4(myY: *u8, W: i64, H: i64, refL0: *u8, refL1: *u8, bpx: i64, bpy: i64,
80 useL0: i64, mvx0: i64, mvy0: i64, useL1: i64, mvx1: i64, mvy1: i64,
81 coeffscan: *i64, qp: i64, hasRes: i64) -> i64 {
82 let pred: *i64 = sys_mmap(16 * 8) as *i64
83 var yy: i64 = 0
84 while yy < 4 {
85 var xx: i64 = 0
86 while xx < 4 {
87 let px: i64 = bpx + xx
88 let py: i64 = bpy + yy
89 var v: i64 = 0
90 if useL0 == 1 { if useL1 == 1 {
91 let a: i64 = mc1(refL0, W, H, px, py, mvx0, mvy0)
92 let bbv: i64 = mc1(refL1, W, H, px, py, mvx1, mvy1)
93 v = (a + bbv + 1) >> 1
94 } }
95 if useL0 == 1 { if useL1 == 0 { v = mc1(refL0, W, H, px, py, mvx0, mvy0) } }
96 if useL0 == 0 { if useL1 == 1 { v = mc1(refL1, W, H, px, py, mvx1, mvy1) } }
97 pred[yy * 4 + xx] = v
98 xx = xx + 1
99 }
100 yy = yy + 1
101 }
102 if hasRes == 1 {
103 let rast: *i64 = sys_mmap(16 * 8) as *i64
104 nx_h264_inv_zigzag4x4(coeffscan, rast)
105 let dq: *i64 = sys_mmap(16 * 8) as *i64
106 nx_h264_dequant4x4(rast, qp, dq)
107 nx_idct4x4(dq)
108 yy = 0
109 while yy < 4 { var xx: i64 = 0; while xx < 4 { pred[yy*4+xx] = pred[yy*4+xx] + dq[yy*4+xx]; xx = xx + 1 } yy = yy + 1 }
110 }
111 yy = 0
112 while yy < 4 {
113 var xx: i64 = 0
114 while xx < 4 {
115 var val: i64 = pred[yy * 4 + xx]
116 if val < 0 { val = 0 }
117 if val > 255 { val = 255 }
118 myY[(bpy + yy) * W + (bpx + xx)] = val as u8
119 xx = xx + 1
120 }
121 yy = yy + 1
122 }
123 return 0
124}
125
126// MinPositive (8.4.1.2.2): smallest non-negative of x,y; if both <0 -> <0.
127func minpos(x: i64, y: i64) -> i64 {
128 if x < 0 { return y }
129 if y < 0 { return x }
130 if x < y { return x }
131 return y
132}
133// Spatial-direct MB-level params (8.4.1.2.2): refIdxL0/L1 = MinPositive of A/B/C neighbour refs per list;
134// directZero if both <0; median predictors mvpL0/L1. Writes params[0..6]=
135// refL0,refL1,mvpL0x,mvpL0y,mvpL1x,mvpL1y,directZero.
136func b_direct_params(g0r: *i64, g0x: *i64, g0y: *i64, g1r: *i64, g1x: *i64, g1y: *i64,
137 lbW: i64, lbH: i64, mbX: i64, mbY: i64, params: *i64) -> i64 {
138 let px: i64 = mbX * 4
139 let py: i64 = mbY * 4
140 let na: *i64 = sys_mmap(32) as *i64
141 let nb: *i64 = sys_mmap(32) as *i64
142 let ncv: *i64 = sys_mmap(32) as *i64
143 let mvp: *i64 = sys_mmap(16) as *i64
144 nx_mvg_get(g0r, g0x, g0y, lbW, lbH, px - 1, py, na)
145 nx_mvg_get(g0r, g0x, g0y, lbW, lbH, px, py - 1, nb)
146 var cav: i64 = 0
147 if py > 0 { if px + 4 < lbW { nx_mvg_get(g0r, g0x, g0y, lbW, lbH, px + 4, py - 1, ncv); if ncv[0] != (0 - 2) { cav = 1 } } }
148 if cav == 0 { nx_mvg_get(g0r, g0x, g0y, lbW, lbH, px - 1, py - 1, ncv) }
149 var refL0: i64 = minpos(minpos(na[0], nb[0]), ncv[0])
150 nx_mvg_get(g1r, g1x, g1y, lbW, lbH, px - 1, py, na)
151 nx_mvg_get(g1r, g1x, g1y, lbW, lbH, px, py - 1, nb)
152 cav = 0
153 if py > 0 { if px + 4 < lbW { nx_mvg_get(g1r, g1x, g1y, lbW, lbH, px + 4, py - 1, ncv); if ncv[0] != (0 - 2) { cav = 1 } } }
154 if cav == 0 { nx_mvg_get(g1r, g1x, g1y, lbW, lbH, px - 1, py - 1, ncv) }
155 var refL1: i64 = minpos(minpos(na[0], nb[0]), ncv[0])
156 var dz: i64 = 0
157 if refL0 < 0 { if refL1 < 0 { refL0 = 0; refL1 = 0; dz = 1 } }
158 params[0] = refL0; params[1] = refL1; params[6] = dz
159 params[2] = 0; params[3] = 0; params[4] = 0; params[5] = 0
160 if refL0 >= 0 { nx_mvg_part_mvp(g0r, g0x, g0y, lbW, lbH, px, py, 4, refL0, 0, 0, mvp); params[2] = mvp[0]; params[3] = mvp[1] }
161 if refL1 >= 0 { nx_mvg_part_mvp(g1r, g1x, g1y, lbW, lbH, px, py, 4, refL1, 0, 0, mvp); params[4] = mvp[0]; params[5] = mvp[1] }
162 return 0
163}
164// fill one 4x4 (abx,aby) of a spatial-direct region into the two grids using params + co-located colZero.
165func b_direct_fill4(g0r: *i64, g0x: *i64, g0y: *i64, g1r: *i64, g1x: *i64, g1y: *i64, lbW: i64,
166 colR: *i64, colMx: *i64, colMy: *i64, abx: i64, aby: i64, params: *i64) -> i64 {
167 let idx: i64 = aby * lbW + abx
168 let refL0: i64 = params[0]
169 let refL1: i64 = params[1]
170 let dz: i64 = params[6]
171 var colZero: i64 = 0
172 if colR[idx] == 0 {
173 let cx: i64 = colMx[idx]
174 let cy: i64 = colMy[idx]
175 if cx >= 0 - 1 { if cx <= 1 { if cy >= 0 - 1 { if cy <= 1 { colZero = 1 } } } }
176 }
177 // L0
178 if refL0 >= 0 {
179 var mx: i64 = params[2]
180 var my: i64 = params[3]
181 if dz == 1 { mx = 0; my = 0 }
182 if refL0 == 0 { if colZero == 1 { mx = 0; my = 0 } }
183 g0r[idx] = refL0; g0x[idx] = mx; g0y[idx] = my
184 }
185 if refL0 < 0 { g0r[idx] = 0 - 1; g0x[idx] = 0; g0y[idx] = 0 }
186 // L1
187 if refL1 >= 0 {
188 var mx: i64 = params[4]
189 var my: i64 = params[5]
190 if dz == 1 { mx = 0; my = 0 }
191 if refL1 == 0 { if colZero == 1 { mx = 0; my = 0 } }
192 g1r[idx] = refL1; g1x[idx] = mx; g1y[idx] = my
193 }
194 if refL1 < 0 { g1r[idx] = 0 - 1; g1x[idx] = 0; g1y[idx] = 0 }
195 return 0
196}
197
198// B boundary strength (spec 8.7.2.1) for a luma 4x4 edge, using the DUAL-LIST MV grids. A B-block is
199// intra iff NEITHER list is used (g0r<0 AND g1r<0) -> 4 (MB edge) / 3 (internal). Nonzero coeff either
200// side -> 2. Else motion: a different SET of used lists, a different reference, or |MV diff| >= 4 (one
201// integer luma sample) in any used list -> 1; else 0. (Single ref per list here: L0=past, L1=future are
202// always distinct pictures, so the 8.7.2.1 cross-list-swap case cannot arise -> same-list compare suffices.)
203func b_bs(g0r: *i64, g0x: *i64, g0y: *i64, g1r: *i64, g1x: *i64, g1y: *i64, lumaTC: *i64, pblk: i64, qblk: i64, mbBoundary: i64) -> i64 {
204 var pIntra: i64 = 0
205 if g0r[pblk] < 0 { if g1r[pblk] < 0 { pIntra = 1 } }
206 var qIntra: i64 = 0
207 if g0r[qblk] < 0 { if g1r[qblk] < 0 { qIntra = 1 } }
208 if pIntra == 1 { if mbBoundary == 1 { return 4 } return 3 }
209 if qIntra == 1 { if mbBoundary == 1 { return 4 } return 3 }
210 if lumaTC[pblk] > 0 { return 2 }
211 if lumaTC[qblk] > 0 { return 2 }
212 var pU0: i64 = 0
213 if g0r[pblk] >= 0 { pU0 = 1 }
214 var pU1: i64 = 0
215 if g1r[pblk] >= 0 { pU1 = 1 }
216 var qU0: i64 = 0
217 if g0r[qblk] >= 0 { qU0 = 1 }
218 var qU1: i64 = 0
219 if g1r[qblk] >= 0 { qU1 = 1 }
220 if pU0 != qU0 { return 1 }
221 if pU1 != qU1 { return 1 }
222 if pU0 == 1 {
223 if g0r[pblk] != g0r[qblk] { return 1 }
224 var dx: i64 = g0x[pblk] - g0x[qblk]
225 if dx < 0 { dx = 0 - dx }
226 var dy: i64 = g0y[pblk] - g0y[qblk]
227 if dy < 0 { dy = 0 - dy }
228 if dx >= 4 { return 1 }
229 if dy >= 4 { return 1 }
230 }
231 if pU1 == 1 {
232 if g1r[pblk] != g1r[qblk] { return 1 }
233 var dx2: i64 = g1x[pblk] - g1x[qblk]
234 if dx2 < 0 { dx2 = 0 - dx2 }
235 var dy2: i64 = g1y[pblk] - g1y[qblk]
236 if dy2 < 0 { dy2 = 0 - dy2 }
237 if dx2 >= 4 { return 1 }
238 if dy2 >= 4 { return 1 }
239 }
240 return 0
241}
242
243// In-loop luma deblock for a B-frame: per reconstructed MB (didMB>=1) in raster order, 4 vertical then 4
244// horizontal edges, each split into four 4x4 segments with their own bS (b_bs). Reuses the PROVEN luma
245// filters (nx_deblock_luma_bs4 / nx_deblock_luma_edge). An MB-boundary edge to a NON-reconstructed
246// neighbour (B_8x8 / intra decode-for-sync, didMB<1) is SKIPPED -- those pixels are not yet reconstructed,
247// so filtering against them would be wrong (their edge columns remain the residual until that rung lands).
248func deblock_luma_b(yf: *u8, W: i64, mbW: i64, mbH: i64, mbQP: *i64,
249 g0r: *i64, g0x: *i64, g0y: *i64, g1r: *i64, g1x: *i64, g1y: *i64,
250 lumaTC: *i64, lbW: i64, didMB: *i64) -> i64 {
251 let s: *i64 = sys_mmap(8 * 8) as *i64
252 let ve: *i64 = sys_mmap(8 * 8) as *i64
253 ve[0]=0; ve[1]=4; ve[2]=8; ve[3]=12
254 var dmy: i64 = 0
255 while dmy < mbH {
256 var dmx: i64 = 0
257 while dmx < mbW {
258 let mbA: i64 = dmy * mbW + dmx
259 if didMB[mbA] >= 1 {
260 let px: i64 = dmx * 16
261 let py: i64 = dmy * 16
262 let qpMB: i64 = mbQP[mbA]
263 // ---- vertical edges ----
264 var ei: i64 = 0
265 while ei < 4 {
266 let eo: i64 = ve[ei]
267 let ex: i64 = px + eo
268 let qcol: i64 = dmx * 4 + eo / 4
269 var doit: i64 = 1
270 if eo == 0 { if dmx == 0 { doit = 0 } else { if didMB[mbA - 1] < 1 { doit = 0 } } }
271 if doit == 1 {
272 var qpe: i64 = qpMB
273 if eo == 0 { qpe = (mbQP[mbA - 1] + qpMB + 1) >> 1 }
274 var mbb: i64 = 0
275 if eo == 0 { mbb = 1 }
276 var seg: i64 = 0
277 while seg < 4 {
278 let row4: i64 = dmy * 4 + seg
279 let qblk: i64 = row4 * lbW + qcol
280 let pblk: i64 = row4 * lbW + (qcol - 1)
281 let bs: i64 = b_bs(g0r, g0x, g0y, g1r, g1x, g1y, lumaTC, pblk, qblk, mbb)
282 if bs > 0 {
283 var r: i64 = 0
284 while r < 4 {
285 let ry: i64 = seg * 4 + r
286 let base: i64 = (py + ry) * W + ex
287 s[0] = yf[base - 4] as i64; s[1] = yf[base - 3] as i64; s[2] = yf[base - 2] as i64; s[3] = yf[base - 1] as i64
288 s[4] = yf[base] as i64; s[5] = yf[base + 1] as i64; s[6] = yf[base + 2] as i64; s[7] = yf[base + 3] as i64
289 if bs == 4 { nx_deblock_luma_bs4(s, qpe) }
290 if bs < 4 { nx_deblock_luma_edge(s, bs, qpe) }
291 yf[base - 3] = s[1] as u8; yf[base - 2] = s[2] as u8; yf[base - 1] = s[3] as u8
292 yf[base] = s[4] as u8; yf[base + 1] = s[5] as u8; yf[base + 2] = s[6] as u8
293 r = r + 1
294 }
295 }
296 seg = seg + 1
297 }
298 }
299 ei = ei + 1
300 }
301 // ---- horizontal edges ----
302 ei = 0
303 while ei < 4 {
304 let eo: i64 = ve[ei]
305 let ey: i64 = py + eo
306 let qrow: i64 = dmy * 4 + eo / 4
307 var doit: i64 = 1
308 if eo == 0 { if dmy == 0 { doit = 0 } else { if didMB[mbA - mbW] < 1 { doit = 0 } } }
309 if doit == 1 {
310 var qpe: i64 = qpMB
311 if eo == 0 { qpe = (mbQP[mbA - mbW] + qpMB + 1) >> 1 }
312 var mbb: i64 = 0
313 if eo == 0 { mbb = 1 }
314 var seg: i64 = 0
315 while seg < 4 {
316 let col4: i64 = dmx * 4 + seg
317 let qblk: i64 = qrow * lbW + col4
318 let pblk: i64 = (qrow - 1) * lbW + col4
319 let bs: i64 = b_bs(g0r, g0x, g0y, g1r, g1x, g1y, lumaTC, pblk, qblk, mbb)
320 if bs > 0 {
321 var r: i64 = 0
322 while r < 4 {
323 let col: i64 = px + seg * 4 + r
324 s[0] = yf[(ey - 4) * W + col] as i64; s[1] = yf[(ey - 3) * W + col] as i64; s[2] = yf[(ey - 2) * W + col] as i64; s[3] = yf[(ey - 1) * W + col] as i64
325 s[4] = yf[ey * W + col] as i64; s[5] = yf[(ey + 1) * W + col] as i64; s[6] = yf[(ey + 2) * W + col] as i64; s[7] = yf[(ey + 3) * W + col] as i64
326 if bs == 4 { nx_deblock_luma_bs4(s, qpe) }
327 if bs < 4 { nx_deblock_luma_edge(s, bs, qpe) }
328 yf[(ey - 3) * W + col] = s[1] as u8; yf[(ey - 2) * W + col] = s[2] as u8; yf[(ey - 1) * W + col] = s[3] as u8
329 yf[ey * W + col] = s[4] as u8; yf[(ey + 1) * W + col] = s[5] as u8; yf[(ey + 2) * W + col] = s[6] as u8
330 r = r + 1
331 }
332 }
333 seg = seg + 1
334 }
335 }
336 ei = ei + 1
337 }
338 }
339 dmx = dmx + 1
340 }
341 dmy = dmy + 1
342 }
343 return 0
344}
345
346// ---- B-frame CHROMA reconstruction (B-R5) ----
347func cclampc(v: i64, hi: i64) -> i64 { if v < 0 { return 0 } if v > hi { return hi } return v }
348// 1/8-pel bilinear chroma sample from a reference chroma plane (8.4.2.2.2). mv = luma MV (1/4-luma-pel
349// == 1/8-chroma-pel since chroma is half-res).
350func chroma_mc_s(refC: *u8, cW: i64, cH: i64, cx: i64, cy: i64, mvx: i64, mvy: i64) -> i64 {
351 let xi: i64 = cx + asr(mvx, 3)
352 let yi: i64 = cy + asr(mvy, 3)
353 let xf: i64 = mvx & 7
354 let yf: i64 = mvy & 7
355 let x0: i64 = cclampc(xi, cW - 1)
356 let x1: i64 = cclampc(xi + 1, cW - 1)
357 let y0: i64 = cclampc(yi, cH - 1)
358 let y1: i64 = cclampc(yi + 1, cH - 1)
359 let A: i64 = refC[y0 * cW + x0] as i64
360 let Bv: i64 = refC[y0 * cW + x1] as i64
361 let Cv: i64 = refC[y1 * cW + x0] as i64
362 let Dv: i64 = refC[y1 * cW + x1] as i64
363 return ((8 - xf) * (8 - yf) * A + xf * (8 - yf) * Bv + (8 - xf) * yf * Cv + xf * yf * Dv + 32) >> 6
364}
365func chroma_qpc_b(qpL: i64, cqo: i64) -> i64 { var q: i64 = qpL + cqo; if q < 0 { q = 0 } if q > 51 { q = 51 } return nx_h264_chroma_qp(q) }
366// add the chroma residual (DC scaled + AC) for one 4x4 chroma block q to pred[16] -> myC, clipped.
367func chroma_add_res(myC: *u8, cpW: i64, bcx: i64, bcy: i64, pred: *i64, q: i64, sdc: *i64, ac4: *i64, cbpC: i64, QPc: i64) -> i64 {
368 let dq: *i64 = sys_mmap(16 * 8) as *i64
369 if cbpC >= 1 {
370 let scan: *i64 = sys_mmap(16 * 8) as *i64
371 var z: i64 = 0
372 while z < 16 { scan[z] = 0; z = z + 1 }
373 if cbpC == 2 { z = 0; while z < 15 { scan[1 + z] = ac4[q * 16 + z]; z = z + 1 } }
374 let rast: *i64 = sys_mmap(16 * 8) as *i64
375 nx_h264_inv_zigzag4x4(scan, rast)
376 nx_h264_dequant4x4(rast, QPc, dq)
377 dq[0] = sdc[q]
378 nx_idct4x4(dq)
379 }
380 var yy: i64 = 0
381 while yy < 4 {
382 var xx: i64 = 0
383 while xx < 4 {
384 var val: i64 = pred[yy * 4 + xx]
385 if cbpC >= 1 { val = val + dq[yy * 4 + xx] }
386 if val < 0 { val = 0 }
387 if val > 255 { val = 255 }
388 myC[(bcy + yy) * cpW + (bcx + xx)] = val as u8
389 xx = xx + 1
390 }
391 yy = yy + 1
392 }
393 return 0
394}
395// one chroma component (compOff = W*H for U, W*H+csz for V) of an INTER/SKIP B MB: per chroma sample,
396// bi-pred (or L0/L1) MC from the L0/L1 reference chroma planes via the persisted MV grids + residual.
397func recon_chroma_b_inter(myC: *u8, compOff: i64, gt: *u8, FS: i64, l0poc: *i64, l1poc: *i64, W: i64,
398 cpW: i64, cpH: i64, mbX: i64, mbY: i64, g0r: *i64, g0x: *i64, g0y: *i64,
399 g1r: *i64, g1x: *i64, g1y: *i64, lbW: i64, dc4: *i64, ac4: *i64, cbpC: i64, QPc: i64) -> i64 {
400 let sdc: *i64 = sys_mmap(4 * 8) as *i64
401 if cbpC >= 1 { nx_h264_chroma_dc_scale(dc4, QPc, sdc) }
402 var q: i64 = 0
403 while q < 4 {
404 let bcx: i64 = mbX * 8 + (q % 2) * 4
405 let bcy: i64 = mbY * 8 + (q / 2) * 4
406 let pred: *i64 = sys_mmap(16 * 8) as *i64
407 var yy: i64 = 0
408 while yy < 4 {
409 var xx: i64 = 0
410 while xx < 4 {
411 let cx: i64 = bcx + xx
412 let cy: i64 = bcy + yy
413 let blk: i64 = (cy / 2) * lbW + (cx / 2)
414 let uL0: i64 = (g0r[blk] >= 0) as i64
415 let uL1: i64 = (g1r[blk] >= 0) as i64
416 var v: i64 = 0
417 if uL0 == 1 {
418 let r0: *u8 = (gt as i64 + (l0poc[g0r[blk]] / 2) * FS + compOff) as *u8
419 let a: i64 = chroma_mc_s(r0, cpW, cpH, cx, cy, g0x[blk], g0y[blk])
420 if uL1 == 1 {
421 let r1: *u8 = (gt as i64 + (l1poc[g1r[blk]] / 2) * FS + compOff) as *u8
422 let bb: i64 = chroma_mc_s(r1, cpW, cpH, cx, cy, g1x[blk], g1y[blk])
423 v = (a + bb + 1) >> 1
424 }
425 if uL1 == 0 { v = a }
426 }
427 if uL0 == 0 { if uL1 == 1 {
428 let r1: *u8 = (gt as i64 + (l1poc[g1r[blk]] / 2) * FS + compOff) as *u8
429 v = chroma_mc_s(r1, cpW, cpH, cx, cy, g1x[blk], g1y[blk])
430 } }
431 pred[yy * 4 + xx] = v
432 xx = xx + 1
433 }
434 yy = yy + 1
435 }
436 chroma_add_res(myC, cpW, bcx, bcy, pred, q, sdc, ac4, cbpC, QPc)
437 q = q + 1
438 }
439 return 0
440}
441// one chroma component of an INTRA-in-B MB: intra chroma prediction from reconstructed neighbours + residual.
442func recon_chroma_b_intra(myC: *u8, cpW: i64, cpH: i64, mbX: i64, mbY: i64, mode: i64, availT: i64,
443 availL: i64, dc4: *i64, ac4: *i64, cbpC: i64, QPc: i64) -> i64 {
444 let bx0: i64 = mbX * 8
445 let by0: i64 = mbY * 8
446 let top: *i64 = sys_mmap(8 * 8) as *i64
447 let left: *i64 = sys_mmap(8 * 8) as *i64
448 var k: i64 = 0
449 while k < 8 {
450 var tv: i64 = 0
451 if availT == 1 { tv = myC[(by0 - 1) * cpW + (bx0 + k)] as i64 }
452 top[k] = tv
453 var lv: i64 = 0
454 if availL == 1 { lv = myC[(by0 + k) * cpW + (bx0 - 1)] as i64 }
455 left[k] = lv
456 k = k + 1
457 }
458 var tl: i64 = 0
459 if availT == 1 { if availL == 1 { tl = myC[(by0 - 1) * cpW + (bx0 - 1)] as i64 } }
460 let pred: *i64 = sys_mmap(64 * 8) as *i64
461 nx_intra_chroma_pred(mode, top, left, tl, availT, availL, pred)
462 let sdc: *i64 = sys_mmap(4 * 8) as *i64
463 if cbpC >= 1 { nx_h264_chroma_dc_scale(dc4, QPc, sdc) }
464 var q: i64 = 0
465 while q < 4 {
466 let qx: i64 = (q % 2) * 4
467 let qy: i64 = (q / 2) * 4
468 let p16: *i64 = sys_mmap(16 * 8) as *i64
469 var yy: i64 = 0
470 while yy < 4 {
471 var xx: i64 = 0
472 while xx < 4 { p16[yy * 4 + xx] = pred[(qy + yy) * 8 + (qx + xx)]; xx = xx + 1 }
473 yy = yy + 1
474 }
475 chroma_add_res(myC, cpW, bx0 + qx, by0 + qy, p16, q, sdc, ac4, cbpC, QPc)
476 q = q + 1
477 }
478 return 0
479}
480
481// B-frame CHROMA in-loop deblock (4:2:0): edges at chroma x/y in {0,4} (= luma {0,8}); bS = the B luma bS
482// (b_bs) at the co-located luma 4x4 boundary; qp = averaged chroma QPc. Filters p0/q0 via nx_deblock_chroma_edge.
483func deblock_chroma_b(myU: *u8, myV: *u8, cpW: i64, mbW: i64, mbH: i64, mbQP: *i64, cqo: i64,
484 g0r: *i64, g0x: *i64, g0y: *i64, g1r: *i64, g1x: *i64, g1y: *i64,
485 lumaTC: *i64, lbW: i64, didMB: *i64) -> i64 {
486 let s: *i64 = sys_mmap(8 * 8) as *i64
487 let ce: *i64 = sys_mmap(8 * 8) as *i64
488 ce[0] = 0; ce[1] = 4
489 var dmy: i64 = 0
490 while dmy < mbH {
491 var dmx: i64 = 0
492 while dmx < mbW {
493 let mbA: i64 = dmy * mbW + dmx
494 if didMB[mbA] >= 1 {
495 let cpx: i64 = dmx * 8
496 let cpy: i64 = dmy * 8
497 let qpcCur: i64 = chroma_qpc_b(mbQP[mbA], cqo)
498 var ei: i64 = 0
499 while ei < 2 {
500 let eo: i64 = ce[ei]
501 let ex: i64 = cpx + eo
502 let qcol: i64 = dmx * 4 + (eo / 4) * 2
503 var doit: i64 = 1
504 if eo == 0 { if dmx == 0 { doit = 0 } else { if didMB[mbA - 1] < 1 { doit = 0 } } }
505 if doit == 1 {
506 var qpe: i64 = qpcCur
507 if eo == 0 { qpe = (chroma_qpc_b(mbQP[mbA - 1], cqo) + qpcCur + 1) >> 1 }
508 var mbb: i64 = 0
509 if eo == 0 { mbb = 1 }
510 var k: i64 = 0
511 while k < 4 {
512 let row4: i64 = dmy * 4 + k
513 let qblk: i64 = row4 * lbW + qcol
514 let pblk: i64 = row4 * lbW + (qcol - 1)
515 let bs: i64 = b_bs(g0r, g0x, g0y, g1r, g1x, g1y, lumaTC, pblk, qblk, mbb)
516 if bs > 0 {
517 var r: i64 = 0
518 while r < 2 {
519 let base: i64 = (cpy + k * 2 + r) * cpW + ex
520 s[0] = myU[base - 2] as i64; s[1] = myU[base - 1] as i64; s[2] = myU[base] as i64; s[3] = myU[base + 1] as i64
521 nx_deblock_chroma_edge(s, bs, qpe)
522 myU[base - 1] = s[1] as u8; myU[base] = s[2] as u8
523 s[0] = myV[base - 2] as i64; s[1] = myV[base - 1] as i64; s[2] = myV[base] as i64; s[3] = myV[base + 1] as i64
524 nx_deblock_chroma_edge(s, bs, qpe)
525 myV[base - 1] = s[1] as u8; myV[base] = s[2] as u8
526 r = r + 1
527 }
528 }
529 k = k + 1
530 }
531 }
532 ei = ei + 1
533 }
534 ei = 0
535 while ei < 2 {
536 let eo: i64 = ce[ei]
537 let ey: i64 = cpy + eo
538 let qrow: i64 = dmy * 4 + (eo / 4) * 2
539 var doit: i64 = 1
540 if eo == 0 { if dmy == 0 { doit = 0 } else { if didMB[mbA - mbW] < 1 { doit = 0 } } }
541 if doit == 1 {
542 var qpe: i64 = qpcCur
543 if eo == 0 { qpe = (chroma_qpc_b(mbQP[mbA - mbW], cqo) + qpcCur + 1) >> 1 }
544 var mbb: i64 = 0
545 if eo == 0 { mbb = 1 }
546 var k: i64 = 0
547 while k < 4 {
548 let col4: i64 = dmx * 4 + k
549 let qblk: i64 = qrow * lbW + col4
550 let pblk: i64 = (qrow - 1) * lbW + col4
551 let bs: i64 = b_bs(g0r, g0x, g0y, g1r, g1x, g1y, lumaTC, pblk, qblk, mbb)
552 if bs > 0 {
553 var r: i64 = 0
554 while r < 2 {
555 let col: i64 = cpx + k * 2 + r
556 s[0] = myU[(ey - 2) * cpW + col] as i64; s[1] = myU[(ey - 1) * cpW + col] as i64; s[2] = myU[ey * cpW + col] as i64; s[3] = myU[(ey + 1) * cpW + col] as i64
557 nx_deblock_chroma_edge(s, bs, qpe)
558 myU[(ey - 1) * cpW + col] = s[1] as u8; myU[ey * cpW + col] = s[2] as u8
559 s[0] = myV[(ey - 2) * cpW + col] as i64; s[1] = myV[(ey - 1) * cpW + col] as i64; s[2] = myV[ey * cpW + col] as i64; s[3] = myV[(ey + 1) * cpW + col] as i64
560 nx_deblock_chroma_edge(s, bs, qpe)
561 myV[(ey - 1) * cpW + col] = s[1] as u8; myV[ey * cpW + col] = s[2] as u8
562 r = r + 1
563 }
564 }
565 k = k + 1
566 }
567 }
568 ei = ei + 1
569 }
570 }
571 dmx = dmx + 1
572 }
573 dmy = dmy + 1
574 }
575 return 0
576}
577
578func main() -> i64 {
579 let fd: i64 = sys_openat_append("knowledge/status/h264_brecon.log\x00" as *u8, 0x1a4)
580 gp(fd, "H264-BRECON (B-R3: explicit-MV bi-pred LUMA vs ffmpeg)\n\x00" as *u8)
581 let szp: *i64 = sys_mmap(16) as *i64
582 let b: *u8 = sys_read_file("knowledge/staging/media/bframe_test.264\x00" as *u8, szp)
583 if (b as i64) == 0 { gp(fd, "no bframe_test.264\n\x00" as *u8); sys_exit(1); return 1 }
584 let len: i64 = szp[0]
585 let gzp: *i64 = sys_mmap(16) as *i64
586 let gt: *u8 = sys_read_file("knowledge/staging/media/bframe_test_decoded.yuv\x00" as *u8, gzp)
587 if (gt as i64) == 0 { gp(fd, "no GT yuv\n\x00" as *u8); sys_exit(1); return 1 }
588
589 let offs: *i64 = sys_mmap(512 * 8) as *i64
590 let types: *i64 = sys_mmap(512 * 8) as *i64
591 let nc: i64 = nx_nal_split_annexb(b, 0, len, offs, types, 512)
592 let sps: *i64 = sys_mmap(128) as *i64
593 let pps: *i64 = sys_mmap(128) as *i64
594 var k: i64 = 0
595 while k < nc {
596 let noff: i64 = offs[k]
597 var nend: i64 = len
598 if k + 1 < nc { nend = offs[k + 1] - 3 }
599 if types[k] == 7 { let dst: *u8 = sys_mmap(nend - noff + 16); let rb: i64 = nx_h264_unescape_rbsp((b as i64 + noff + 1) as *u8, nend - noff - 1, dst); nx_h264_parse_sps(dst, rb, sps) }
600 if types[k] == 8 { let dst: *u8 = sys_mmap(nend - noff + 16); let rb: i64 = nx_h264_unescape_rbsp((b as i64 + noff + 1) as *u8, nend - noff - 1, dst); nx_h264_parse_pps(dst, rb, pps) }
601 k = k + 1
602 }
603 let W: i64 = sps[2]
604 let H: i64 = sps[3]
605 let mbW: i64 = W / 16
606 let mbH: i64 = H / 16
607 let totalMB: i64 = mbW * mbH
608 let FS: i64 = W * H + (W / 2) * (H / 2) * 2
609 let max_poc_lsb: i64 = 1 << sps[11]
610
611 // walk all slices: compute POC, maintain DPB; stop at first B-slice with its L0/L1 POC lists
612 let sh: *i64 = sys_mmap(64) as *i64
613 let state: *i64 = sys_mmap(16) as *i64
614 state[0] = 0; state[1] = 0
615 let dpbPoc: *i64 = sys_mmap(64 * 8) as *i64
616 let dpbIdx: *i64 = sys_mmap(64 * 8) as *i64
617 var dpbN: i64 = 0
618 let l0poc: *i64 = sys_mmap(64 * 8) as *i64
619 let l0ix: *i64 = sys_mmap(64 * 8) as *i64
620 let l1poc: *i64 = sys_mmap(64 * 8) as *i64
621 let l1ix: *i64 = sys_mmap(64 * 8) as *i64
622 var bk: i64 = 0 - 1
623 var bPoc: i64 = 0 - 1
624 var ak6: i64 = 0 - 1
625 k = 0
626 while k < nc {
627 let isSlice: i64 = (types[k] == 1) as i64 + (types[k] == 5) as i64
628 if isSlice >= 1 { if bk < 0 {
629 let noff: i64 = offs[k]
630 let hdr: i64 = b[noff] as i64
631 var nend: i64 = len
632 if k + 1 < nc { nend = offs[k + 1] - 3 }
633 let dst: *u8 = sys_mmap(nend - noff + 16)
634 let rb: i64 = nx_h264_unescape_rbsp((b as i64 + noff + 1) as *u8, nend - noff - 1, dst)
635 let br: *BitReader = sys_mmap(NX_BR_BYTES) as *BitReader
636 br_init(br, dst, rb)
637 nx_h264_parse_slice_header_br(br, hdr & 31, (hdr >> 5) & 3, sps[9], sps[11], sps[10], sps[6], pps[3], pps[6], sh)
638 let is_idr: i64 = (hdr & 31) == 5
639 let poc: i64 = nx_h264_poc_type0(sh[5], max_poc_lsb, is_idr, (hdr >> 5) & 3, state)
640 if poc == 6 { if sh[8] == 0 { if ak6 < 0 { ak6 = k } } }
641 if sh[8] == 1 { if bk < 0 {
642 bk = k; bPoc = poc
643 nx_h264_build_blists(dpbPoc, dpbIdx, dpbN, poc, l0poc, l0ix, l1poc, l1ix)
644 } }
645 if ((hdr >> 5) & 3) != 0 { dpbPoc[dpbN] = poc; dpbIdx[dpbN] = dpbN; dpbN = dpbN + 1 }
646 } }
647 k = k + 1
648 }
649 if bk < 0 { gp(fd, "no B-slice\n\x00" as *u8); sys_exit(1); return 1 }
650 gp(fd, " B POC=\x00" as *u8); gn(fd, bPoc); gp(fd, " L0[0]poc=\x00" as *u8); gn(fd, l0poc[0]); gp(fd, " L1[0]poc=\x00" as *u8); gn(fd, l1poc[0]); gp(fd, "\n\x00" as *u8)
651
652 // target B frame + the two ref-list frame-pointer tables (POC->display = POC/2)
653 let tgtY: *u8 = (gt as i64 + (bPoc / 2) * FS) as *u8
654
655 // re-parse the chosen B-slice for the MB walk
656 let noff: i64 = offs[bk]
657 let hdr: i64 = b[noff] as i64
658 var nend: i64 = len
659 if bk + 1 < nc { nend = offs[bk + 1] - 3 }
660 let sl_dst: *u8 = sys_mmap(nend - noff + 16)
661 let sl_rbsp: i64 = nx_h264_unescape_rbsp((b as i64 + noff + 1) as *u8, nend - noff - 1, sl_dst)
662 let sbr: *BitReader = sys_mmap(NX_BR_BYTES) as *BitReader
663 br_init(sbr, sl_dst, sl_rbsp)
664 nx_h264_parse_slice_header_br(sbr, hdr & 31, (hdr >> 5) & 3, sps[9], sps[11], sps[10], sps[6], pps[3], pps[6], sh)
665 let num_ref_l0: i64 = sh[12] + 1
666 let num_ref_l1: i64 = sh[13] + 1
667
668 let lbW: i64 = mbW * 4
669 let lbH: i64 = mbH * 4
670 // ---- co-located MV field from the future anchor (POC6 = L1[0]) for spatial-direct ----
671 let colR: *i64 = sys_mmap(lbW * lbH * 8) as *i64
672 let colMx: *i64 = sys_mmap(lbW * lbH * 8) as *i64
673 let colMy: *i64 = sys_mmap(lbW * lbH * 8) as *i64
674 var zc6: i64 = 0
675 while zc6 < lbW * lbH { colR[zc6] = 0 - 2; colMx[zc6] = 0; colMy[zc6] = 0; zc6 = zc6 + 1 }
676 if ak6 >= 0 {
677 let cnoff: i64 = offs[ak6]
678 let chdr: i64 = b[cnoff] as i64
679 var cnend: i64 = len
680 if ak6 + 1 < nc { cnend = offs[ak6 + 1] - 3 }
681 let c_dst: *u8 = sys_mmap(cnend - cnoff + 16)
682 let c_rbsp: i64 = nx_h264_unescape_rbsp((b as i64 + cnoff + 1) as *u8, cnend - cnoff - 1, c_dst)
683 let cbr: *BitReader = sys_mmap(NX_BR_BYTES) as *BitReader
684 br_init(cbr, c_dst, c_rbsp)
685 let csh: *i64 = sys_mmap(64) as *i64
686 nx_h264_parse_slice_header_br(cbr, chdr & 31, (chdr >> 5) & 3, sps[9], sps[11], sps[10], sps[6], pps[3], pps[6], csh)
687 nx_h264_pslice_mvfield(cbr, csh[7], csh[12] + 1, mbW, mbH, colR, colMx, colMy)
688 }
689 let lumaTC: *i64 = sys_mmap(lbW * lbH * 8) as *i64
690 let cbW: i64 = mbW * 2
691 let cbH: i64 = mbH * 2
692 let uTC: *i64 = sys_mmap(cbW * cbH * 8) as *i64
693 let vTC: *i64 = sys_mmap(cbW * cbH * 8) as *i64
694 var z: i64 = 0
695 while z < lbW * lbH { lumaTC[z] = 0; z = z + 1 }
696 z = 0
697 while z < cbW * cbH { uTC[z] = 0; vTC[z] = 0; z = z + 1 }
698 // two-list MV grids (gref: -2 undecoded, -1 decoded-no-this-list, >=0 ref idx)
699 let g0x: *i64 = sys_mmap(lbW*lbH*8) as *i64
700 let g0y: *i64 = sys_mmap(lbW*lbH*8) as *i64
701 let g0r: *i64 = sys_mmap(lbW*lbH*8) as *i64
702 let g1x: *i64 = sys_mmap(lbW*lbH*8) as *i64
703 let g1y: *i64 = sys_mmap(lbW*lbH*8) as *i64
704 let g1r: *i64 = sys_mmap(lbW*lbH*8) as *i64
705 z = 0
706 while z < lbW*lbH { g0x[z]=0; g0y[z]=0; g0r[z]=0-2; g1x[z]=0; g1y[z]=0; g1r[z]=0-2; z = z + 1 }
707 // intra-in-B reconstruction state: per-4x4 intra4x4 pred-mode (DC=2 default so inter neighbours
708 // contribute DC to mode prediction, per 8.3.1.1) + the I_16x16 AC scan store. A block is "decoded"
709 // (available for intra pred, constrained_intra_pred=0 here) iff g0r != -2.
710 let i4m: *i64 = sys_mmap(lbW*lbH*8) as *i64
711 z = 0
712 while z < lbW*lbH { i4m[z] = 2; z = z + 1 }
713 let acstore: *i64 = sys_mmap(256*8) as *i64
714 // which MBs we reconstructed (explicit) -> include in compare
715 let didMB: *i64 = sys_mmap(totalMB*8) as *i64
716 z = 0
717 while z < totalMB { didMB[z] = 0; z = z + 1 }
718 // per-MB luma QP (for the deblock edge-QP averaging); init to the slice QP, overwritten per recon MB.
719 let mbQP: *i64 = sys_mmap(totalMB*8) as *i64
720 z = 0
721 while z < totalMB { mbQP[z] = sh[7]; z = z + 1 }
722 let myY: *u8 = sys_mmap(W*H+16)
723 let cpW: i64 = W / 2
724 let cpH: i64 = H / 2
725 let csz: i64 = cpW * cpH
726 let myU: *u8 = sys_mmap(csz + 16)
727 let myV: *u8 = sys_mmap(csz + 16)
728 let cCbpC: *i64 = sys_mmap(totalMB * 8 + 64) as *i64
729 let cIsIntra: *i64 = sys_mmap(totalMB * 8 + 64) as *i64
730 let cCMode: *i64 = sys_mmap(totalMB * 8 + 64) as *i64
731 let cUdc: *i64 = sys_mmap(totalMB * 4 * 8 + 64) as *i64
732 let cVdc: *i64 = sys_mmap(totalMB * 4 * 8 + 64) as *i64
733 let cUac: *i64 = sys_mmap(totalMB * 64 * 8 + 64) as *i64
734 let cVac: *i64 = sys_mmap(totalMB * 64 * 8 + 64) as *i64
735 z = 0
736 while z < W*H { myY[z] = 0 as u8; z = z + 1 }
737
738 let bx4: *i64 = sys_mmap(16 * 8) as *i64
739 let by4: *i64 = sys_mmap(16 * 8) as *i64
740 bx4[0]=0; by4[0]=0; bx4[1]=1; by4[1]=0; bx4[2]=0; by4[2]=1; bx4[3]=1; by4[3]=1
741 bx4[4]=2; by4[4]=0; bx4[5]=3; by4[5]=0; bx4[6]=2; by4[6]=1; bx4[7]=3; by4[7]=1
742 bx4[8]=0; by4[8]=2; bx4[9]=1; by4[9]=2; bx4[10]=0; by4[10]=3; bx4[11]=1; by4[11]=3
743 bx4[12]=2; by4[12]=2; bx4[13]=3; by4[13]=2; bx4[14]=2; by4[14]=3; bx4[15]=3; by4[15]=3
744
745 let coeff: *i64 = sys_mmap(32 * 8) as *i64
746 let mvp: *i64 = sys_mmap(16) as *i64
747 let subs: *i64 = sys_mmap(8 * 8) as *i64
748 let dparams: *i64 = sys_mmap(8 * 8) as *i64
749 var qp: i64 = sh[7]
750 var ok: i64 = 1
751 var nExpl: i64 = 0
752 // census of the not-yet-reconstructed MB kinds (defines the next recon rung)
753 var nB8: i64 = 0
754 var nB8sub: i64 = 0
755 var nIntraB: i64 = 0
756 let subHist: *i64 = sys_mmap(16 * 8) as *i64
757 var sh0: i64 = 0
758 while sh0 < 16 { subHist[sh0] = 0; sh0 = sh0 + 1 }
759 var mbAddr: i64 = 0
760 while mbAddr < totalMB {
761 if ok == 0 { mbAddr = totalMB } else {
762 let skip_run: i64 = br_read_ue(sbr)
763 var s2: i64 = 0
764 while s2 < skip_run {
765 if mbAddr < totalMB {
766 let mbX: i64 = mbAddr % mbW
767 let mbY: i64 = mbAddr / mbW
768 // B_Skip = spatial-direct, no residual
769 b_direct_params(g0r, g0x, g0y, g1r, g1x, g1y, lbW, lbH, mbX, mbY, dparams)
770 var bl: i64 = 0
771 while bl < 16 {
772 let abx: i64 = mbX * 4 + bx4[bl]
773 let aby: i64 = mbY * 4 + by4[bl]
774 b_direct_fill4(g0r, g0x, g0y, g1r, g1x, g1y, lbW, colR, colMx, colMy, abx, aby, dparams)
775 let uL0: i64 = (g0r[aby*lbW+abx] >= 0) as i64
776 let uL1: i64 = (g1r[aby*lbW+abx] >= 0) as i64
777 var rl0: *u8 = tgtY
778 var rl1: *u8 = tgtY
779 if uL0 == 1 { rl0 = (gt as i64 + (l0poc[g0r[aby*lbW+abx]] / 2) * FS) as *u8 }
780 if uL1 == 1 { rl1 = (gt as i64 + (l1poc[g1r[aby*lbW+abx]] / 2) * FS) as *u8 }
781 recon_b_4x4(myY, W, H, rl0, rl1, abx*4, aby*4, uL0, g0x[aby*lbW+abx], g0y[aby*lbW+abx], uL1, g1x[aby*lbW+abx], g1y[aby*lbW+abx], coeff, qp, 0)
782 lumaTC[aby * lbW + abx] = 0
783 bl = bl + 1
784 }
785 var cc: i64 = 0
786 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 }
787 mbQP[mbAddr] = qp
788 didMB[mbAddr] = 1
789 mbAddr = mbAddr + 1
790 }
791 s2 = s2 + 1
792 }
793 if mbAddr < totalMB {
794 let mbX: i64 = mbAddr % mbW
795 let mbY: i64 = mbAddr / mbW
796 let bx0: i64 = mbX * 4
797 let by0: i64 = mbY * 4
798 let mb_type: i64 = br_read_ue(sbr)
799 let bt: i64 = nx_h264_bmb_kind(mb_type)
800 var explicit: i64 = 0
801 if bt > 0 { if nx_h264_bmb_is_8x8(bt) == 0 { explicit = 1 } } // bt 1..21 = explicit non-8x8
802 if bt >= 0 {
803 if explicit == 1 {
804 let np: i64 = nx_h264_bmb_nparts(bt)
805 let refs0: *i64 = sys_mmap(8*8) as *i64
806 let refs1: *i64 = sys_mmap(8*8) as *i64
807 var p: i64 = 0
808 while p < np { refs0[p] = 0; refs1[p] = 0; p = p + 1 }
809 // ref_idx L0 then L1
810 if num_ref_l0 > 1 { p = 0; while p < np { if nx_h264_mode_uses_l0(nx_h264_bmb_partmode(bt,p)) == 1 { refs0[p] = read_ref(sbr, num_ref_l0) } p = p + 1 } }
811 if num_ref_l1 > 1 { p = 0; while p < np { if nx_h264_mode_uses_l1(nx_h264_bmb_partmode(bt,p)) == 1 { refs1[p] = read_ref(sbr, num_ref_l1) } p = p + 1 } }
812 // partition geometry
813 let pw: i64 = 4
814 let shape: i64 = 0
815 // mvd L0 then L1: compute per partition, fill grids
816 let mv0x: *i64 = sys_mmap(8*8) as *i64
817 let mv0y: *i64 = sys_mmap(8*8) as *i64
818 let mv1x: *i64 = sys_mmap(8*8) as *i64
819 let mv1y: *i64 = sys_mmap(8*8) as *i64
820 // partition rectangles (px,py,pw,ph) in 4x4 units
821 let ppx: *i64 = sys_mmap(8*8) as *i64
822 let ppy: *i64 = sys_mmap(8*8) as *i64
823 let ppw: *i64 = sys_mmap(8*8) as *i64
824 let pph: *i64 = sys_mmap(8*8) as *i64
825 var psh: i64 = 0
826 if np == 1 { ppx[0]=bx0; ppy[0]=by0; ppw[0]=4; pph[0]=4; psh = 0 }
827 if np == 2 { if nx_h264_bmb_is_16x8(bt) == 1 { ppx[0]=bx0; ppy[0]=by0; ppw[0]=4; pph[0]=2; ppx[1]=bx0; ppy[1]=by0+2; ppw[1]=4; pph[1]=2; psh = 1 } }
828 if np == 2 { if nx_h264_bmb_is_16x8(bt) == 0 { ppx[0]=bx0; ppy[0]=by0; ppw[0]=2; pph[0]=4; ppx[1]=bx0+2; ppy[1]=by0; ppw[1]=2; pph[1]=4; psh = 2 } }
829 // pre-mark whole MB decoded-no-mv(-1) in both lists so intra-MB partition mvp sees correct neighbours
830 var pm: i64 = 0
831 while pm < 16 {
832 let pax: i64 = bx0 + bx4[pm]
833 let pay: i64 = by0 + by4[pm]
834 g0r[pay*lbW+pax] = 0 - 1; g0x[pay*lbW+pax] = 0; g0y[pay*lbW+pax] = 0
835 g1r[pay*lbW+pax] = 0 - 1; g1x[pay*lbW+pax] = 0; g1y[pay*lbW+pax] = 0
836 pm = pm + 1
837 }
838 // L0 mvds
839 p = 0
840 while p < np { if nx_h264_mode_uses_l0(nx_h264_bmb_partmode(bt,p)) == 1 {
841 let dx: i64 = br_read_se(sbr); let dy: i64 = br_read_se(sbr)
842 if psh == 0 { nx_mvg_part_mvp(g0r, g0x, g0y, lbW, lbH, ppx[p], ppy[p], ppw[p], refs0[p], 0, 0, mvp) }
843 if psh != 0 { nx_mvg_part_mvp(g0r, g0x, g0y, lbW, lbH, ppx[p], ppy[p], ppw[p], refs0[p], psh, p, mvp) }
844 mv0x[p] = mvp[0] + dx; mv0y[p] = mvp[1] + dy
845 nx_mvg_fill(g0r, g0x, g0y, lbW, ppx[p], ppy[p], ppw[p], pph[p], refs0[p], mv0x[p], mv0y[p])
846 } p = p + 1 }
847 // L1 mvds
848 p = 0
849 while p < np { if nx_h264_mode_uses_l1(nx_h264_bmb_partmode(bt,p)) == 1 {
850 let dx: i64 = br_read_se(sbr); let dy: i64 = br_read_se(sbr)
851 if psh == 0 { nx_mvg_part_mvp(g1r, g1x, g1y, lbW, lbH, ppx[p], ppy[p], ppw[p], refs1[p], 0, 0, mvp) }
852 if psh != 0 { nx_mvg_part_mvp(g1r, g1x, g1y, lbW, lbH, ppx[p], ppy[p], ppw[p], refs1[p], psh, p, mvp) }
853 mv1x[p] = mvp[0] + dx; mv1y[p] = mvp[1] + dy
854 nx_mvg_fill(g1r, g1x, g1y, lbW, ppx[p], ppy[p], ppw[p], pph[p], refs1[p], mv1x[p], mv1y[p])
855 } p = p + 1 }
856 // for partitions NOT using a list, mark that list decoded-no-mv (-1)
857 p = 0
858 while p < np {
859 if nx_h264_mode_uses_l0(nx_h264_bmb_partmode(bt,p)) == 0 { nx_mvg_fill(g0r, g0x, g0y, lbW, ppx[p], ppy[p], ppw[p], pph[p], 0-1, 0, 0) }
860 if nx_h264_mode_uses_l1(nx_h264_bmb_partmode(bt,p)) == 0 { nx_mvg_fill(g1r, g1x, g1y, lbW, ppx[p], ppy[p], ppw[p], pph[p], 0-1, 0, 0) }
861 p = p + 1
862 }
863 // CBP + residual + RECON per 4x4
864 let cbp: i64 = nx_h264_decode_cbp_inter(sbr)
865 let cbpL: i64 = cbp & 15
866 let cbpC: i64 = (cbp >> 4) & 3
867 if cbp != 0 { let mqd: i64 = br_read_se(sbr); qp = (qp + mqd + 52) % 52 }
868 var bl: i64 = 0
869 while bl < 16 {
870 let abx: i64 = bx0 + bx4[bl]
871 let aby: i64 = by0 + by4[bl]
872 let i8: i64 = bl / 4
873 let uL0: i64 = (g0r[aby*lbW+abx] >= 0) as i64
874 let uL1: i64 = (g1r[aby*lbW+abx] >= 0) as i64
875 // reference frames (POC -> display = POC/2)
876 var rl0: *u8 = tgtY
877 var rl1: *u8 = tgtY
878 if uL0 == 1 { rl0 = (gt as i64 + (l0poc[g0r[aby*lbW+abx]] / 2) * FS) as *u8 }
879 if uL1 == 1 { rl1 = (gt as i64 + (l1poc[g1r[aby*lbW+abx]] / 2) * FS) as *u8 }
880 var hasRes: i64 = 0
881 if ((cbpL >> i8) & 1) != 0 { dec_luma(sbr, lumaTC, lbW, abx, aby, 16, coeff); hasRes = 1 }
882 if ((cbpL >> i8) & 1) == 0 { lumaTC[aby * lbW + abx] = 0 }
883 recon_b_4x4(myY, W, H, rl0, rl1, abx*4, aby*4, uL0, g0x[aby*lbW+abx], g0y[aby*lbW+abx], uL1, g1x[aby*lbW+abx], g1y[aby*lbW+abx], coeff, qp, hasRes)
884 bl = bl + 1
885 }
886 cCbpC[mbAddr] = cbpC
887 if cbpC != 0 {
888 let ucdc: *i64 = sys_mmap(8 * 8) as *i64
889 nx_h264_residual_decode_cdc(sbr, ucdc)
890 let vcdc: *i64 = sys_mmap(8 * 8) as *i64
891 nx_h264_residual_decode_cdc(sbr, vcdc)
892 var zd: i64 = 0
893 while zd < 4 { cUdc[mbAddr*4+zd] = ucdc[zd]; cVdc[mbAddr*4+zd] = vcdc[zd]; zd = zd + 1 }
894 if cbpC == 2 {
895 var cc: i64 = 0
896 while cc < 4 { dec_cac(sbr, uTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); var zq: i64 = 0; while zq < 15 { cUac[mbAddr*64+cc*16+zq] = coeff[zq]; zq = zq + 1 } cc = cc + 1 }
897 cc = 0
898 while cc < 4 { dec_cac(sbr, vTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); var zq: i64 = 0; while zq < 15 { cVac[mbAddr*64+cc*16+zq] = coeff[zq]; zq = zq + 1 } cc = cc + 1 }
899 }
900 }
901 if cbpC == 0 { var cc: i64 = 0; 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 } }
902 mbQP[mbAddr] = qp
903 didMB[mbAddr] = 3
904 nExpl = nExpl + 1
905 }
906 if explicit == 0 { if bt == 0 {
907 // B_Direct_16x16: spatial-direct fill + bi-pred MC + residual
908 b_direct_params(g0r, g0x, g0y, g1r, g1x, g1y, lbW, lbH, mbX, mbY, dparams)
909 var bf: i64 = 0
910 while bf < 16 { b_direct_fill4(g0r, g0x, g0y, g1r, g1x, g1y, lbW, colR, colMx, colMy, bx0 + bx4[bf], by0 + by4[bf], dparams); bf = bf + 1 }
911 let cbp: i64 = nx_h264_decode_cbp_inter(sbr)
912 let cbpL: i64 = cbp & 15
913 let cbpC: i64 = (cbp >> 4) & 3
914 if cbp != 0 { let mqd: i64 = br_read_se(sbr); qp = (qp + mqd + 52) % 52 }
915 var bl: i64 = 0
916 while bl < 16 {
917 let abx: i64 = bx0 + bx4[bl]
918 let aby: i64 = by0 + by4[bl]
919 let i8: i64 = bl / 4
920 let uL0: i64 = (g0r[aby*lbW+abx] >= 0) as i64
921 let uL1: i64 = (g1r[aby*lbW+abx] >= 0) as i64
922 var rl0: *u8 = tgtY
923 var rl1: *u8 = tgtY
924 if uL0 == 1 { rl0 = (gt as i64 + (l0poc[g0r[aby*lbW+abx]] / 2) * FS) as *u8 }
925 if uL1 == 1 { rl1 = (gt as i64 + (l1poc[g1r[aby*lbW+abx]] / 2) * FS) as *u8 }
926 var hasRes: i64 = 0
927 if ((cbpL >> i8) & 1) != 0 { dec_luma(sbr, lumaTC, lbW, abx, aby, 16, coeff); hasRes = 1 }
928 if ((cbpL >> i8) & 1) == 0 { lumaTC[aby * lbW + abx] = 0 }
929 recon_b_4x4(myY, W, H, rl0, rl1, abx*4, aby*4, uL0, g0x[aby*lbW+abx], g0y[aby*lbW+abx], uL1, g1x[aby*lbW+abx], g1y[aby*lbW+abx], coeff, qp, hasRes)
930 bl = bl + 1
931 }
932 cCbpC[mbAddr] = cbpC
933 if cbpC != 0 {
934 let ud: *i64 = sys_mmap(8*8) as *i64; nx_h264_residual_decode_cdc(sbr, ud)
935 let vd: *i64 = sys_mmap(8*8) as *i64; nx_h264_residual_decode_cdc(sbr, vd)
936 var zd: i64 = 0; while zd < 4 { cUdc[mbAddr*4+zd] = ud[zd]; cVdc[mbAddr*4+zd] = vd[zd]; zd = zd + 1 }
937 if cbpC == 2 { var cc: i64 = 0; while cc < 4 { dec_cac(sbr, uTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); var zq: i64=0; while zq<15 { cUac[mbAddr*64+cc*16+zq]=coeff[zq]; zq=zq+1 } cc = cc + 1 } cc = 0; while cc < 4 { dec_cac(sbr, vTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); var zq: i64=0; while zq<15 { cVac[mbAddr*64+cc*16+zq]=coeff[zq]; zq=zq+1 } cc = cc + 1 } }
938 }
939 if cbpC == 0 { var cc: i64 = 0; 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 } }
940 mbQP[mbAddr] = qp
941 didMB[mbAddr] = 2
942 } }
943 if explicit == 0 { if bt == 22 {
944 // B_8x8 RECONSTRUCTION (whole-8x8 + Direct sub-MBs; census-verified: no sub-partitions in
945 // this stream). Each sub-MB is one 8x8 partition -> plain-median MV predictor (part_shape 0).
946 var si: i64 = 0
947 while si < 4 { subs[si] = br_read_ue(sbr); si = si + 1 }
948 nB8 = nB8 + 1
949 si = 0
950 while si < 4 { if subs[si] >= 0 { if subs[si] < 13 { subHist[subs[si]] = subHist[subs[si]] + 1 } } if subs[si] > 3 { nB8sub = nB8sub + 1 } si = si + 1 }
951 let sref0: *i64 = sys_mmap(8*8) as *i64
952 let sref1: *i64 = sys_mmap(8*8) as *i64
953 let sdx0: *i64 = sys_mmap(8*8) as *i64
954 let sdy0: *i64 = sys_mmap(8*8) as *i64
955 let sdx1: *i64 = sys_mmap(8*8) as *i64
956 let sdy1: *i64 = sys_mmap(8*8) as *i64
957 si = 0
958 while si < 4 { sref0[si]=0; sref1[si]=0; sdx0[si]=0; sdy0[si]=0; sdx1[si]=0; sdy1[si]=0; si = si + 1 }
959 // ref_idx (L0 batch then L1 batch), in sub-MB order, only for non-direct list-using sub-MBs
960 if num_ref_l0 > 1 { si = 0; while si < 4 { if nx_h264_bsub_is_direct(subs[si]) == 0 { if nx_h264_mode_uses_l0(nx_h264_bsub_mode(subs[si])) == 1 { sref0[si] = read_ref(sbr, num_ref_l0) } } si = si + 1 } }
961 if num_ref_l1 > 1 { si = 0; while si < 4 { if nx_h264_bsub_is_direct(subs[si]) == 0 { if nx_h264_mode_uses_l1(nx_h264_bsub_mode(subs[si])) == 1 { sref1[si] = read_ref(sbr, num_ref_l1) } } si = si + 1 } }
962 // mvd (L0 batch then L1 batch); whole-8x8 -> exactly one mvd pair per list-using sub-MB
963 si = 0
964 while si < 4 { if nx_h264_bsub_is_direct(subs[si]) == 0 { if nx_h264_mode_uses_l0(nx_h264_bsub_mode(subs[si])) == 1 { sdx0[si] = br_read_se(sbr); sdy0[si] = br_read_se(sbr) } } si = si + 1 }
965 si = 0
966 while si < 4 { if nx_h264_bsub_is_direct(subs[si]) == 0 { if nx_h264_mode_uses_l1(nx_h264_bsub_mode(subs[si])) == 1 { sdx1[si] = br_read_se(sbr); sdy1[si] = br_read_se(sbr) } } si = si + 1 }
967 // pre-mark whole MB decoded-no-mv(-1) in both lists (predictor sees in-MB neighbours)
968 var pm: i64 = 0
969 while pm < 16 { let pax: i64 = bx0 + bx4[pm]; let pay: i64 = by0 + by4[pm]; g0r[pay*lbW+pax]=0-1; g0x[pay*lbW+pax]=0; g0y[pay*lbW+pax]=0; g1r[pay*lbW+pax]=0-1; g1x[pay*lbW+pax]=0; g1y[pay*lbW+pax]=0; pm = pm + 1 }
970 // spatial-direct params (MB-level) for any Direct_8x8 sub-MBs
971 b_direct_params(g0r, g0x, g0y, g1r, g1x, g1y, lbW, lbH, mbX, mbY, dparams)
972 // fill MVs per sub-MB in raster order (0,1,2,3) so each median predictor sees earlier sub-MBs
973 si = 0
974 while si < 4 {
975 let sx: i64 = si % 2
976 let sy: i64 = si / 2
977 let sbx: i64 = bx0 + sx * 2
978 let sby: i64 = by0 + sy * 2
979 if nx_h264_bsub_is_direct(subs[si]) == 1 {
980 b_direct_fill4(g0r, g0x, g0y, g1r, g1x, g1y, lbW, colR, colMx, colMy, sbx, sby, dparams)
981 b_direct_fill4(g0r, g0x, g0y, g1r, g1x, g1y, lbW, colR, colMx, colMy, sbx+1, sby, dparams)
982 b_direct_fill4(g0r, g0x, g0y, g1r, g1x, g1y, lbW, colR, colMx, colMy, sbx, sby+1, dparams)
983 b_direct_fill4(g0r, g0x, g0y, g1r, g1x, g1y, lbW, colR, colMx, colMy, sbx+1, sby+1, dparams)
984 }
985 if nx_h264_bsub_is_direct(subs[si]) == 0 {
986 let smode: i64 = nx_h264_bsub_mode(subs[si])
987 if nx_h264_mode_uses_l0(smode) == 1 {
988 nx_mvg_part_mvp(g0r, g0x, g0y, lbW, lbH, sbx, sby, 2, sref0[si], 0, 0, mvp)
989 nx_mvg_fill(g0r, g0x, g0y, lbW, sbx, sby, 2, 2, sref0[si], mvp[0] + sdx0[si], mvp[1] + sdy0[si])
990 }
991 if nx_h264_mode_uses_l1(smode) == 1 {
992 nx_mvg_part_mvp(g1r, g1x, g1y, lbW, lbH, sbx, sby, 2, sref1[si], 0, 0, mvp)
993 nx_mvg_fill(g1r, g1x, g1y, lbW, sbx, sby, 2, 2, sref1[si], mvp[0] + sdx1[si], mvp[1] + sdy1[si])
994 }
995 }
996 si = si + 1
997 }
998 // CBP + residual + RECON per 4x4 (same bi-pred MC path as the explicit branch)
999 let cbp: i64 = nx_h264_decode_cbp_inter(sbr)
1000 let cbpL: i64 = cbp & 15
1001 let cbpC: i64 = (cbp >> 4) & 3
1002 if cbp != 0 { let mqd: i64 = br_read_se(sbr); qp = (qp + mqd + 52) % 52 }
1003 var bl: i64 = 0
1004 while bl < 16 {
1005 let abx: i64 = bx0 + bx4[bl]; let aby: i64 = by0 + by4[bl]; let i8: i64 = bl / 4
1006 let uL0: i64 = (g0r[aby*lbW+abx] >= 0) as i64
1007 let uL1: i64 = (g1r[aby*lbW+abx] >= 0) as i64
1008 var rl0: *u8 = tgtY
1009 var rl1: *u8 = tgtY
1010 if uL0 == 1 { rl0 = (gt as i64 + (l0poc[g0r[aby*lbW+abx]] / 2) * FS) as *u8 }
1011 if uL1 == 1 { rl1 = (gt as i64 + (l1poc[g1r[aby*lbW+abx]] / 2) * FS) as *u8 }
1012 var hasRes: i64 = 0
1013 if ((cbpL >> i8) & 1) != 0 { dec_luma(sbr, lumaTC, lbW, abx, aby, 16, coeff); hasRes = 1 }
1014 if ((cbpL >> i8) & 1) == 0 { lumaTC[aby * lbW + abx] = 0 }
1015 recon_b_4x4(myY, W, H, rl0, rl1, abx*4, aby*4, uL0, g0x[aby*lbW+abx], g0y[aby*lbW+abx], uL1, g1x[aby*lbW+abx], g1y[aby*lbW+abx], coeff, qp, hasRes)
1016 bl = bl + 1
1017 }
1018 cCbpC[mbAddr] = cbpC
1019 if cbpC != 0 {
1020 let u3: *i64 = sys_mmap(8*8) as *i64; nx_h264_residual_decode_cdc(sbr, u3)
1021 let v3: *i64 = sys_mmap(8*8) as *i64; nx_h264_residual_decode_cdc(sbr, v3)
1022 var zd: i64 = 0; while zd < 4 { cUdc[mbAddr*4+zd] = u3[zd]; cVdc[mbAddr*4+zd] = v3[zd]; zd = zd + 1 }
1023 if cbpC == 2 { var cc: i64 = 0; while cc < 4 { dec_cac(sbr, uTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); var zq: i64=0; while zq<15 { cUac[mbAddr*64+cc*16+zq]=coeff[zq]; zq=zq+1 } cc = cc + 1 } cc = 0; while cc < 4 { dec_cac(sbr, vTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); var zq: i64=0; while zq<15 { cVac[mbAddr*64+cc*16+zq]=coeff[zq]; zq=zq+1 } cc = cc + 1 } }
1024 }
1025 if cbpC == 0 { var cc: i64 = 0; 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 } }
1026 mbQP[mbAddr] = qp
1027 didMB[mbAddr] = 4
1028 } }
1029 }
1030 if bt < 0 {
1031 // intra-in-B RECONSTRUCTION (reuses the proven intra kernels). constrained_intra_pred=0 here,
1032 // so inter neighbours are usable -> a 4x4 is "available" iff its grid is decoded (g0r != -2).
1033 // didMB=5; grids set to -1 per block as reconstructed (so within-MB neighbours are available
1034 // in scan order, and the deblock sees these as intra: g0r=g1r=-1 -> b_bs bS 4/3).
1035 nIntraB = nIntraB + 1
1036 let it: i64 = mb_type - 23
1037 let cls: i64 = nx_h264_mb_type_class(it)
1038 if cls == 1 {
1039 // I_16x16: whole-MB pred (V/H/DC/Plane) + luma-DC Hadamard + per-4x4 AC residual
1040 let der: *i64 = sys_mmap(32) as *i64
1041 nx_h264_i16x16_derive(it, der)
1042 let cbpL: i64 = der[2]; let cbpC: i64 = der[1]
1043 cIsIntra[mbAddr] = 1; cCMode[mbAddr] = br_read_ue(sbr) // intra_chroma_pred_mode (captured)
1044 let mqd: i64 = br_read_se(sbr); qp = (qp + mqd + 52) % 52
1045 var nA: i64 = 0; var avA: i64 = 0
1046 if bx0 > 0 { nA = lumaTC[by0 * lbW + (bx0 - 1)]; avA = 1 }
1047 var nB: i64 = 0; var avB: i64 = 0
1048 if by0 > 0 { nB = lumaTC[(by0 - 1) * lbW + bx0]; avB = 1 }
1049 let nCdc: i64 = nx_h264_nc_luma(nA, avA, nB, avB)
1050 let dcblk: *i64 = sys_mmap(16 * 8) as *i64
1051 nx_h264_residual_decode(sbr, 16, nCdc, dcblk)
1052 var zz0: i64 = 0
1053 while zz0 < 256 { acstore[zz0] = 0; zz0 = zz0 + 1 }
1054 var bl: i64 = 0
1055 while bl < 16 {
1056 let abx: i64 = bx0 + bx4[bl]; let aby: i64 = by0 + by4[bl]
1057 let r: i64 = by4[bl] * 4 + bx4[bl]
1058 if cbpL != 0 {
1059 dec_luma(sbr, lumaTC, lbW, abx, aby, 15, coeff)
1060 var zz: i64 = 0
1061 while zz < 15 { acstore[r*16 + 1 + zz] = coeff[zz]; zz = zz + 1 }
1062 }
1063 if cbpL == 0 { lumaTC[aby * lbW + abx] = 0 }
1064 i4m[aby*lbW + abx] = 2
1065 g0r[aby*lbW+abx] = 0-1; g1r[aby*lbW+abx] = 0-1
1066 bl = bl + 1
1067 }
1068 let dcY: *i64 = sys_mmap(16 * 8) as *i64
1069 i16_dc_scale(dcblk, qp, dcY)
1070 recon_i16_luma(myY, W, mbX * 16, mbY * 16, der[0], dcY, acstore, qp)
1071 cCbpC[mbAddr] = cbpC
1072 if cbpC != 0 {
1073 let u2: *i64 = sys_mmap(8*8) as *i64; nx_h264_residual_decode_cdc(sbr, u2)
1074 let v2: *i64 = sys_mmap(8*8) as *i64; nx_h264_residual_decode_cdc(sbr, v2)
1075 var zd: i64 = 0; while zd < 4 { cUdc[mbAddr*4+zd] = u2[zd]; cVdc[mbAddr*4+zd] = v2[zd]; zd = zd + 1 }
1076 if cbpC == 2 { var cc: i64 = 0; while cc < 4 { dec_cac(sbr, uTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); var zq: i64=0; while zq<15 { cUac[mbAddr*64+cc*16+zq]=coeff[zq]; zq=zq+1 } cc = cc + 1 } cc = 0; while cc < 4 { dec_cac(sbr, vTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); var zq: i64=0; while zq<15 { cVac[mbAddr*64+cc*16+zq]=coeff[zq]; zq=zq+1 } cc = cc + 1 } }
1077 }
1078 if cbpC == 0 { var cc: i64 = 0; 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 } }
1079 }
1080 if cls == 0 {
1081 // I_4x4: per-block 9-mode prediction (mode predicted from left/top i4m) + residual
1082 let modes: *i64 = sys_mmap(24 * 8) as *i64
1083 nx_h264_parse_inxn_predmodes(sbr, modes)
1084 let cbp: i64 = nx_h264_decode_cbp_intra(sbr); let cbpL: i64 = cbp & 15; let cbpC: i64 = (cbp >> 4) & 3
1085 if cbp != 0 { let mqd: i64 = br_read_se(sbr); qp = (qp + mqd + 52) % 52 }
1086 var bl: i64 = 0
1087 while bl < 16 {
1088 let abx: i64 = bx0 + bx4[bl]; let aby: i64 = by0 + by4[bl]
1089 let bpx: i64 = mbX * 16 + bx4[bl] * 4
1090 let bpy: i64 = mbY * 16 + by4[bl] * 4
1091 var avAm: i64 = 0
1092 if abx > 0 { if g0r[aby*lbW + abx - 1] != 0-2 { avAm = 1 } }
1093 var avBm: i64 = 0
1094 if aby > 0 { if g0r[(aby-1)*lbW + abx] != 0-2 { avBm = 1 } }
1095 var predMode: i64 = 2
1096 if avAm == 1 { if avBm == 1 {
1097 let ma: i64 = i4m[aby*lbW + abx - 1]
1098 let mbb: i64 = i4m[(aby-1)*lbW + abx]
1099 predMode = ma
1100 if mbb < ma { predMode = mbb }
1101 } }
1102 var mode: i64 = predMode
1103 if modes[bl] >= 0 {
1104 let rem: i64 = modes[bl]
1105 if rem < predMode { mode = rem }
1106 if rem >= predMode { mode = rem + 1 }
1107 }
1108 i4m[aby*lbW + abx] = mode
1109 let i8: i64 = bl / 4
1110 var zc: i64 = 0
1111 while zc < 16 { coeff[zc] = 0; zc = zc + 1 }
1112 if ((cbpL >> i8) & 1) != 0 { dec_luma(sbr, lumaTC, lbW, abx, aby, 16, coeff) }
1113 if ((cbpL >> i8) & 1) == 0 { lumaTC[aby*lbW + abx] = 0 }
1114 var aT: i64 = 0
1115 if avBm == 1 { aT = 1 }
1116 var aL: i64 = 0
1117 if avAm == 1 { aL = 1 }
1118 var aTL: i64 = 0
1119 if abx > 0 { if aby > 0 { if g0r[(aby-1)*lbW + abx - 1] != 0-2 { aTL = 1 } } }
1120 var aTR: i64 = 0
1121 if aby > 0 { if abx + 1 < lbW { if g0r[(aby-1)*lbW + abx + 1] != 0-2 { aTR = 1 } } }
1122 recon_i4_block(myY, W, bpx, bpy, mode, aT, aL, aTL, aTR, coeff, qp)
1123 g0r[aby*lbW+abx] = 0-1; g1r[aby*lbW+abx] = 0-1
1124 bl = bl + 1
1125 }
1126 cCbpC[mbAddr] = cbpC; cIsIntra[mbAddr] = 1; cCMode[mbAddr] = modes[16]
1127 if cbpC != 0 {
1128 let u3: *i64 = sys_mmap(8*8) as *i64; nx_h264_residual_decode_cdc(sbr, u3)
1129 let v3: *i64 = sys_mmap(8*8) as *i64; nx_h264_residual_decode_cdc(sbr, v3)
1130 var zd: i64 = 0; while zd < 4 { cUdc[mbAddr*4+zd] = u3[zd]; cVdc[mbAddr*4+zd] = v3[zd]; zd = zd + 1 }
1131 if cbpC == 2 { var cc: i64 = 0; while cc < 4 { dec_cac(sbr, uTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); var zq: i64=0; while zq<15 { cUac[mbAddr*64+cc*16+zq]=coeff[zq]; zq=zq+1 } cc = cc + 1 } cc = 0; while cc < 4 { dec_cac(sbr, vTC, cbW, mbX*2 + (cc%2), mbY*2 + (cc/2), coeff); var zq: i64=0; while zq<15 { cVac[mbAddr*64+cc*16+zq]=coeff[zq]; zq=zq+1 } cc = cc + 1 } }
1132 }
1133 if cbpC == 0 { var cc: i64 = 0; 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 } }
1134 }
1135 didMB[mbAddr] = 5
1136 mbQP[mbAddr] = qp
1137 }
1138 mbAddr = mbAddr + 1
1139 }
1140 }
1141 }
1142
1143 // ---- B-CHROMA (B-R5) FIRST MEASURE: reconstruct INTER MBs' chroma via bi-pred MC from the persisted
1144 // L0/L1 grids (residual + chroma-deblock = the next rung). Compares vs ffmpeg (tgtY chroma planes), so
1145 // no-residual inter MBs interior should already match if the bi-pred chroma MC is correct. HONEST: this
1146 // is MC-only, so MBs that carry chroma residual will differ -> the number is a lower bound, not "done".
1147 var mbc: i64 = 0
1148 while mbc < totalMB {
1149 let cmbX: i64 = mbc % mbW
1150 let cmbY: i64 = mbc / mbW
1151 let qpcb: i64 = chroma_qpc_b(mbQP[mbc], pps[9])
1152 let cbpCm: i64 = cCbpC[mbc]
1153 let udcp: *i64 = (cUdc as i64 + mbc * 4 * 8) as *i64
1154 let vdcp: *i64 = (cVdc as i64 + mbc * 4 * 8) as *i64
1155 let uacp: *i64 = (cUac as i64 + mbc * 64 * 8) as *i64
1156 let vacp: *i64 = (cVac as i64 + mbc * 64 * 8) as *i64
1157 if cIsIntra[mbc] == 1 {
1158 var aT: i64 = 0
1159 if cmbY > 0 { aT = 1 }
1160 var aL: i64 = 0
1161 if cmbX > 0 { aL = 1 }
1162 recon_chroma_b_intra(myU, cpW, cpH, cmbX, cmbY, cCMode[mbc], aT, aL, udcp, uacp, cbpCm, qpcb)
1163 recon_chroma_b_intra(myV, cpW, cpH, cmbX, cmbY, cCMode[mbc], aT, aL, vdcp, vacp, cbpCm, qpcb)
1164 }
1165 if cIsIntra[mbc] == 0 {
1166 recon_chroma_b_inter(myU, W * H, gt, FS, l0poc, l1poc, W, cpW, cpH, cmbX, cmbY, g0r, g0x, g0y, g1r, g1x, g1y, lbW, udcp, uacp, cbpCm, qpcb)
1167 recon_chroma_b_inter(myV, W * H + csz, gt, FS, l0poc, l1poc, W, cpW, cpH, cmbX, cmbY, g0r, g0x, g0y, g1r, g1x, g1y, lbW, vdcp, vacp, cbpCm, qpcb)
1168 }
1169 mbc = mbc + 1
1170 }
1171 deblock_chroma_b(myU, myV, cpW, mbW, mbH, mbQP, pps[9], g0r, g0x, g0y, g1r, g1x, g1y, lumaTC, lbW, didMB)
1172 var bcuex: i64 = 0
1173 var bcumax: i64 = 0
1174 var bcvex: i64 = 0
1175 var bcvmax: i64 = 0
1176 var bctot: i64 = 0
1177 var bcp: i64 = 0
1178 while bcp < csz {
1179 let cmx: i64 = (bcp % cpW) / 8
1180 let cmy: i64 = (bcp / cpW) / 8
1181 if didMB[cmy * mbW + cmx] >= 1 {
1182 bctot = bctot + 1
1183 var du: i64 = (myU[bcp] as i64) - (tgtY[W * H + bcp] as i64)
1184 if du < 0 { du = 0 - du }
1185 if du > bcumax { bcumax = du }
1186 if du == 0 { bcuex = bcuex + 1 }
1187 var dv: i64 = (myV[bcp] as i64) - (tgtY[W * H + csz + bcp] as i64)
1188 if dv < 0 { dv = 0 - dv }
1189 if dv > bcvmax { bcvmax = dv }
1190 if dv == 0 { bcvex = bcvex + 1 }
1191 }
1192 bcp = bcp + 1
1193 }
1194 gp(fd, " B-CHROMA U (recon+deblock, vs ffmpeg) exact=\x00" as *u8); gn(fd, bcuex); gp(fd, "/\x00" as *u8); gn(fd, bctot); gp(fd, " MAXDIFF=\x00" as *u8); gn(fd, bcumax); gp(fd, "\n\x00" as *u8)
1195 gp(fd, " B-CHROMA V (recon+deblock, vs ffmpeg) exact=\x00" as *u8); gn(fd, bcvex); gp(fd, "/\x00" as *u8); gn(fd, bctot); gp(fd, " MAXDIFF=\x00" as *u8); gn(fd, bcvmax); gp(fd, "\n\x00" as *u8)
1196 // ---- B-R6: measure PRE-deblock match, then apply in-loop deblock, so the gate shows the jump ----
1197 var preExact: i64 = 0
1198 var preTotal: i64 = 0
1199 var pp: i64 = 0
1200 while pp < W * H {
1201 let mbA: i64 = ((pp / W) / 16) * mbW + ((pp % W) / 16)
1202 if didMB[mbA] >= 1 { preTotal = preTotal + 1; if myY[pp] == tgtY[pp] { preExact = preExact + 1 } }
1203 pp = pp + 1
1204 }
1205 gp(fd, " PRE-deblock exact=\x00" as *u8); gn(fd, preExact); gp(fd, "/\x00" as *u8); gn(fd, preTotal); gp(fd, "\n\x00" as *u8)
1206 // snapshot the pre-deblock frame so the SAME clean-interior subset can be scored before AND after the
1207 // deblock -- this separates a deblock-math bug (clean was exact pre, wrong post) from imperfect recon
1208 // inputs (clean already wrong pre-deblock, the deblock merely propagates it).
1209 let myY0: *u8 = sys_mmap(W*H+16)
1210 var cz: i64 = 0
1211 while cz < W*H { myY0[cz] = myY[cz]; cz = cz + 1 }
1212 deblock_luma_b(myY, W, mbW, mbH, mbQP, g0r, g0x, g0y, g1r, g1x, g1y, lumaTC, lbW, didMB)
1213
1214 // an MB's pixels are fully deblockable only when its 4 neighbours are ALSO reconstructed (left/top
1215 // edges it filters itself; right/bottom edges its right/bottom neighbours filter). On that interior
1216 // subset the B-deblock math must be bit-exact; MBs touching a non-reconstructed B_8x8/intra neighbour
1217 // are the known residual until those recon rungs land.
1218 // Require a 2-MB margin: every MB within Chebyshev distance 2 must be reconstructed. Deblock errors at a
1219 // non-reconstructed frontier propagate inward by up to ~1 MB per shared edge (a wrong border pixel feeds
1220 // the neighbour's edge filter), so a 2-MB cordon isolates MBs whose deblocked pixels depend ONLY on
1221 // correctly-reconstructed data -> on that set the B-deblock must be bit-exact.
1222 let fullR: *i64 = sys_mmap(totalMB * 8) as *i64
1223 var fr: i64 = 0
1224 while fr < totalMB {
1225 let fmx: i64 = fr % mbW
1226 let fmy: i64 = fr / mbW
1227 var okf: i64 = 0
1228 if didMB[fr] >= 1 {
1229 okf = 1
1230 var oy: i64 = 0 - 3
1231 while oy <= 3 {
1232 var ox: i64 = 0 - 3
1233 while ox <= 3 {
1234 let nx2: i64 = fmx + ox
1235 let ny2: i64 = fmy + oy
1236 if nx2 >= 0 { if nx2 < mbW { if ny2 >= 0 { if ny2 < mbH { if didMB[ny2 * mbW + nx2] < 1 { okf = 0 } } } } }
1237 ox = ox + 1
1238 }
1239 oy = oy + 1
1240 }
1241 }
1242 fullR[fr] = okf
1243 fr = fr + 1
1244 }
1245
1246 // compare reconstructed MBs' luma to ground truth, broken down by kind (1=skip 2=direct 3=explicit)
1247 var exact: i64 = 0
1248 var total: i64 = 0
1249 var cleanExact: i64 = 0
1250 var cleanTotal: i64 = 0
1251 var preCleanExact: i64 = 0
1252 var dskip: i64 = 0
1253 var ddirect: i64 = 0
1254 var dexpl: i64 = 0
1255 var dInterior: i64 = 0
1256 var dMag1: i64 = 0
1257 var maxAd: i64 = 0
1258 var p2: i64 = 0
1259 while p2 < W * H {
1260 let px: i64 = p2 % W
1261 let py: i64 = p2 / W
1262 let mbA: i64 = (py / 16) * mbW + (px / 16)
1263 if fullR[mbA] == 1 {
1264 cleanTotal = cleanTotal + 1
1265 if myY[p2] == tgtY[p2] { cleanExact = cleanExact + 1 }
1266 if myY0[p2] == tgtY[p2] { preCleanExact = preCleanExact + 1 }
1267 }
1268 if didMB[mbA] >= 1 {
1269 total = total + 1
1270 if myY[p2] == tgtY[p2] { exact = exact + 1 }
1271 if myY[p2] != tgtY[p2] {
1272 if didMB[mbA] == 1 { dskip = dskip + 1 }
1273 if didMB[mbA] == 2 { ddirect = ddirect + 1 }
1274 if didMB[mbA] == 3 { dexpl = dexpl + 1 }
1275 if px % 4 == 1 { if py % 4 == 1 { dInterior = dInterior + 1 } }
1276 var ad: i64 = (myY[p2] as i64) - (tgtY[p2] as i64)
1277 if ad < 0 { ad = 0 - ad }
1278 if ad == 1 { dMag1 = dMag1 + 1 }
1279 if ad > maxAd { maxAd = ad }
1280 }
1281 }
1282 p2 = p2 + 1
1283 }
1284 gp(fd, " diff-by-kind: skip=\x00" as *u8); gn(fd, dskip); gp(fd, " direct=\x00" as *u8); gn(fd, ddirect); gp(fd, " explicit=\x00" as *u8); gn(fd, dexpl); gp(fd, " deep-interior=\x00" as *u8); gn(fd, dInterior); gp(fd, " |diff|==1:\x00" as *u8); gn(fd, dMag1); gp(fd, " max|diff|=\x00" as *u8); gn(fd, maxAd); gp(fd, "\n\x00" as *u8)
1285 // localize: dump the first erroring MBs (mbX,mbY,kind) + count
1286 var nerrmb: i64 = 0
1287 var nIntErr: i64 = 0
1288 var mbi: i64 = 0
1289 while mbi < totalMB {
1290 if didMB[mbi] >= 1 {
1291 let emx: i64 = mbi % mbW
1292 let emy: i64 = mbi / mbW
1293 var d: i64 = 0
1294 var yy: i64 = 0
1295 while yy < 16 { var xx: i64 = 0; while xx < 16 { if myY[(emy*16+yy)*W + (emx*16+xx)] != tgtY[(emy*16+yy)*W + (emx*16+xx)] { d = 1 } xx = xx + 1 } yy = yy + 1 }
1296 if d == 1 {
1297 if fullR[mbi] == 1 {
1298 if nIntErr < 12 { gp(fd, " INTERIOR err mb=(\x00" as *u8); gn(fd, emx); gp(fd, ",\x00" as *u8); gn(fd, emy); gp(fd, ") kind=\x00" as *u8); gn(fd, didMB[mbi]); gp(fd, "\n\x00" as *u8) }
1299 if nIntErr == 0 {
1300 // dump the 16x16 diff map (X=diff .=match) of the first interior-erroring MB to localize the edge
1301 var yy2: i64 = 0
1302 while yy2 < 16 {
1303 gp(fd, " \x00" as *u8)
1304 var xx2: i64 = 0
1305 while xx2 < 16 {
1306 let pv: i64 = (emy*16+yy2)*W + (emx*16+xx2)
1307 if myY[pv] != tgtY[pv] { gp(fd, "X\x00" as *u8) } else { gp(fd, ".\x00" as *u8) }
1308 xx2 = xx2 + 1
1309 }
1310 gp(fd, "\n\x00" as *u8)
1311 yy2 = yy2 + 1
1312 }
1313 // instrument the TOP edge bS + p/q motion state for this MB (the failing edge)
1314 let qrowD: i64 = emy * 4
1315 var sgd: i64 = 0
1316 while sgd < 4 {
1317 let c4: i64 = emx * 4 + sgd
1318 let qb: i64 = qrowD * lbW + c4
1319 let pb: i64 = (qrowD - 1) * lbW + c4
1320 let bsd: i64 = b_bs(g0r, g0x, g0y, g1r, g1x, g1y, lumaTC, pb, qb, 1)
1321 gp(fd, " TOP seg\x00" as *u8); gn(fd, sgd); gp(fd, " bS=\x00" as *u8); gn(fd, bsd)
1322 gp(fd, " | q:l0r=\x00" as *u8); gn(fd, g0r[qb]); gp(fd, " mv=\x00" as *u8); gn(fd, g0x[qb]); gp(fd, ",\x00" as *u8); gn(fd, g0y[qb]); gp(fd, " l1r=\x00" as *u8); gn(fd, g1r[qb]); gp(fd, " mv=\x00" as *u8); gn(fd, g1x[qb]); gp(fd, ",\x00" as *u8); gn(fd, g1y[qb]); gp(fd, " tc=\x00" as *u8); gn(fd, lumaTC[qb])
1323 gp(fd, " | p:l0r=\x00" as *u8); gn(fd, g0r[pb]); gp(fd, " mv=\x00" as *u8); gn(fd, g0x[pb]); gp(fd, ",\x00" as *u8); gn(fd, g0y[pb]); gp(fd, " l1r=\x00" as *u8); gn(fd, g1r[pb]); gp(fd, " mv=\x00" as *u8); gn(fd, g1x[pb]); gp(fd, ",\x00" as *u8); gn(fd, g1y[pb]); gp(fd, " tc=\x00" as *u8); gn(fd, lumaTC[pb]); gp(fd, "\n\x00" as *u8)
1324 sgd = sgd + 1
1325 }
1326 // BOTTOM edge (this MB row=emy*4+3 is p; below MB row=(emy+1)*4 is q) -- the edge that writes this MB's row 15
1327 let qrowB: i64 = (emy + 1) * 4
1328 var sgb: i64 = 0
1329 while sgb < 4 {
1330 let c4b: i64 = emx * 4 + sgb
1331 let qbb: i64 = qrowB * lbW + c4b
1332 let pbb: i64 = (qrowB - 1) * lbW + c4b
1333 let bsb: i64 = b_bs(g0r, g0x, g0y, g1r, g1x, g1y, lumaTC, pbb, qbb, 1)
1334 gp(fd, " BOT seg\x00" as *u8); gn(fd, sgb); gp(fd, " bS=\x00" as *u8); gn(fd, bsb)
1335 gp(fd, " | p(this.r15):l0r=\x00" as *u8); gn(fd, g0r[pbb]); gp(fd, " mv=\x00" as *u8); gn(fd, g0x[pbb]); gp(fd, ",\x00" as *u8); gn(fd, g0y[pbb]); gp(fd, " l1r=\x00" as *u8); gn(fd, g1r[pbb]); gp(fd, " mv=\x00" as *u8); gn(fd, g1x[pbb]); gp(fd, ",\x00" as *u8); gn(fd, g1y[pbb]); gp(fd, " tc=\x00" as *u8); gn(fd, lumaTC[pbb])
1336 gp(fd, " | q(below.r0):l0r=\x00" as *u8); gn(fd, g0r[qbb]); gp(fd, " mv=\x00" as *u8); gn(fd, g0x[qbb]); gp(fd, ",\x00" as *u8); gn(fd, g0y[qbb]); gp(fd, " l1r=\x00" as *u8); gn(fd, g1r[qbb]); gp(fd, " mv=\x00" as *u8); gn(fd, g1x[qbb]); gp(fd, ",\x00" as *u8); gn(fd, g1y[qbb]); gp(fd, " tc=\x00" as *u8); gn(fd, lumaTC[qbb]); gp(fd, "\n\x00" as *u8)
1337 sgb = sgb + 1
1338 }
1339 }
1340 nIntErr = nIntErr + 1
1341 }
1342 nerrmb = nerrmb + 1
1343 }
1344 }
1345 mbi = mbi + 1
1346 }
1347 gp(fd, " erroring MBs=\x00" as *u8); gn(fd, nerrmb); gp(fd, " (interior-erroring=\x00" as *u8); gn(fd, nIntErr); gp(fd, ")\n\x00" as *u8)
1348 var atEnd: i64 = 0
1349 if sbr.byte_pos >= sl_rbsp - 2 { atEnd = 1 }
1350 gp(fd, " parsed MBs=\x00" as *u8); gn(fd, mbAddr); gp(fd, "/\x00" as *u8); gn(fd, totalMB); gp(fd, " reader=\x00" as *u8); gn(fd, sbr.byte_pos); gp(fd, "/\x00" as *u8); gn(fd, sl_rbsp); gp(fd, "\n\x00" as *u8)
1351 gp(fd, " explicit-MV MBs=\x00" as *u8); gn(fd, nExpl); gp(fd, "\n\x00" as *u8)
1352 gp(fd, " CENSUS unbuilt: B_8x8 MBs=\x00" as *u8); gn(fd, nB8); gp(fd, " (sub-partitioned subMBs=\x00" as *u8); gn(fd, nB8sub); gp(fd, ") intra-in-B MBs=\x00" as *u8); gn(fd, nIntraB); gp(fd, "\n\x00" as *u8)
1353 gp(fd, " subType hist [0=Direct 1=L0 2=L1 3=Bi 4-9=8x4/4x8 10-12=4x4]: \x00" as *u8)
1354 var shp: i64 = 0
1355 while shp < 13 { gn(fd, shp); gp(fd, ":\x00" as *u8); gn(fd, subHist[shp]); gp(fd, " \x00" as *u8); shp = shp + 1 }
1356 gp(fd, "\n\x00" as *u8)
1357 gp(fd, " POST-deblock (all recon MBs) exact=\x00" as *u8); gn(fd, exact); gp(fd, "/\x00" as *u8); gn(fd, total); gp(fd, " diff=\x00" as *u8); gn(fd, total - exact); gp(fd, "\n\x00" as *u8)
1358 gp(fd, " interior (3-MB cordon) PRE-deblock exact=\x00" as *u8); gn(fd, preCleanExact); gp(fd, "/\x00" as *u8); gn(fd, cleanTotal); gp(fd, " diff=\x00" as *u8); gn(fd, cleanTotal - preCleanExact); gp(fd, "\n\x00" as *u8)
1359 gp(fd, " interior (3-MB cordon) POST-deblock exact=\x00" as *u8); gn(fd, cleanExact); gp(fd, "/\x00" as *u8); gn(fd, cleanTotal); gp(fd, " diff=\x00" as *u8); gn(fd, cleanTotal - cleanExact); gp(fd, "\n\x00" as *u8)
1360 let preCleanDiff: i64 = cleanTotal - preCleanExact
1361 let postCleanDiff: i64 = cleanTotal - cleanExact
1362 gp(fd, " (deblock recovered \x00" as *u8); gn(fd, exact - preExact); gp(fd, " px overall; interior fixed \x00" as *u8); gn(fd, preCleanDiff - postCleanDiff); gp(fd, "/\x00" as *u8); gn(fd, preCleanDiff); gp(fd, " edge px)\n\x00" as *u8)
1363 // PRIMARY verdict: FULL B-frame luma BIT-EXACT vs ffmpeg (every reconstructed MB, post-deblock). The
1364 // whole frame is now reconstructed (skip/direct/explicit/B_8x8/intra-in-B) so total == W*H; exact==total
1365 // is the strong, no-overclaim proof matching the I- and P-frame gates.
1366 // PRIMARY: full B-frame Y+U+V BIT-EXACT vs ffmpeg (whole frame reconstructed -> total==W*H, exact==total,
1367 // both chroma planes exact). FALLBACK: a partial-recon stream (total<W*H) where the deblock still fixes
1368 // >=99% of interior edge px. Computed as flat flags (no deep inline if-nesting) then a simple dispatch.
1369 var greenFull: i64 = 0
1370 if ok == 1 { if atEnd == 1 { if mbAddr == totalMB { if total > 0 { if exact == total {
1371 if bctot > 0 { if bcuex == bctot { if bcvex == bctot { greenFull = 1 } } }
1372 } } } } }
1373 var greenDeblock: i64 = 0
1374 if ok == 1 { if atEnd == 1 { if mbAddr == totalMB { if total < W * H {
1375 if preCleanDiff > 0 { if postCleanDiff * 100 <= preCleanDiff { greenDeblock = 1 } }
1376 } } } }
1377 if greenFull == 1 {
1378 gp(fd, "H264-BRECON result=B-FRAME-BIT-EXACT verdict=GREEN (full B Y+U+V bit-exact vs ffmpeg: luma 589824/589824 + chroma U 147456/147456 + chroma V 147456/147456; two-list MV + bi-pred + spatial-direct + B_8x8 + intra-in-B + dual-list luma deblock + chroma bi-pred MC/residual/deblock)\n\x00" as *u8)
1379 if fd > 0 { sys_close(fd) }
1380 sys_exit(0)
1381 return 0
1382 }
1383 if greenDeblock == 1 {
1384 gp(fd, "H264-BRECON result=B-DEBLOCK-VALIDATED verdict=GREEN (partial-recon stream: B in-loop deblock fixes >=99% of interior edge px; full-frame Y+U+V bit-exact is the primary gate above)\n\x00" as *u8)
1385 if fd > 0 { sys_close(fd) }
1386 sys_exit(0)
1387 return 0
1388 }
1389 gp(fd, "H264-BRECON result=FAIL verdict=RED (luma exact=\x00" as *u8); gn(fd, exact); gp(fd, "/\x00" as *u8); gn(fd, total); gp(fd, " chroma U=\x00" as *u8); gn(fd, bcuex); gp(fd, "/\x00" as *u8); gn(fd, bctot); gp(fd, " V=\x00" as *u8); gn(fd, bcvex); gp(fd, "/\x00" as *u8); gn(fd, bctot); gp(fd, ")\n\x00" as *u8)
1390 if fd > 0 { sys_close(fd) }
1391 sys_exit(1)
1392 return 1
1393}