理论知识参考
十一、H.264的Slice Header解析
1、理论依据
2、类定义
slice头部
//解析slice头部
class CSliceHeader
{
public:
CSliceHeader(UINT8 *pSODB, CSeqParamSet *sps, CPicParamSet *pps, UINT8 nalType);
~CSliceHeader();
UINT32 Parse_slice_header(); //解析slice头部
int m_disable_deblocking_filter_idc;
int m_slice_alpha_c0_offset;
int m_slice_beta_offset;
private:
CSeqParamSet *m_sps_active;
CPicParamSet *m_pps_active;
UINT8 *m_pSODB;
UINT8 m_nalType;
/* slice头信息*/
UINT16 m_first_mb_in_slice; //当前slice中包含的第一个宏块在整帧中的位置
UINT8 m_slice_type; //当前slice的类型
UINT8 m_pps_id; //slice所依赖的pps的id
UINT8 m_colour_plane_id; //表示当前的颜色分量,0、1、2分别表示Y、U、V分量
UINT32 m_frame_num; //表示当前帧序号的一种计量方式
bool m_field_pic_flag; //场编码标识位
bool m_bottom_field_flag; //底场标识位
UINT16 m_idr_pic_id; //表示IDR帧的序号
UINT32 m_poc; //表示当前帧序号的另一种计量方式
int m_delta_poc_bottom; // 表示顶场与底场POC差值的计算方法,不存在则默认为0
DecRefPicMarking m_dec_ref_pic_marking;
int m_slice_qp_delta; // 用于计算 当前slice内所使用的初始qp
};
slice整体
class CSliceStruct
{
public:
CSliceStruct(UINT8 *pSODB, CSeqParamSet *sps, CPicParamSet *pps, UINT8 nalType, UINT32 sliceIdx);
~CSliceStruct();
CSliceHeader *m_sliceHeader;
int Parse();
CSeqParamSet *m_sps_active; //解析所依赖的序列参数集SPS
CPicParamSet *m_pps_active; //解析所依赖的图像参数集PPS
private:
UINT8 *m_pSODB;
UINT8 m_nalType; //是否为IDR
UINT32 m_sliceIdx;
UINT16 m_max_mb_number;
};
3、slice解析
解析slice头
UINT32 CSliceHeader::Parse_slice_header()
{
UINT32 sliceHeaderLengthInBits = 0; //sliceHeader占据了整个slice多长的bit
UINT8 bitPosition = 0;
UINT32 bytePosition = 0;
m_first_mb_in_slice = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);
m_slice_type = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);
m_slice_type %= 5;
m_pps_id = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);
if (m_sps_active->Get_separate_colour_plane_flag()) /* 根据协议,需要根据sps中的字段来决定 */
{
m_colour_plane_id = Get_uint_code_num(m_pSODB, bytePosition, bitPosition, 2);
}
m_frame_num = Get_uint_code_num(m_pSODB, bytePosition, bitPosition, m_sps_active->Get_log2_max_frame_num());
if (!m_sps_active->Get_frame_mbs_only_flag()) /* 是否仅为帧编码 */
{
m_field_pic_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition); /* 获取场编码标志位 */
if (m_field_pic_flag)
{
m_bottom_field_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
}
}
if (m_nalType == 5) /* 如果是IDR帧才获取IDR帧的序号 */
{
m_idr_pic_id = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);
}
if (m_sps_active->Get_poc_type() == 0)
{
m_poc = Get_uint_code_num(m_pSODB, bytePosition, bitPosition, m_sps_active->Get_log2_max_poc_cnt()); /* 根绝POC最大长度来获取 */
if ((!m_field_pic_flag) && m_pps_active->Get_bottom_field_pic_order_in_frame_present_flag())
{
m_delta_poc_bottom = Get_sev_code_num(m_pSODB, bytePosition, bitPosition);
}
}
if (m_nalType == 5)
{
m_dec_ref_pic_marking.no_output_of_prior_pics_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
m_dec_ref_pic_marking.long_term_reference_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
}
m_slice_qp_delta = Get_sev_code_num(m_pSODB, bytePosition, bitPosition);
if (m_pps_active->Get_deblocking_filter_control_present_flag())
{
m_disable_deblocking_filter_idc = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);
if (m_disable_deblocking_filter_idc != 1)
{
m_slice_alpha_c0_offset = 2 * Get_sev_code_num(m_pSODB, bytePosition, bitPosition);
m_slice_beta_offset = 2 * Get_sev_code_num(m_pSODB, bytePosition, bitPosition);
}
}
sliceHeaderLengthInBits = 8 * bytePosition + bitPosition;
return sliceHeaderLengthInBits;
}
解析slice整体
int CSliceStruct::Parse()
{
UINT32 sliceHeaderLength = 0;
m_sliceHeader = new CSliceHeader(m_pSODB, m_sps_active, m_pps_active, m_nalType);
sliceHeaderLength = m_sliceHeader->Parse_slice_header(); //返回sliceHeader占用的位数,方便解析slice内容
/* 后面开始解析一个个的宏块 */
return kPARSING_ERROR_NO_ERROR;
}
总结
本节重点需要了解的是slice的解析是用到sps中的成员的,体会sps和slice解析之间的交互