code wiki / (root) / nx_h264_slice.nx

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}