nx_h264_slice.nx source
↩ module page · 111 lines · 6051 B
1// nx_h264_slice.nx -- H.264 slice header parser (rung 4a, spec 7.3.3).
2// Extracts the fields the macroblock loop needs: first_mb_in_slice, slice_type
3// (I/P/B via %5), pic_parameter_set_id, frame_num, idr_pic_id, pic_order_cnt_lsb,
4// slice_qp_delta -> actual QP = pic_init_qp + slice_qp_delta.
5//
6// Needs SPS/PPS context (log2_max_frame_num, log2_max_poc_lsb, pic_order_cnt_type,
7// frame_mbs_only_flag, pic_init_qp) -> passed in (honest: a slice header cannot be
8// parsed without it). Scoped to the common IDR/non-IDR I-slice, CAVLC, poc_type 0,
9// frame_mbs_only path; P/B ref-list modification, adaptive ref marking, and
10// delta_pic_order_cnt are NOT parsed (flagged) -- that is the slice-data rung.
11//
12// genealogy_id: itu_t_h264_sec7_3_3_slice_header
13// lineage_id: slice_type_first_mb_framenum + slice_qp
14// license_tier: ORIGINAL
15import "nx_syscalls.nx"
16import "nx_h264_bits.nx"
17
18// out[0]=first_mb [1]=slice_type [2]=pps_id [3]=frame_num [4]=idr_pic_id(-1 if not IDR)
19// [5]=pic_order_cnt_lsb [6]=slice_qp_delta [7]=qp [8]=slice_type_mod5 (2=I,0=P,1=B)
20// Parse on a caller-supplied BitReader, leaving it positioned at slice_data (so the
21// macroblock layer can continue reading from the same reader).
22func nx_h264_parse_slice_header_br(br: *BitReader, nal_type: i64, nal_ref_idc: i64, log2_frame_num: i64, log2_poc_lsb: i64, poc_type: i64, frame_mbs_only: i64, pic_init_qp: i64, deblock_present: i64, out: *i64) -> i64 {
23 var i: i64 = 0
24 while i < 15 { out[i] = 0; i = i + 1 }
25 var is_idr: i64 = 0
26 if nal_type == 5 { is_idr = 1 }
27 out[0] = br_read_ue(br) // first_mb_in_slice
28 let st: i64 = br_read_ue(br)
29 out[1] = st
30 out[8] = st % 5
31 out[2] = br_read_ue(br) // pic_parameter_set_id
32 out[3] = br_read_bits(br, log2_frame_num) // frame_num
33 if frame_mbs_only == 0 {
34 let fp: i64 = br_read_bits(br, 1) // field_pic_flag
35 if fp == 1 { br_read_bits(br, 1) } // bottom_field_flag
36 }
37 out[4] = 0 - 1
38 if is_idr == 1 { out[4] = br_read_ue(br) } // idr_pic_id
39 if poc_type == 0 { out[5] = br_read_bits(br, log2_poc_lsb) } // pic_order_cnt_lsb
40 // ---- P-slice (slice_type%5==0): ref-index override + ref_pic_list_modification ----
41 out[12] = 0 // num_ref_idx_l0_active_minus1 (default; PPS default if no override)
42 if (st % 5) == 0 {
43 let ovr: i64 = br_read_bits(br, 1) // num_ref_idx_active_override_flag
44 if ovr == 1 { out[12] = br_read_ue(br) } // num_ref_idx_l0_active_minus1
45 let rplm: i64 = br_read_bits(br, 1) // ref_pic_list_modification_flag_l0
46 if rplm == 1 {
47 var midc: i64 = br_read_ue(br)
48 while midc != 3 {
49 br_read_ue(br) // abs_diff_pic_num_minus1 / long_term_pic_num
50 midc = br_read_ue(br)
51 }
52 }
53 }
54 // ---- B-slice (slice_type%5==1): direct_spatial flag, L0+L1 ref-index override + both ref_pic_list_mods ----
55 out[13] = 0 // num_ref_idx_l1_active_minus1
56 out[14] = 0 // direct_spatial_mv_pred_flag (1=spatial, 0=temporal)
57 if (st % 5) == 1 {
58 out[14] = br_read_bits(br, 1) // direct_spatial_mv_pred_flag (read FIRST, before override)
59 let ovr: i64 = br_read_bits(br, 1) // num_ref_idx_active_override_flag
60 if ovr == 1 { out[12] = br_read_ue(br); out[13] = br_read_ue(br) }
61 let rplm0: i64 = br_read_bits(br, 1) // ref_pic_list_modification_flag_l0
62 if rplm0 == 1 {
63 var m0: i64 = br_read_ue(br)
64 while m0 != 3 { br_read_ue(br); m0 = br_read_ue(br) }
65 }
66 let rplm1: i64 = br_read_bits(br, 1) // ref_pic_list_modification_flag_l1
67 if rplm1 == 1 {
68 var m1: i64 = br_read_ue(br)
69 while m1 != 3 { br_read_ue(br); m1 = br_read_ue(br) }
70 }
71 // (weighted_bipred_idc==0 here -> no pred_weight_table; x264 --no-weightb)
72 }
73 // ---- dec_ref_pic_marking ----
74 if is_idr == 1 { br_read_bits(br, 1); br_read_bits(br, 1) } // no_output_of_prior + long_term_reference (IDR)
75 if is_idr == 0 {
76 if nal_ref_idc > 0 {
77 let amf: i64 = br_read_bits(br, 1) // adaptive_ref_pic_marking_mode_flag
78 if amf == 1 {
79 var mmco: i64 = br_read_ue(br)
80 while mmco != 0 {
81 if mmco == 1 { br_read_ue(br) }
82 if mmco == 2 { br_read_ue(br) }
83 if mmco == 3 { br_read_ue(br); br_read_ue(br) }
84 if mmco == 4 { br_read_ue(br) }
85 if mmco == 6 { br_read_ue(br) }
86 mmco = br_read_ue(br)
87 }
88 }
89 }
90 }
91 let d: i64 = br_read_se(br) // slice_qp_delta
92 out[6] = d
93 out[7] = pic_init_qp + d
94 // deblocking-filter slice fields (present iff PPS deblocking_filter_control_present_flag)
95 if deblock_present == 1 {
96 let idc: i64 = br_read_ue(br) // disable_deblocking_filter_idc
97 out[9] = idc
98 if idc != 1 {
99 out[10] = br_read_se(br) * 2 // FilterOffsetA = slice_alpha_c0_offset_div2 << 1
100 out[11] = br_read_se(br) * 2 // FilterOffsetB = slice_beta_offset_div2 << 1
101 }
102 }
103 return 0
104}
105
106// convenience wrapper: parse from an rbsp buffer (allocates its own reader)
107func nx_h264_parse_slice_header(rbsp: *u8, len: i64, nal_type: i64, nal_ref_idc: i64, log2_frame_num: i64, log2_poc_lsb: i64, poc_type: i64, frame_mbs_only: i64, pic_init_qp: i64, deblock_present: i64, out: *i64) -> i64 {
108 let br: *BitReader = sys_mmap(NX_BR_BYTES) as *BitReader
109 br_init(br, rbsp, len)
110 return nx_h264_parse_slice_header_br(br, nal_type, nal_ref_idc, log2_frame_num, log2_poc_lsb, poc_type, frame_mbs_only, pic_init_qp, deblock_present, out)
111}