code wiki / (root) / nx_h264_sps.nx

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}