Sequence Paramater Set(NAL Unit=7)
SPS和PPS一般处于码流的起始位置,但也可能出现在码流中间,主要原因是:
1、解码器需要在码流中间开始解码;
2、编码器在编码的过程中改变了码流的参数(如图像分辨率等);
SPS结构(H264文档7.3.2.1)
/**
Sequence Parameter Set
@see 7.3.2.1 Sequence parameter set RBSP syntax
*/
typedef struct
{
int profile_idc; // u(8)
/* —————————— 编码级别的制约条件 Start —————————— */
int constraint_set0_flag; // u(1)
int constraint_set1_flag; // u(1)
int constraint_set2_flag; // u(1)
int constraint_set3_flag; // u(1)
int constraint_set4_flag; // u(1)
int constraint_set5_flag; // u(1)
int reserved_zero_2bits; // u(2)
/* —————————— 编码级别的制约条件 End —————————— */
int level_idc; // u(8)
int seq_parameter_set_id; // ue(v)
/* —————————— 几个罕见级别对应的句法元素 Start —————————— */
/*
if( profile_idc = = 100 | | profile_idc = = 110 | |
profile_idc = = 122 | | profile_idc = = 244 | |
profile_idc = = 44 | | profile_idc = = 83 | |
profile_idc = = 86 | | profile_idc = = 118 | |
profile_idc = = 128 | | profile_idc = = 138 | |
profile_idc = = 139 | | profile_idc = = 134 | |
profile_idc = = 135 ) {
*/
int chroma_format_idc; // ue(v)
// if( chroma_format_idc = = 3 )
int separate_colour_plane_flag; // u(1)
int bit_depth_luma_minus8; // ue(v)
int bit_depth_chroma_minus8; // ue(v)
int qpprime_y_zero_transform_bypass_flag; // u(1)
int seq_scaling_matrix_present_flag; // u(1)
// if( seq_scaling_matrix_present_flag )
// for( i = 0; i < ( ( chroma_format_idc != 3 ) ? 8 : 12 ); i++ ) {
int seq_scaling_list_present_flag[12]; // 最大值12数组 // u(1)
// if( seq_scaling_list_present_flag[ i ] )
// if( i < 6 )
int ScalingList4x4[6][16]; // 二维数组遍历
int UseDefaultScalingMatrix4x4Flag[6];
// else
int ScalingList8x8[6][64];
int UseDefaultScalingMatrix8x8Flag[6];
/* —————————— 几个罕见级别对应的句法元素 End —————————— */
/* —————————— 用来计算POC的句法元素 Start —————————— */
int log2_max_frame_num_minus4; // ue(v)
int pic_order_cnt_type; // ue(v)
// if( pic_order_cnt_type = = 0 )
int log2_max_pic_order_cnt_lsb_minus4; // ue(v)
// else if( pic_order_cnt_type = = 1 ) {
int delta_pic_order_always_zero_flag; // u(1)
int offset_for_non_ref_pic; // se(v)
int offset_for_top_to_bottom_field; // se(v)
int num_ref_frames_in_pic_order_cnt_cycle; // ue(v)
// for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )
int offset_for_ref_frame[256]; // 最大值256数组 // se(v)
/* —————————— 用来计算POC的句法元素 End —————————— */
int max_num_ref_frames; // ue(v)
int gaps_in_frame_num_value_allowed_flag; // u(1)
/* —————————— 图像宽高相关 Start —————————— */
int pic_width_in_mbs_minus1; // ue(v)
int pic_height_in_map_units_minus1; // ue(v)
int frame_mbs_only_flag; // u(1)
// if( !frame_mbs_only_flag )
int mb_adaptive_frame_field_flag; // u(1)
/* —————————— 图像宽高相关 End —————————— */
int direct_8x8_inference_flag; // u(1)
/* —————————— 解码后图像剪裁的几个句法元素 Start —————————— */
int frame_cropping_flag; // u(1)
// if( frame_cropping_flag ) {
int frame_crop_left_offset; // ue(v)
int frame_crop_right_offset; // ue(v)
int frame_crop_top_offset; // ue(v)
int frame_crop_bottom_offset; // ue(v)
/* —————————— 解码后图像剪裁的几个句法元素 End —————————— */
int vui_parameters_present_flag; // u(1)
// if( vui_parameters_present_flag )
vui_parameters_t vui_parameters; // Annex E E.1.1
} sps_t;
要注意里面有些句法元素,需要结合它前后的语法结构,和它的语义推敲得来。比如scaling_list相关几个数组,它们的数组大小是根据for循环的遍历次数得来。而且ScalingList4x4和ScalingList8x8被定义为了二维数组,因为在调用scaling_list()时,传进去的ScalingList4x4[i]本身是个一维数组,因此ScalingList4x4是二维数组。
而其中数组offset_for_ref_frame[]的大小,是由for循环的次数num_ref_frames_in_pic_order_cnt_cycle决定的,我们已经知道num_ref_frames_in_pic_order_cnt_cycle的取值为[0,255],因此数组offset_for_ref_frame[]的大小就是256。
SPS中的子结构体VUI_parameters(见E.1.1)
/**
vui_parameters()
@see Annex E E.1.1 VUI parameters syntax
*/
typedef struct {
int aspect_ratio_info_present_flag; // u(1)
// if( aspect_ratio_info_present_flag ) {
int aspect_ratio_idc; // u(8)
// if( aspect_ratio_idc = = Extended_SAR ) {
int sar_width; // u(16)
int sar_height; // u(16)
int overscan_info_present_flag; // u(1)
// if( overscan_info_present_flag )
int overscan_appropriate_flag; // u(1)
int video_signal_type_present_flag; // u(1)
// if( video_signal_type_present_flag ) {
int video_format; // u(3)
int video_full_range_flag; // u(1)
int colour_d