nx_h264_bframe_probe.nx source
↩ module page · 104 lines · 4728 B
1// nx_h264_bframe_probe.nx -- B-R0: parse the GOP STRUCTURE of an annexb H.264 stream with B-frames
2// (knowledge/staging/media/bframe_test.264, made by x264 --no-cabac --bframes 1). Splits annexb NALs,
3// parses SPS/PPS, and for every slice prints (decode-order idx, nal_type, slice_type I/P/B, frame_num,
4// poc_lsb, nal_ref_idc) -- revealing decode order vs display (POC) order and which frames are B + their
5// reference role. Foundation for the B-frame decode arc (ref-list construction, bi-prediction). Exit 0.
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"
12
13func gp(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
14func gn(v: i64) -> i64 {
15 let bb: *u8 = sys_mmap(28); var m: i64 = v
16 if m < 0 { sys_write(1, "-\x00" as *u8, 1); m = 0 - m }
17 let t: *u8 = sys_mmap(28); var k: i64 = 0
18 if m == 0 { t[0] = 48 as u8; k = 1 }
19 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
20 var i: i64 = 0
21 while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
22 sys_write(1, bb, k); return 0
23}
24
25func main() -> i64 {
26 let szp: *i64 = sys_mmap(16) as *i64
27 let b: *u8 = sys_read_file("knowledge/staging/media/bframe_test.264\x00" as *u8, szp)
28 if (b as i64) == 0 { gp("no bframe_test.264\n\x00" as *u8); return 1 }
29 let len: i64 = szp[0]
30 gp("B-FRAME-PROBE: bframe_test.264 size=\x00" as *u8); gn(len); gp("\n\x00" as *u8)
31
32 let offs: *i64 = sys_mmap(512 * 8) as *i64
33 let types: *i64 = sys_mmap(512 * 8) as *i64
34 let nc: i64 = nx_nal_split_annexb(b, 0, len, offs, types, 512)
35 gp(" NAL count=\x00" as *u8); gn(nc); gp("\n\x00" as *u8)
36
37 // find + parse SPS (7) and PPS (8)
38 let sps: *i64 = sys_mmap(128) as *i64
39 let pps: *i64 = sys_mmap(128) as *i64
40 var k: i64 = 0
41 while k < nc {
42 let noff: i64 = offs[k]
43 var nend: i64 = len
44 if k + 1 < nc { nend = offs[k + 1] - 3 }
45 if types[k] == 7 {
46 let dst: *u8 = sys_mmap(nend - noff + 16)
47 let rb: i64 = nx_h264_unescape_rbsp((b as i64 + noff + 1) as *u8, nend - noff - 1, dst)
48 nx_h264_parse_sps(dst, rb, sps)
49 }
50 if types[k] == 8 {
51 let dst: *u8 = sys_mmap(nend - noff + 16)
52 let rb: i64 = nx_h264_unescape_rbsp((b as i64 + noff + 1) as *u8, nend - noff - 1, dst)
53 nx_h264_parse_pps(dst, rb, pps)
54 }
55 k = k + 1
56 }
57 gp(" SPS WxH=\x00" as *u8); gn(sps[2]); gp("x\x00" as *u8); gn(sps[3])
58 gp(" log2_frame_num=\x00" as *u8); gn(sps[9]); gp(" poc_type=\x00" as *u8); gn(sps[10])
59 gp(" log2_poc_lsb=\x00" as *u8); gn(sps[11]); gp(" PPS init_qp=\x00" as *u8); gn(pps[3]); gp("\n\x00" as *u8)
60
61 // walk slices in decode order
62 let sh: *i64 = sys_mmap(64) as *i64
63 var di: i64 = 0
64 var nI: i64 = 0
65 var nP: i64 = 0
66 var nB: i64 = 0
67 k = 0
68 while k < nc {
69 if types[k] == 1 { di = di + 0 } // placeholder to keep structure
70 let isSlice: i64 = (types[k] == 1) as i64 + (types[k] == 5) as i64
71 if isSlice >= 1 {
72 let noff: i64 = offs[k]
73 let hdr: i64 = b[noff] as i64
74 let ntype: i64 = hdr & 31
75 let nref: i64 = (hdr >> 5) & 3
76 var nend: i64 = len
77 if k + 1 < nc { nend = offs[k + 1] - 3 }
78 let dst: *u8 = sys_mmap(nend - noff + 16)
79 let rb: i64 = nx_h264_unescape_rbsp((b as i64 + noff + 1) as *u8, nend - noff - 1, dst)
80 let br: *BitReader = sys_mmap(NX_BR_BYTES) as *BitReader
81 br_init(br, dst, rb)
82 nx_h264_parse_slice_header_br(br, ntype, nref, sps[9], sps[11], sps[10], sps[6], pps[3], pps[6], sh)
83 let stm: i64 = sh[8]
84 gp(" [dec\x00" as *u8); gn(di); gp("] nal=\x00" as *u8); gn(ntype); gp(" ref_idc=\x00" as *u8); gn(nref)
85 gp(" type=\x00" as *u8)
86 if stm == 2 { gp("I\x00" as *u8); nI = nI + 1 }
87 if stm == 0 { gp("P\x00" as *u8); nP = nP + 1 }
88 if stm == 1 { gp("B\x00" as *u8); nB = nB + 1 }
89 gp(" frame_num=\x00" as *u8); gn(sh[3]); gp(" poc_lsb=\x00" as *u8); gn(sh[5])
90 gp(" QP=\x00" as *u8); gn(sh[7]); gp("\n\x00" as *u8)
91 di = di + 1
92 }
93 k = k + 1
94 }
95 gp(" TOTALS: slices=\x00" as *u8); gn(di); gp(" I=\x00" as *u8); gn(nI); gp(" P=\x00" as *u8); gn(nP); gp(" B=\x00" as *u8); gn(nB); gp("\n\x00" as *u8)
96 if nB >= 1 {
97 gp(" *** B-frames present, parsed in decode order -> B-R0 GREEN ***\n\x00" as *u8)
98 sys_exit(0)
99 return 0
100 }
101 gp(" no B-frames found\n\x00" as *u8)
102 sys_exit(1)
103 return 1
104}