nx_h264_bframe_reflist_gate.nx source
↩ module page · 121 lines · 5932 B
1// nx_h264_bframe_reflist_gate.nx -- B-R1: compute POC (display order) for every frame of bframe_test.264
2// and construct each B-slice's L0/L1 reference lists, verified against hand-derived ground truth:
3// POC (decode order) == 0,2,6,4,8,12,10,14,16,20,18,22
4// B@POC4 -> L0[0]=2 L1[0]=6 ; B@POC10 -> L0[0]=8 L1[0]=12 ; B@POC18 -> L0[0]=16 L1[0]=20
5// Exits 0/1. license_tier: ORIGINAL
6import "nx_syscalls.nx"
7import "nx_h264_bits.nx"
8import "nx_h264_sps.nx"
9import "nx_h264_pps.nx"
10import "nx_h264_nal.nx"
11import "nx_h264_slice.nx"
12import "nx_h264_poc.nx"
13import "nx_gate_verdict.nx"
14
15func gp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
16func gn(v: i64) -> i64 {
17 let bb: *u8 = sys_mmap(28); var m: i64 = v
18 if m < 0 { sys_write(1, "-\x00" as *u8, 1); m = 0 - m }
19 let t: *u8 = sys_mmap(28); var k: i64 = 0
20 if m == 0 { t[0] = 48 as u8; k = 1 }
21 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
22 var i: i64 = 0
23 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
24 sys_write(1, bb, k); return 0
25}
26
27func main() -> i64 {
28 let szp: *i64 = sys_mmap(16) as *i64
29 let b: *u8 = sys_read_file("knowledge/staging/media/bframe_test.264\x00" as *u8, szp)
30 if (b as i64) == 0 { gp("no bframe_test.264\n\x00" as *u8); sys_exit(1); return 1 }
31 let len: i64 = szp[0]
32 gp("B-FRAME-REFLIST-GATE (B-R1: POC + L0/L1)\n\x00" as *u8)
33
34 let offs: *i64 = sys_mmap(512 * 8) as *i64
35 let types: *i64 = sys_mmap(512 * 8) as *i64
36 let nc: i64 = nx_nal_split_annexb(b, 0, len, offs, types, 512)
37 let sps: *i64 = sys_mmap(128) as *i64
38 let pps: *i64 = sys_mmap(128) as *i64
39 var k: i64 = 0
40 while k < nc {
41 let noff: i64 = offs[k]
42 var nend: i64 = len
43 if k + 1 < nc { nend = offs[k + 1] - 3 }
44 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) }
45 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) }
46 k = k + 1
47 }
48 let max_poc_lsb: i64 = 1 << sps[11]
49
50 // expected POC (decode order) + expected B L0/L1[0]
51 let expPoc: *i64 = sys_mmap(16 * 8) as *i64
52 expPoc[0]=0; expPoc[1]=2; expPoc[2]=6; expPoc[3]=4; expPoc[4]=8; expPoc[5]=12
53 expPoc[6]=10; expPoc[7]=14; expPoc[8]=16; expPoc[9]=20; expPoc[10]=18; expPoc[11]=22
54
55 let state: *i64 = sys_mmap(16) as *i64
56 state[0] = 0; state[1] = 0
57 // DPB of reference pics (POC + decode idx), in decode order
58 let dpbPoc: *i64 = sys_mmap(64 * 8) as *i64
59 let dpbIdx: *i64 = sys_mmap(64 * 8) as *i64
60 var dpbN: i64 = 0
61 let l0: *i64 = sys_mmap(64 * 8) as *i64
62 let l0i: *i64 = sys_mmap(64 * 8) as *i64
63 let l1: *i64 = sys_mmap(64 * 8) as *i64
64 let l1i: *i64 = sys_mmap(64 * 8) as *i64
65 let sh: *i64 = sys_mmap(64) as *i64
66
67 var ok: i64 = 1
68 var di: i64 = 0
69 var nB: i64 = 0
70 var bmatch: i64 = 0
71 k = 0
72 while k < nc {
73 let isSlice: i64 = (types[k] == 1) as i64 + (types[k] == 5) as i64
74 if isSlice >= 1 {
75 let noff: i64 = offs[k]
76 let hdr: i64 = b[noff] as i64
77 let ntype: i64 = hdr & 31
78 let nref: i64 = (hdr >> 5) & 3
79 var nend: i64 = len
80 if k + 1 < nc { nend = offs[k + 1] - 3 }
81 let dst: *u8 = sys_mmap(nend - noff + 16)
82 let rb: i64 = nx_h264_unescape_rbsp((b as i64 + noff + 1) as *u8, nend - noff - 1, dst)
83 let br: *BitReader = sys_mmap(NX_BR_BYTES) as *BitReader
84 br_init(br, dst, rb)
85 nx_h264_parse_slice_header_br(br, ntype, nref, sps[9], sps[11], sps[10], sps[6], pps[3], pps[6], sh)
86 let is_idr: i64 = (ntype == 5) as i64
87 let poc: i64 = nx_h264_poc_type0(sh[5], max_poc_lsb, is_idr, nref, state)
88 gp(" dec\x00" as *u8); gn(di); gp(" type=\x00" as *u8); gn(sh[8]); gp(" POC=\x00" as *u8); gn(poc)
89 if poc != expPoc[di] { ok = 0; gp(" *POC-MISMATCH(exp \x00" as *u8); gn(expPoc[di]); gp(")\x00" as *u8) }
90 // B-slice: build + check ref lists from DPB so far
91 if sh[8] == 1 {
92 nB = nB + 1
93 nx_h264_build_blists(dpbPoc, dpbIdx, dpbN, poc, l0, l0i, l1, l1i)
94 gp(" L0[0]=\x00" as *u8); gn(l0[0]); gp(" L1[0]=\x00" as *u8); gn(l1[0])
95 var expL0: i64 = 0 - 1
96 var expL1: i64 = 0 - 1
97 if poc == 4 { expL0 = 2; expL1 = 6 }
98 if poc == 10 { expL0 = 8; expL1 = 12 }
99 if poc == 18 { expL0 = 16; expL1 = 20 }
100 if l0[0] == expL0 { if l1[0] == expL1 { bmatch = bmatch + 1; gp(" OK\x00" as *u8) } }
101 if l0[0] != expL0 { ok = 0; gp(" *L0-BAD\x00" as *u8) }
102 if l1[0] != expL1 { ok = 0; gp(" *L1-BAD\x00" as *u8) }
103 }
104 gp("\n\x00" as *u8)
105 // reference pics (nal_ref_idc != 0) join the DPB
106 if nref != 0 { dpbPoc[dpbN] = poc; dpbIdx[dpbN] = di; dpbN = dpbN + 1 }
107 di = di + 1
108 }
109 k = k + 1
110 }
111 gp(" frames=\x00" as *u8); gn(di); gp(" B=\x00" as *u8); gn(nB); gp(" B-lists-correct=\x00" as *u8); gn(bmatch); gp("/\x00" as *u8); gn(nB); gp("\n\x00" as *u8)
112 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
113 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
114 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
115 let ctr__dry: *i64 = gv_ctr()
116 ctr__dry[0] = ok
117 ctr__dry[1] = 1
118 let rc__dry: i64 = gv_verdict("H264-BFRAME-REFLIST-GATE" as *u8, ctr__dry, "POC + B L0/L1 correct)00" as *u8)
119 sys_exit(rc__dry)
120 return rc__dry
121}