PPS结构解析
与之前解析SPS方式类似一、定义PPS类:
在3.NAL Unit
目录下,新建PicParamSet.cpp
和PicParamSet.h
,在这两个文件中写入类的定义和函数实现。
类定义写在PicParamSet.h
文件中,定义待解析语法元素变量,并定义相应的setter函数,代码如下:
#ifndef _PICPARAM_SET_H#define _PICPARAM_SET_Hclass 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中,并从中解析,代码如下:
#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);}
二、解析NALUnit中PPS数据:
1. 添加解析有符号指数哥伦布编码函数:
由于PPS语法元素中包含有符号指数哥伦布编码的数据,这里新建一个函数Get_sev_code_num
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() 用于解析语法元素,代码如下。(均按照中官方文档顺序解析即可)
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;}
三、添加调用部分:
回到Stream.cpp
中,找到Parse_h264_bitstream() 函数中switch (nalType)条件分支,在后面添加解析序列参数集pps的部分:
case 8: // 解析PPS NAL 数据 if (m_pps) { delete m_pps; } m_pps = new CPicParamSet; nalUint.Parse_as_pic_param_set(m_pps); break;