PPS結構解析 與以前解析SPS方式相似函數
在3.NAL Unit
目錄下,新建PicParamSet.cpp
和PicParamSet.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); }
因爲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; }
在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; }
回到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;