【視頻編解碼·學習筆記】13. 提取PPS信息程序

PPS結構解析 與以前解析SPS方式相似函數

1、定義PPS類:

3.NAL Unit目錄下,新建PicParamSet.cppPicParamSet.h,在這兩個文件中寫入類的定義和函數實現。學習

類定義寫在PicParamSet.h文件中,定義待解析語法元素變量,並定義相應的setter函數,代碼以下:編碼

#ifndef _PICPARAM_SET_H
#define _PICPARAM_SET_H

class CPicParamSet
{
public:
	CPicParamSet();
	~CPicParamSet();

	void Set_pps_id(UINT8 ppsID);
	void Set_sps_id(UINT8 spsID);
	void Set_num_slice_groups(UINT8 num_slice_grops);
	void Set_num_ref_idx(UINT8 l0, UINT8 l1);
	void Set_weighted_bipred_idc(UINT8 weighted_bipred_idc);
	void Set_pic_init_qp(int pic_init_qp);
	void Set_pic_init_qs(int pic_init_qs);
	void Set_chroma_qp_index_offset(int chroma_qp_index_offset);
	void Set_multiple_flags(UINT16 flags);

private:
	UINT8  m_pps_id;
	UINT8  m_sps_id;
	bool   m_entropy_coding_flag;
	bool   m_bottom_field_pic_order_in_frame_present_flag;
	UINT8  m_num_slice_groups;
	UINT8  m_num_ref_idx_l0_default_active;
	UINT8  m_num_ref_idx_l1_default_active;
	bool   m_weighted_pred_flag;
	UINT8  m_weighted_bipred_idc;
	int    m_pic_init_qp;
	int    m_pic_init_qs;
	int    m_chroma_qp_index_offset;
	bool   m_deblocking_filter_control_present_flag;
	bool   m_constrained_intra_pred_flag;
	bool   m_redundant_pic_cnt_present_flag;
	bool   m_transform_8x8_mode_flag;
};

#endif // !_PICPARAM_SET_H

setter函數具體實現寫在PicParamSet.cpp中,均爲簡單的set賦值方法,全部的標誌位仍按位存在一個flag中,並從中解析,代碼以下:spa

#include "stdafx.h"
#include "PicParamSet.h"

CPicParamSet::CPicParamSet()
{
}

CPicParamSet::~CPicParamSet()
{
}

void CPicParamSet::Set_pps_id(UINT8 ppsID)
{
	m_pps_id = ppsID;
}

void CPicParamSet::Set_sps_id(UINT8 spsID)
{
	m_sps_id = spsID;
}

void CPicParamSet::Set_num_slice_groups(UINT8 num_slice_grops)
{
	m_num_slice_groups = num_slice_grops;
}

void CPicParamSet::Set_num_ref_idx(UINT8 l0, UINT8 l1)
{
	m_num_ref_idx_l0_default_active = l0;
	m_num_ref_idx_l1_default_active = l1;
}

void CPicParamSet::Set_weighted_bipred_idc(UINT8 weighted_bipred_idc)
{
	m_weighted_bipred_idc = weighted_bipred_idc;
}

void CPicParamSet::Set_pic_init_qp(int pic_init_qp)
{
	m_pic_init_qp = pic_init_qp;
}

void CPicParamSet::Set_pic_init_qs(int  pic_init_qs)
{
	m_pic_init_qs = pic_init_qs;
}

void CPicParamSet::Set_chroma_qp_index_offset(int chroma_qp_index_offset)
{
	m_chroma_qp_index_offset = chroma_qp_index_offset;
}

void CPicParamSet::Set_multiple_flags(UINT16 flags)
{
	m_entropy_coding_flag = flags & 1;
	m_bottom_field_pic_order_in_frame_present_flag = flags & (1 << 1);
	m_weighted_pred_flag = flags & (1 << 2);
	m_deblocking_filter_control_present_flag = flags & (1 << 3);
	m_constrained_intra_pred_flag = flags & (1 << 4);
	m_redundant_pic_cnt_present_flag = flags & (1 << 5);
}

2、解析NALUnit中PPS數據:

1. 添加解析有符號指數哥倫布編碼函數:

因爲PPS語法元素中包含有符號指數哥倫布編碼的數據,這裏新建一個函數Get_sev_code_num 無符號指數哥倫布編碼(k)轉爲有符號的(n)公式:$n = (-1)^{(k+1)} \times Ceil(k / 2)$code

int Get_sev_code_num(UINT8 * buf, UINT8 & bytePosition, UINT8 & bitPosition)
{
	int uev = Get_uev_code_num(buf, bytePosition, bitPosition);
	int sign = (uev % 2) ? 1 : -1;
	int sev = sign * ((uev + 1) >> 1);
	return sev;
}

2. 獲取PPS中各個成員變量的值:

在NALUnit.h和NALUnit.cpp中添加函數,Parse_as_seq_param_set() 用於解析語法元素,代碼以下。(均按照學習筆記12中官方文檔順序解析便可)orm

int CNalUnit::Parse_as_pic_param_set(CPicParamSet * pps)
{
	UINT8  pps_id = 0;
	UINT8  sps_id = 0;
	bool   entropy_coding_flag = 0;
	bool   bottom_field_pic_order_in_frame_present_flag = 0;
	UINT8  num_slice_groups = 0;
	UINT8  num_ref_idx_l0_default_active = 0;
	UINT8  num_ref_idx_l1_default_active = 0;
	bool   weighted_pred_flag = 0;
	UINT8  weighted_bipred_idc = 0;
	int    pic_init_qp = 0;
	int    pic_init_qs = 0;
	int    chroma_qp_index_offset = 0;
	bool   deblocking_filter_control_present_flag = 0;
	bool   constrained_intra_pred_flag = 0;
	bool   redundant_pic_cnt_present_flag = 0;


	UINT8 bitPosition = 0;
	UINT8 bytePosition = 0;
	UINT16 flags = 0;

	pps_id = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);
	sps_id = Get_uev_code_num(m_pSODB, bytePosition, bitPosition);

	entropy_coding_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
	flags |= entropy_coding_flag;
	bottom_field_pic_order_in_frame_present_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
	flags |= bottom_field_pic_order_in_frame_present_flag << 1;

	num_slice_groups = Get_uev_code_num(m_pSODB, bytePosition, bitPosition) + 1;

	if (1 != num_slice_groups)
	{
		return -1;
	}

	num_ref_idx_l0_default_active = Get_uev_code_num(m_pSODB, bytePosition, bitPosition) + 1;
	num_ref_idx_l1_default_active = Get_uev_code_num(m_pSODB, bytePosition, bitPosition) + 1;

	weighted_pred_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
	flags |= weighted_pred_flag << 2;

	// 這裏是獲取連續兩個比特位數據——把第一次獲取到的左移1位,再加上第二次獲取到的
	weighted_bipred_idc = Get_bit_at_position(m_pSODB, bytePosition, bitPosition) << 1 + Get_bit_at_position(m_pSODB, bytePosition, bitPosition);

	pic_init_qp = Get_sev_code_num(m_pSODB, bytePosition, bitPosition) + 26;
	pic_init_qs = Get_sev_code_num(m_pSODB, bytePosition, bitPosition) + 26;
	chroma_qp_index_offset = Get_sev_code_num(m_pSODB, bytePosition, bitPosition);

	deblocking_filter_control_present_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
	flags |= deblocking_filter_control_present_flag << 3;
	constrained_intra_pred_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
	flags |= constrained_intra_pred_flag << 4;
	redundant_pic_cnt_present_flag = Get_bit_at_position(m_pSODB, bytePosition, bitPosition);
	flags |= redundant_pic_cnt_present_flag << 5;

	pps->Set_pps_id(pps_id);
	pps->Set_sps_id(sps_id);
	pps->Set_num_slice_groups(num_slice_groups);
	pps->Set_num_ref_idx(num_ref_idx_l0_default_active, num_ref_idx_l1_default_active);
	pps->Set_weighted_bipred_idc(weighted_bipred_idc);
	pps->Set_pic_init_qp(pic_init_qp);
	pps->Set_pic_init_qs(pic_init_qs);
	pps->Set_chroma_qp_index_offset(chroma_qp_index_offset);
	pps->Set_multiple_flags(flags);

	return 0;
}

3、添加調用部分:

回到Stream.cpp中,找到Parse_h264_bitstream() 函數中switch (nalType)條件分支,在後面添加解析序列參數集pps的部分:ip

case 8:
	// 解析PPS NAL 數據
	if (m_pps)
	{
		delete m_pps;
	}
	m_pps = new CPicParamSet;
	nalUint.Parse_as_pic_param_set(m_pps);
	break;
相關文章
相關標籤/搜索