首先NALU的构成如下,图来自网上。
其中SPS的语法根据文档ITU-T H264中表格7.3.2.1.1可知
根据H264文档ITU-T H264中表格7.3.2.1.1 Sequence parameter set data syntax可知,SPS有以下信息:
表中的描述符Descriptor的含义如下,
下面用代码去解析,源码来自雷霄骅
首先将NAL转为RBSP
int nal_to_rbsp(const uint8_t* nal_buf, int* nal_size, uint8_t* rbsp_buf, int* rbsp_size) {
int i;
int j = 0;
int count = 0;
for( i = 1; i < *nal_size; i++ ){
// in NAL unit, 0x000000, 0x000001 or 0x000002 shall not occur at any byte-aligned position
if( ( count == 2 ) && ( nal_buf[i] < 0x03) )
return -1;
if( ( count == 2 ) && ( nal_buf[i] == 0x03) ) {
// check the 4th byte after 0x000003, except when cabac_zero_word is used, in which case the last three bytes of this NAL unit must be 0x000003
if((i < *nal_size - 1) && (nal_buf[i+1] > 0x03))
return -1;
// if cabac_zero_word is used, the final byte of this NAL unit(0x03) is discarded, and the last two bytes of RBSP must be 0x0000
if(i == *nal_size - 1)
break;
i++;
count = 0;
}
if ( j >= *rbsp_size ) {
// error, not enough space
return -1;
}
rbsp_buf[j] = nal_buf[i];
if(nal_buf[i] == 0x00)
count++;
else
count = 0;
j++;
}
*nal_size = i;
*rbsp_size = j;
return j;
}
转换出来的rbsp可以使用h264bitstream库来解析,bs_xxx这些是库的内容
void read_seq_parameter_set_rbsp(bs_t* b) {
int i;
// NOTE can't read directly into sps because seq_parameter_set_id not yet known and so sps is not selected
int profile_idc = bs_read_u8(b);
int constraint_set0_flag = bs_read_u1(b);
int constraint_set1_flag = bs_read_u1(b);
int constraint_set2_flag = bs_read_u1(b);
int constraint_set3_flag = bs_read_u1(b);
int constraint_set4_flag = bs_read_u1(b);
int constraint_set5_flag = bs_read_u1(b);
int reserved_zero_2bits = bs_read_u(b,2); /* all 0's */
int level_idc = bs_read_u8(b);
int seq_parameter_set_id = bs_read_ue(b);
// select the correct sps
h->sps = h->sps_table[seq_parameter_set_id];
sps_t* sps = h->sps;
memset(sps, 0, sizeof(sps_t));
sps->chroma_format_idc = 1;
sps->profile_idc = profile_idc; // bs_read_u8(b);
sps->constraint_set0_flag = constraint_set0_flag;//bs_read_u1(b);
sps->constraint_set1_flag = constraint_set1_flag;//bs_read_u1(b);
sps->constraint_set2_flag = constraint_set2_flag;//bs_read_u1(b);
sps->constraint_set3_flag = constraint_set3_flag;//bs_read_u1(b);
sps->constraint_set4_flag = constraint_set4_flag;//bs_read_u1(b);
sps->constraint_set5_flag = constraint_set5_flag;//bs_read_u1(b);
sps->reserved_zero_2bits = reserved_zero_2bits;//bs_read_u(b,2);
sps->level_idc = level_idc; //bs_read_u8(b);
sps->seq_parameter_set_id = seq_parameter_set_id; // bs_read_ue(b);
if( sps->profile_idc == 100 || sps->profile_idc == 110 ||
sps->profile_idc == 122 || sps->profile_idc == 144 ) {
sps->chroma_format_idc = bs_read_ue(b);
if( sps->chroma_format_idc == 3 ) {
sps->residual_colour_transform_flag = bs_read_u1(b);
}
sps->bit_depth_luma_minus8 = bs_read_ue(b);
sps->bit_depth_chroma_minus8 = bs_read_ue(b);
sps->qpprime_y_zero_transform_bypass_flag = bs_read_u1(b);
sps->seq_scaling_matrix_present_flag = bs_read_u1(b);
if( sps->seq_scaling_matrix_present_flag ){
for( i = 0; i < 8; i++ ){
sps->seq_scaling_list_present_flag[ i ] = bs_read_u1(b);
if( sps->seq_scaling_list_present_flag[ i ] ){
if( i < 6 ){
read_scaling_list( b, sps->ScalingList4x4[ i ], 16,
sps->UseDefaultScalingMatrix4x4Flag[ i ]);
}else{
read_scaling_list( b, sps->ScalingList8x8[ i - 6 ], 64,
sps->UseDefaultScalingMatrix8x8Flag[ i - 6 ] );
}
}
}
}
}
sps->log2_max_frame_num_minus4 = bs_read_ue(b);
sps->pic_order_cnt_type = bs_read_ue(b);
if( sps->pic_order_cnt_type == 0 ){
sps->log2_max_pic_order_cnt_lsb_minus4 = bs_read_ue(b);
}else if( sps->pic_order_cnt_type == 1 ){
sps->delta_pic_order_always_zero_flag = bs_read_u1(b);
sps->offset_for_non_ref_pic = bs_read_se(b);
sps->offset_for_top_to_bottom_field = bs_read_se(b);
sps->num_ref_frames_in_pic_order_cnt_cycle = bs_read_ue(b);
for( i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++ ){
sps->offset_for_ref_frame[ i ] = bs_read_se(b);
}
}
sps->num_ref_frames = bs_read_ue(b);
sps->gaps_in_frame_num_value_allowed_flag = bs_read_u1(b);
sps->pic_width_in_mbs_minus1 = bs_read_ue(b);
sps->pic_height_in_map_units_minus1 = bs_read_ue(b);
sps->frame_mbs_only_flag = bs_read_u1(b);
if( !sps->frame_mbs_only_flag ){
sps->mb_adaptive_frame_field_flag = bs_read_u1(b);
}
sps->direct_8x8_inference_flag = bs_read_u1(b);
sps->frame_cropping_flag = bs_read_u1(b);
if( sps->frame_cropping_flag ){
sps->frame_crop_left_offset = bs_read_ue(b);
sps->frame_crop_right_offset = bs_read_ue(b);
sps->frame_crop_top_offset = bs_read_ue(b);
sps->frame_crop_bottom_offset = bs_read_ue(b);
}
sps->vui_parameters_present_flag = bs_read_u1(b);
if( sps->vui_parameters_present_flag ){
read_vui_parameters(h, b);
}
read_rbsp_trailing_bits(b);
}
更多详细的内容在视音频编解码学习工程:H.264分析器《雷霄骅》