code wiki / (root) / nx_h264_bframe_probe.nx

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}