一,Nalu解析
首先来介绍下h265(HEVC)nal单元头,与h264的nal层相比,h265的nal unit header有两个字节构成,如下图所示 :
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| F | Type | LayerId | TID |
+———— – +—————- – +
其语法如下表中的定义:
nal_unit_header( ) { |
Descriptor |
forbidden_zero_bit |
f(1) |
nal_unit_type |
u(6) |
nuh_reserved_zero_6bits |
u(6) |
nuh_temporal_id_plus1 |
u(3) |
} |
Nalu Type的定义:
enum NalUnitType
{
NAL_UNIT_CODED_SLICE_TRAIL_N = 0, // 0
NAL_UNIT_CODED_SLICE_TRAIL_R, // 1
NAL_UNIT_CODED_SLICE_TSA_N, // 2
NAL_UNIT_CODED_SLICE_TLA, // 3
NAL_UNIT_CODED_SLICE_STSA_N, // 4
NAL_UNIT_CODED_SLICE_STSA_R, // 5
NAL_UNIT_CODED_SLICE_RADL_N, // 6
NAL_UNIT_CODED_SLICE_DLP, // 7
NAL_UNIT_CODED_SLICE_RASL_N, // 8
NAL_UNIT_CODED_SLICE_TFD, // 9
NAL_UNIT_RESERVED_10,
NAL_UNIT_RESERVED_11,
NAL_UNIT_RESERVED_12,
NAL_UNIT_RESERVED_13,
NAL_UNIT_RESERVED_14,
NAL_UNIT_RESERVED_15, NAL_UNIT_CODED_SLICE_BLA, // 16
NAL_UNIT_CODED_SLICE_BLA, // 16
NAL_UNIT_CODED_SLICE_BLANT, // 17
NAL_UNIT_CODED_SLICE_BLA_N_LP, // 18
NAL_UNIT_CODED_SLICE_IDR, // 19 // Current name in the spec: IDR_W_DLP
NAL_UNIT_CODED_SLICE_IDR_N_LP, // 20
NAL_UNIT_CODED_SLICE_CRA, // 21
NAL_UNIT_RESERVED_22,
NAL_UNIT_RESERVED_23,
NAL_UNIT_RESERVED_24,
NAL_UNIT_RESERVED_25,
NAL_UNIT_RESERVED_26,
NAL_UNIT_RESERVED_27,
NAL_UNIT_RESERVED_28,
NAL_UNIT_RESERVED_29,
NAL_UNIT_RESERVED_30,
NAL_UNIT_RESERVED_31,
NAL_UNIT_VPS, // 32
NAL_UNIT_SPS, // 33
NAL_UNIT_PPS, // 34
NAL_UNIT_ACCESS_UNIT_DELIMITER, // 35
NAL_UNIT_EOS, // 36
NAL_UNIT_EOB, // 37
NAL_UNIT_FILLER_DATA, // 38
NAL_UNIT_SEI, // 39 Prefix SEI
NAL_UNIT_SEI_SUFFIX, // 40 Suffix SEI
NAL_UNIT_RESERVED_41,
NAL_UNIT_RESERVED_42,
NAL_UNIT_RESERVED_43,
NAL_UNIT_RESERVED_44,
NAL_UNIT_RESERVED_45,
NAL_UNIT_RESERVED_46,
NAL_UNIT_RESERVED_47,
NAL_UNIT_UNSPECIFIED_48,
NAL_UNIT_UNSPECIFIED_49,
NAL_UNIT_UNSPECIFIED_50,
NAL_UNIT_UNSPECIFIED_51,
NAL_UNIT_UNSPECIFIED_52,
NAL_UNIT_UNSPECIFIED_53,
NAL_UNIT_UNSPECIFIED_54,
NAL_UNIT_UNSPECIFIED_55,
NAL_UNIT_UNSPECIFIED_56,
NAL_UNIT_UNSPECIFIED_57,
NAL_UNIT_UNSPECIFIED_58,
NAL_UNIT_UNSPECIFIED_59,
NAL_UNIT_UNSPECIFIED_60,
NAL_UNIT_UNSPECIFIED_61,
NAL_UNIT_UNSPECIFIED_62,
NAL_UNIT_UNSPECIFIED_63,
NAL_UNIT_INVALID,
};
通过录制H265的ES流,进行分析NALU头,发现在有6种开头分别为:
1) 00 00 00 01 40 01
2) 00 00 00 01 42 01
3) 00 00 00 01 44 01
4) 00 00 00 01 4E 01
5) 00 00 00 01 26 01
6) 00 00 00 01 02 01
再根据H265的NALU类型定义分析,
00 00 00 01 40 01 的nuh_unit_type的值为32, 语义为视频参数集
00 00 00 01 42 01 的nuh_unit_type的值为33, 语义为序列参数集
00 00 00 01 44 01 的nuh_unit_type的值为34, 语义为图像参数集
00 00 00 01 4E 01 的nuh_unit_type的值为39, 语义为补充增强信息
00 00 00 01 26 01 的nuh_unit_type的值为19, 语义为可能有RADL图像的IDR图像的SS编码数据
00 00 00 01 02 01 的nuh_unit_type的值为1, 语义为被参考的后置图像,且非TSA、非STSA的SS编码数据
在编码过程中,从编码器获取码流的时候,1、2、3、4、5是在一帧数据当中。相当于H264的I帧。
二,SPS解析
一段HEVC码流可能包含一个或者多个编码视频序列CVS,每个CVS由一个随机接入点开始,即 IDR/BLA/CRA。在H.264和HEVC中,序列参数集SPS包含该CVS中所有slice需要的信息。SPS的内容大致可以分为几个部分:
1、自引ID;
2、解码相关信息,如档次级别、分辨率、子层数等;
3、某档次中的功能开关标识及该功能的参数;
4、对结构和变换系数编码灵活性的限制信息;
5、时域可分级信息;
6、VUI。
以下是对每一个语法元素的讨论解释:
1、sps_video_parameter_set_id
2、sps_max_sub_layers_minus1 : 该值+1表示引用该SPS的CVS所包含的最大时域子层数,取值范围0-6;本例取值为0,即只有1个时域子层;
3、sps_temporal_id_nesting_flag :标识时域可分级中的帧间预测参考帧的限制信息;此处该值取0【好像与标准文档里写的有点矛盾啊……】;
4、sps_seq_parameter_set_id :【其实在这个参数之前码流中还有很多数据没有解释清楚,留到以后看吧】本SPS的ID值,此处取0;
5、chroma_format_idc:色度采样格式,此处取值为1,代表采用4:2:0格式;
6、separate_colour_plane_flag :这个参数是4:4:4格式专用的,在本例中不存在;
7、pic_width_in_luma_samples和pic_height_in_luma_samples :图像的分辨率信息,用指数哥伦布编码,本例取176*144;
8、conformance_window_flag :指示一致窗口裁剪偏移参数conformance cropping window offset parameters的信息;此处取值为1,表示后续几位为conf_win_left_offset、conf_win_right_offset、conf_win_top_offset、conf_win_bottom_offset等参数;
9、bit_depth_luma_minus8 :指定了亮度矩阵的比特深度以及亮度量化参数范围偏移量;此处取0,表示每个亮度像素用8为表示,QpBdOffset参数为0;
10、bit_depth_chroma_minus8 :与bit_depth_luma_minus8类似,只不过是针对色度的;
11、log2_max_pic_order_cnt_lsb_minus4 :负责计算变量MaxPicOrderCntLsb的值【这个值是干嘛的……】;
12、sps_sub_layer_ordering_info_present_flag :时域子层顺序标识开关,该值取1,表示后续几位分别是sps_max_dec_pic_buffering、sps_num_reorder_pics、sps_max_latency_increase等参数;
13、log2_min_coding_block_size_minus3 :用于计算最小亮度CB的尺寸,此处取0;
14、log2_diff_max_min_coding_block_size :用于计算最大最小亮度CB尺寸的差值,此处取3;
15、log2_min_transform_block_size_minus2:用于计算最小TB尺寸,此处取0;
16、log2_diff_max_min_transform_block_size :用于计算最大最小TB尺寸的差值,此处取3;
17、max_transform_hierarchy_depth_inter :帧间模式CB中TB的最大层级深度,此处为2;
18、max_transform_hierarchy_depth_intra ::帧内模式CB中TB的最大层级深度,此处为2;
19、scaling_list_enabled_flag:标识是否在变换系数量化中使用量化列表,此处取0;
20、amp_enabled_flag :标识是否使用不对称运动划分,此处为1;
21、sample_adaptive_offset_enabled_flag :标识是否使用SAO,此处为1;
22、pcm_enabled_flag :标识是否使用PCM,此处为0,即不实用PCM数据;
23、num_short_term_ref_pic_sets :指示SPS中short_term_ref_pic_set(
24、long_term_ref_pics_present_flag :指示帧间预测中是否使用长期参考帧,此处为1,即使用长期参考帧;
25、sps_temporal_mvp_enable_flag :标识CVS中非IDR帧的条带头中是否包含slice_temporal_mvp_enabled_flag标识,此处为1,即含有;
26、sps_strong_intra_smoothing_enable_flag :标识平滑滤波过程中是否使用双线性差值方法,此处为1,即使用;
27、vui_parameters_present_flag :标识是否有
以下是解析代码
1、重新定义类型
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned longuint32;
typedef unsigned __int64uint64;
typedef signed charint8;
typedef signed shortint16;
typedef signed longint32;
typedef signed __int64int64;
2、定义Sps 需要的相关参数
struct vc_params_t
{
LONG width,height;
DWORD profile, level;
DWORD nal_length_size;
void clear()
{
memset(this, 0, sizeof(*this));
}
};
3、定义网络抽象层Nal类
class NALBitstream
{
public:
NALBitstream() : m_data(NULL), m_len(0), m_idx(0), m_bits(0), m_byte(0), m_zeros(0)
{
};
NALBitstream(void * data, int len)
{
Init(data, len);
};
void Init(void * data, int len)
{
m_data = (LPBYTE)data;
m_len = len;
m_idx = 0;
m_bits = 0;
m_byte = 0;
m_zeros = 0;
};
BYTE GetBYTE(){
if ( m_idx >= m_len )
return 0;
BYTE b = m_data[m_idx++];
if ( b == 0 )
{
m_zeros++;
if ( (m_idx < m_len) && (m_zeros == 2) && (m_data[m_idx] == 0x03) )
{
m_idx++;
m_zeros=0;
}
}
else m_zeros = 0;
return b;};
UINT32 GetBit()
{
if (m_bits == 0)
{
m_byte = GetBYTE();
m_bits = 8;
}
m_bits—;return (m_byte >> m_bits) & 0x1;
};
UINT32 GetWord(int bits)
{
UINT32 u = 0;
while ( bits > 0 )
{
u <<= 1;
u |= GetBit();
bits—;
}
return u;
};
UINT32 GetUE()
{
int zeros = 0;
while (m_idx < m_len && GetBit() == 0 )
zeros++;return GetWord(zeros) + ((1 << zeros) – 1);
};
INT32 GetSE()
{
UINT32 UE = GetUE();
bool positive = UE & 1;
INT32 SE = (UE + 1) >> 1;
if ( !positive )
SE = –SE;
return SE;
};
private:LPBYTE m_data;
int m_len;
int m_idx;int m_bits;
BYTE m_byte;
int m_zeros;
};
bool ParseSequenceParameterSet(BYTE* data,int size, vc_params_t& params)
{
if (size < 20)
return false;
NALBitstream bs(data, size);
// seq_parameter_set_rbsp()
bs.GetWord(4);// sps_video_parameter_set_id
int sps_max_sub_layers_minus1 = bs.GetWord(3);
if (sps_max_sub_layers_minus1 > 6)
return false;
bs.GetWord(1);bs.GetWord(2);
bs.GetWord(1);
params.profile = bs.GetWord(5);
bs.GetWord(32);//
bs.GetWord(1);//
bs.GetWord(1);//
bs.GetWord(1);//
bs.GetWord(1);//
bs.GetWord(44);//
params.level = bs.GetWord(8);// general_level_idc
uint8 sub_layer_profile_present_flag[6] = {0};
uint8 sub_layer_level_present_flag[6] = {0};
for (int i = 0; i < sps_max_sub_layers_minus1; i++)
{sub_layer_profile_present_flag[i]= bs.GetWord(1);
sub_layer_level_present_flag[i]= bs.GetWord(1);
}
if (sps_max_sub_layers_minus1 > 0)
{
for (int i = sps_max_sub_layers_minus1; i < 8; i++)
uint8 reserved_zero_2bits = bs.GetWord(2);
}
for (int i = 0; i < sps_max_sub_layers_minus1; i++)
{
if (sub_layer_profile_present_flag[i])
{bs.GetWord(2);
bs.GetWord(1);
bs.GetWord(5);/
bs.GetWord(32);
bs.GetWord(1);
bs.GetWord(1);
bs.GetWord(1);
bs.GetWord(1);
bs.GetWord(44);
}
if (sub_layer_level_present_flag[i])
bs.GetWord(8);// sub_layer_level_idc[i]
}
uint32 sps_seq_parameter_set_id= bs.GetUE();
if (sps_seq_parameter_set_id > 15)
return false;
uint32 chroma_format_idc = bs.GetUE();
if (sps_seq_parameter_set_id > 3)
return false;
if (chroma_format_idc == 3)
bs.GetWord(1);//
params.width = bs.GetUE(); // pic_width_in_luma_samples
params.height = bs.GetUE(); // pic_height_in_luma_samples
if (bs.GetWord(1))
{bs.GetUE();
bs.GetUE();
bs.GetUE();
bs.GetUE();
}
uint32 bit_depth_luma_minus8= bs.GetUE();
uint32 bit_depth_chroma_minus8= bs.GetUE();
if (bit_depth_luma_minus8 != bit_depth_chroma_minus8)
return false;
//…
}
4、测试代码
本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/2439.html