nx_h264_sps.nx source
↩ module page · 112 lines · 5197 B
1// nx_h264_sps.nx -- H.264 Sequence Parameter Set parser (rung 3).
2// Decodes profile/level/resolution straight from the SPS bitstream using the
3// Exp-Golomb keystone (nx_h264_bits). Field order + dimension formulas verified
4// against the Cardinal Peak worked example (SPS 42 00 0a f8 41 a2 -> 128x96).
5//
6// Width = (pic_width_in_mbs_minus1 + 1) * 16
7// Height = (pic_height_in_map_units_minus1 + 1) * 16 * (2 - frame_mbs_only_flag)
8// minus frame-crop * cropUnit (4:2:0 default).
9//
10// Also ships RBSP de-emulation (remove 00 00 03 emulation-prevention bytes),
11// required before bit-parsing a real NAL payload.
12//
13// HONEST scope: seq_scaling_matrix lists are NOT parsed (flagged in out[8]); VUI
14// ignored (it is last). Baseline/Main/High (no scaling matrix) parse correctly.
15//
16// genealogy_id: itu_t_h264_sec7_3_2_1_1_sps + cardinalpeak_sps_worked_example
17// lineage_id: exp_golomb_sps_fields + mb_dimension_formula
18// license_tier: ORIGINAL
19import "nx_syscalls.nx"
20import "nx_h264_bits.nx"
21
22// remove emulation-prevention bytes: 00 00 03 -> 00 00. Returns dst length.
23func nx_h264_unescape_rbsp(src: *u8, len: i64, dst: *u8) -> i64 {
24 var i: i64 = 0
25 var j: i64 = 0
26 while i < len {
27 var skip: i64 = 0
28 if i + 2 < len { if (src[i] as i64) == 0 { if (src[i + 1] as i64) == 0 { if (src[i + 2] as i64) == 3 { skip = 1 } } } }
29 if skip == 1 { dst[j] = 0 as u8; dst[j + 1] = 0 as u8; j = j + 2; i = i + 3 }
30 if skip == 0 { dst[j] = src[i]; j = j + 1; i = i + 1 }
31 }
32 return j
33}
34
35func nx_h264_is_high(p: i64) -> i64 {
36 if p == 100 { return 1 }
37 if p == 110 { return 1 }
38 if p == 122 { return 1 }
39 if p == 244 { return 1 }
40 if p == 44 { return 1 }
41 if p == 83 { return 1 }
42 if p == 86 { return 1 }
43 if p == 118 { return 1 }
44 if p == 128 { return 1 }
45 return 0
46}
47
48// Parse SPS RBSP (NAL header byte already stripped, de-emulated). Writes:
49// out[0]=profile_idc out[1]=level_idc out[2]=width out[3]=height
50// out[4]=pic_width_in_mbs_minus1 out[5]=pic_height_in_map_units_minus1
51// out[6]=frame_mbs_only_flag out[7]=chroma_format_idc out[8]=scaling_matrix_unparsed
52func nx_h264_parse_sps(rbsp: *u8, len: i64, out: *i64) -> i64 {
53 out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = 0; out[6] = 0; out[7] = 1; out[8] = 0
54 out[9] = 0; out[10] = 0; out[11] = 0 // log2_max_frame_num, poc_type, log2_max_poc_lsb (for slice hdr)
55 let br: *BitReader = sys_mmap(NX_BR_BYTES) as *BitReader
56 br_init(br, rbsp, len)
57 let profile: i64 = br_read_bits(br, 8)
58 let constraints: i64 = br_read_bits(br, 8)
59 let level: i64 = br_read_bits(br, 8)
60 br_read_ue(br) // seq_parameter_set_id
61 var chroma: i64 = 1
62 if nx_h264_is_high(profile) == 1 {
63 chroma = br_read_ue(br)
64 if chroma == 3 { br_read_bits(br, 1) } // separate_colour_plane_flag
65 br_read_ue(br) // bit_depth_luma_minus8
66 br_read_ue(br) // bit_depth_chroma_minus8
67 br_read_bits(br, 1) // qpprime_y_zero_transform_bypass_flag
68 let scaling: i64 = br_read_bits(br, 1) // seq_scaling_matrix_present_flag
69 if scaling == 1 { out[8] = 1 } // scaling lists NOT parsed (honest flag)
70 }
71 let l2fn: i64 = br_read_ue(br) // log2_max_frame_num_minus4
72 out[9] = l2fn + 4
73 let poc_type: i64 = br_read_ue(br)
74 out[10] = poc_type
75 if poc_type == 0 { let l2poc: i64 = br_read_ue(br); out[11] = l2poc + 4 }
76 if poc_type == 1 {
77 br_read_bits(br, 1) // delta_pic_order_always_zero_flag
78 br_read_se(br) // offset_for_non_ref_pic
79 br_read_se(br) // offset_for_top_to_bottom_field
80 let nc: i64 = br_read_ue(br)
81 var ci: i64 = 0
82 while ci < nc { br_read_se(br); ci = ci + 1 }
83 }
84 br_read_ue(br) // max_num_ref_frames
85 br_read_bits(br, 1) // gaps_in_frame_num_value_allowed_flag
86 let w_m1: i64 = br_read_ue(br)
87 let h_m1: i64 = br_read_ue(br)
88 let frame_mbs_only: i64 = br_read_bits(br, 1)
89 if frame_mbs_only == 0 { br_read_bits(br, 1) } // mb_adaptive_frame_field_flag
90 br_read_bits(br, 1) // direct_8x8_inference_flag
91 let crop: i64 = br_read_bits(br, 1)
92 var cl: i64 = 0
93 var cr: i64 = 0
94 var ct: i64 = 0
95 var cb: i64 = 0
96 if crop == 1 { cl = br_read_ue(br); cr = br_read_ue(br); ct = br_read_ue(br); cb = br_read_ue(br) }
97
98 var width: i64 = (w_m1 + 1) * 16
99 var height: i64 = (h_m1 + 1) * 16 * (2 - frame_mbs_only)
100 var subw: i64 = 2
101 var subh: i64 = 2
102 if chroma == 0 { subw = 1; subh = 1 }
103 if chroma == 3 { subw = 1; subh = 1 }
104 let unitx: i64 = subw
105 let unity: i64 = subh * (2 - frame_mbs_only)
106 width = width - (cl + cr) * unitx
107 height = height - (ct + cb) * unity
108
109 out[0] = profile; out[1] = level; out[2] = width; out[3] = height
110 out[4] = w_m1; out[5] = h_m1; out[6] = frame_mbs_only; out[7] = chroma
111 return 0
112}