天天看點

【H264解析Demo】7、解析Slice Header1、理論依據2、類定義3、slice解析總結

理論知識參考

十一、H.264的Slice Header解析

1、理論依據

【H264解析Demo】7、解析Slice Header1、理論依據2、類定義3、slice解析總結
【H264解析Demo】7、解析Slice Header1、理論依據2、類定義3、slice解析總結

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解析之間的互動

繼續閱讀