五、序列参数集Sequence Paramater Set(SP
2024-02-18 本文已影响0人
一亩三分甜
H264H265视频编解码算法文章汇总
1.序列参数集
-
序列参数集Sequence Paramater Set:
-
H.264码流中重要的组成部分,保存针对整个视频序列的参数;
-
丢失SPS的码流通常无法正常解码;
-
-
SPS在视频中保存:
-
封装视频格式:视频头
-
H.264裸码流:NAL Unit Type = 7
-
int CNALUnit::Parse_as_seq_param_set(CSeqParamSet *sps)
{
UINT8 profile_idc = 0;//表示profile的索引值
UINT8 level_idc = 0;//表示level值
UINT8 sps_id = 0;//sps id,当前sps id是多少,后面的pps根据此sps_id来引用sps中的参数,取值范围0-31
UINT8 chroma_format_idc = 0;//表示颜色色度索引,色度采样相对于亮度采样的比例,色度采样比,取值0-3,如果不存在,默认为1(4;2:0的色度模式)
bool separate_colour_plane_flag = 0;//若为1,表示4:4:4颜色空间当做3个图像进行编码,为0表明亮度和色度统一进行编码
UINT8 bit_depth_luma = 0;//亮度比特深度,一般为8
UINT8 bit_depth_chroma = 0;//色度比特深度,一般为8
bool qpprime_y_zero_transform_bypass_flag = 0;//若为1,对于亮度的量化参数为0,解码过程的变化系数和先于去块滤波器图像重建的过程的变换操作会被去掉或跳过,出于节省运算复杂度的考虑
bool seq_scaling_matrix_present_flag = 0;//量化矩阵,若为1,后面还会存在量化矩阵的数据表,若为0,后续的数据表就不存在。不常用
UINT32 max_frame_num = 0;//log2_max_frame_num_minus4 frame_num的取值范围上限,frame_num 和 poc在后面帧间编码中标记参考帧的序号索引是非常重要的
UINT8 poc_type = 0;//表示如何解码picture order count的过程,取值范围0-2
UINT32 max_poc_cnt = 0;//表示poc图像索引值的上限
UINT32 max_num_ref_frames = 0;//表示参考帧数目允许的上限
bool gaps_in_frame_num_value_allowed_flag = 0;//gaps_in_frame_num_value_allowed_flag每一帧的frame_num是否允许不连续的情况
UINT16 pic_width_in_mbs = 0;//只计算实际值,图像以宏块为单位的宽度,这幅图像横着排了多少宏块,一个宏块在264中是16x16像素的,若图像的宽度为64个像素,横着只排了4个宏块
UINT16 pic_height_in_map_units = 0;//pic_height_in_map_units_minus1考虑了帧编码和场编码,若是帧编码,值为宏块的高度,若是场编码,则多一步的换算关系
UINT16 pic_height_in_mbs = 0;//图像实际高度,可通过m_frame_mbs_only_flag m_pic_width_in_mbs m_pic_height_in_map_units 计算得出
bool frame_mbs_only_flag = 0;//是否是帧编码或场编码,若为场编码下面还有一个参数mb_adaptive_frame_field_flag,是否采用了宏块级别的帧场自适应问题,宏块是否可以根据情况在帧编码和场编码间相互切换
bool mb_adaptive_frame_field_flag = 0;
bool direct_8x8_inference_flag = 0;//for B_Skip,B_Direct_16x16 and B_Direct_8x8推导亮度运动矢量的方法,具体采用什么方法,后续帧间编码会详细说明
bool frame_cropping_flag = 0;//若为1,在sps中会有图像裁剪偏移量(包含上下左右);若为0,裁剪偏移量在sps中并不存在,也就是图像完成解码后不需要任何裁剪
UINT32 frame_crop_offset[4] = {0};
bool vui_parameters_present_flag = 0;//表示vui_parameters( ) syntax structure是否存在,VUI表示视频的有用性信息,比如视频纵横比sar_width,sar_height,以及视频渲染过程中的一些辅助信息
//从缓冲区第三个字节开始解析sps
UINT8 bytePosition = 3, bitPosition = 0;
UINT32 flags = 0;
profile_idc = m_pSODB[0];
level_idc = m_pSODB[2];
sps_id = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);
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)
{
//获取颜色格式的值
chroma_format_idc = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);
if (chroma_format_idc == 3)
{
separate_colour_plane_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
flags |= (separate_colour_plane_flag << 21);
}
//色度bit深度
bit_depth_luma = Get_uev_code_num(m_pSODB, bytePosition, bitPosition) + 8;
//亮度bit深度
bit_depth_chroma = Get_uev_code_num(m_pSODB, bytePosition, bitPosition) + 8;
qpprime_y_zero_transform_bypass_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
flags |= (qpprime_y_zero_transform_bypass_flag << 20);
seq_scaling_matrix_present_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
flags |= (seq_scaling_matrix_present_flag << 19);
if (seq_scaling_matrix_present_flag)
{
//返回错误码
return -1;
}
}
max_frame_num = 1 << (Get_uev_code_num(m_pSODB, bytePosition, bitPosition) + 4);
poc_type = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);
if (0 == poc_type)
{
max_poc_cnt = 1 << (Get_uev_code_num(m_pSODB, bytePosition, bitPosition) + 4);
}
else
{
//暂时不支持这种格式
return -1;
}
max_num_ref_frames = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);
gaps_in_frame_num_value_allowed_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
//给中间暂时跳过的flag,留出一定扩展空间,给不支持的数据留空间,后续会支持此格式的数据
flags |= (gaps_in_frame_num_value_allowed_flag << 5);
pic_width_in_mbs = Get_uev_code_num(m_pSODB, bytePosition, bitPosition) + 1;
pic_height_in_map_units = Get_uev_code_num(m_pSODB, bytePosition, bitPosition) + 1;
frame_mbs_only_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
flags |= (frame_mbs_only_flag << 4);
if (!frame_mbs_only_flag)
{
mb_adaptive_frame_field_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
flags |= (mb_adaptive_frame_field_flag << 3);
}
direct_8x8_inference_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
flags |= (direct_8x8_inference_flag << 2);
//图像是否有裁剪
frame_cropping_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
flags |= (frame_cropping_flag << 1);
if (frame_cropping_flag)
{
for (int idx = 0; idx < 4; idx++) {
frame_crop_offset[idx] = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);
}
}
vui_parameters_present_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
flags |= vui_parameters_present_flag;
//vui_parameters() 保存视频的实用性参数包括图像纵横比信息,暂时不考虑,后面会解析vui信息
sps->Set_profile_level(profile_idc, level_idc);
sps->Set_sps_id(sps_id);
sps->Set_chroma_format_idc(chroma_format_idc);
sps->Set_bit_depth(bit_depth_luma, bit_depth_chroma);
sps->Set_max_frame_num(max_frame_num);
sps->Set_poc_type(poc_type);
sps->Set_max_poc_cnt(max_poc_cnt);
sps->Set_max_num_ref_frames(max_num_ref_frames);
sps->Set_sps_multiple_flags(flags);
sps->Set_pic_reslution_in_mbs(pic_width_in_mbs, pic_height_in_map_units);
if (frame_cropping_flag)
{
sps->Set_frame_crop_offset(frame_crop_offset);
}
//返回0表示解析sps正常
return 0;
}
image.png