概述
H.265技术的应用
编码技术主要运用于视频播放设备、软件应用以及拍摄、录制视频的设备。人们最熟悉的莫过于PPS网络视频播放器。在PC屏客户端产品上面,PPS已经于2013年初推出了基于H.265标准的高清视频,并命名“臻高清”为自己的高清品牌。同时 PPS不断加大了在H.265技术应用方面的研究,把H.265推向手机客户端,且在性能上不断优化提升。
名词
- CTU: 编码树单元
- CU: 编码单元
- PU: 以CU为根,对CU进行划分,一个预测单元PU包含一个亮度预测块PB和两个色度预测块PB.
- TU: 以CU为根,变换单元TU是在CU的基础上划分的,跟PU没有关系,采用四叉树划分方式,具体划分有率失真代价决定,下图给出了某个CU划分成TU的结构。
H265-NALU-Type介绍
NAL_TRAIL_N = 0, NAL_TRAIL_R = 1, NAL_TSA_N = 2, NAL_TSA_R = 3, NAL_STSA_N = 4, NAL_STSA_R = 5, NAL_RADL_N = 6, NAL_RADL_R = 7, NAL_RASL_N = 8, NAL_RASL_R = 9, NAL_BLA_W_LP = 16, NAL_BLA_W_RADL = 17, NAL_BLA_N_LP = 18, NAL_IDR_W_RADL = 19, NAL_IDR_N_LP = 20, NAL_CRA_NUT = 21, NAL_VPS = 32, NAL_SPS = 33, NAL_PPS = 34, NAL_AUD = 35, NAL_EOS_NUT = 36, NAL_EOB_NUT = 37, NAL_FD_NUT = 38, NAL_SEI_PREFIX = 39, NAL_SEI_SUFFIX = 40,
H265码流格式
VPS:视频参数集,用于传输视频分级信息,有利于兼容标准在可分级视频编码或多视点视频的扩展。
NALU header定义:
NALU header(){ | Descriptor |
---|---|
forbidden_zero_bit | f(1) |
nalu unit type | u(6) |
nuh_layer_id | u(6) |
nuh_temporal_id_plus1 | u(3) |
H264的NALU type是首字节&0x1f,H265的NALU type是(首字节&0x7E)>>1;
NALU type定义:
/**
* Table 7-3: NAL unit type codes
*/
enum HEVCNALUnitType {
HEVC_NAL_TRAIL_N = 0,
HEVC_NAL_TRAIL_R = 1,
HEVC_NAL_TSA_N = 2,
HEVC_NAL_TSA_R = 3,
HEVC_NAL_STSA_N = 4,
HEVC_NAL_STSA_R = 5,
HEVC_NAL_RADL_N = 6,
HEVC_NAL_RADL_R = 7,
HEVC_NAL_RASL_N = 8,
HEVC_NAL_RASL_R = 9,
HEVC_NAL_VCL_N10 = 10,
HEVC_NAL_VCL_R11 = 11,
HEVC_NAL_VCL_N12 = 12,
HEVC_NAL_VCL_R13 = 13,
HEVC_NAL_VCL_N14 = 14,
HEVC_NAL_VCL_R15 = 15,
HEVC_NAL_BLA_W_LP = 16,
HEVC_NAL_BLA_W_RADL = 17,
HEVC_NAL_BLA_N_LP = 18,
HEVC_NAL_IDR_W_RADL = 19,
HEVC_NAL_IDR_N_LP = 20,
HEVC_NAL_CRA_NUT = 21,
HEVC_NAL_IRAP_VCL22 = 22,
HEVC_NAL_IRAP_VCL23 = 23,
HEVC_NAL_RSV_VCL24 = 24,
HEVC_NAL_RSV_VCL25 = 25,
HEVC_NAL_RSV_VCL26 = 26,
HEVC_NAL_RSV_VCL27 = 27,
HEVC_NAL_RSV_VCL28 = 28,
HEVC_NAL_RSV_VCL29 = 29,
HEVC_NAL_RSV_VCL30 = 30,
HEVC_NAL_RSV_VCL31 = 31,
HEVC_NAL_VPS = 32,
HEVC_NAL_SPS = 33,
HEVC_NAL_PPS = 34,
HEVC_NAL_AUD = 35,
HEVC_NAL_EOS_NUT = 36,
HEVC_NAL_EOB_NUT = 37,
HEVC_NAL_FD_NUT = 38,
HEVC_NAL_SEI_PREFIX = 39,
HEVC_NAL_SEI_SUFFIX = 40,
};
丢帧
在性能不足,或者音画不同步时,需要进行丢帧,H264丢帧根据nal_ref_idc来判断,H265根据来NALU type判断。以下type是可以丢帧,且不花屏的:
HEVC_NAL_TRAIL_N、HEVC_NAL_TSA_N、HEVC_NAL_STSA_N、HEVC_NAL_RADL_N、HEVC_NAL_RASL_N。
H265码流分析
H265相比较于H264,除了包含SPS、PPS外,还多包含一个VPS;在NALU header上,H.264的HALU header是一个字节,而H.265则是两个字节。
以OX4001为例,头信息可以被解析成4个部分,其中:
- forbidden_zero_bit = 0:占1个bit,与H.264相同,禁止位,用以检查传输过程中是否发生错误,0表示正常,1表示违反语法; nal_unit_type = 32:占6个bit,用来用以指定NALU类型 nuh_reserved_zero_6bits = 0:占6位,预留位,要求为0,用于未来扩展或3D视频编码
- nuh_temporal_id_plus1 = 1:占3个bit,表示NAL所在的时间层ID 对比H.264的头信息,H.265移除了nal_ref_idc,此信息被合并到了nal_unit_type中,H.265NALU类型规定如下:
nal_unit_type NALU类型 备注
0 NAL_UNIT_CODE_SLICE_TRAIL_N 非关键帧
1 NAL_UNIT_CODED_SLICE_TRAIL_R
2 NAL_UNIT_CODED_SLICE_TSA_N
3 NAL_UINT_CODED_SLICE_TSA_R
4 NAL_UINT_CODED_SLICE_STSA_N
5 NAL_UINT_CODED_SLICE_STSA_R
6 NAL_UNIT_CODED_SLICE_RADL_N
7 NAL_UNIT_CODED_SLICE_RADL_R
8 NAL_UNIT_CODED_SLICE_RASL_N
9 NAL_UNIT_CODE_SLICE_RASL_R
10 ~ 15 NAL_UNIT_RESERVED_X 保留
16 NAL_UNIT_CODED_SLICE_BLA_W_LP 关键帧
17 NAL_UNIT_CODE_SLICE_BLA_W_RADL
18 NAL_UNIT_CODE_SLICE_BLA_N_LP
19 NAL_UNIT_CODE_SLICE_IDR_W_RADL
20 NAL_UNIT_CODE_SLICE_IDR_N_LP
21 NAL_UNIT_CODE_SLICE_CRA
22 ~ 31 NAL_UNIT_RESERVED_X 保留
32 NAL_UNIT_VPS VPS(Video Paramater Set)
33 NAL_UNIT_SPS SPS
34 NAL_UNIT_PPS PPS
35 NAL_UNIT_ACCESS_UNIT_DELIMITER
36 NAL_UNIT_EOS
37 NAL_UNIT_EOB
38 NAL_UNIT_FILLER_DATA
39 NAL_UNIT_SEI Prefix SEI
40 NAL_UNIT_SEI_SUFFIX Suffix SEI
41 ~ 47 NAL_UNIT_RESERVED_X 保留
48 ~ 63 NAL_UNIT_UNSPECIFIED_X 未规定
64 NAL_UNIT_INVALID
H.265的NALU类型是在信息头的第一个字节的第2到7位,所以判断H.265NALU类型的方法是将NALU第一个字节与0x7E进行与操作并右移一位,即:
NALU类型 = (NALU头第一字节 & 0x7E) >> 1 与H.264类似,H.265码流也有两种封装格式,一种是用起始码作为分界的Annex B格式,另一种则是在NALU头添加NALU长度前缀的格式,称为HVCC。
H265码流分析帧类型
- nal单元分割
寻找0x000001或者0x00000001, 规则如下:
- 每个NALU前面都有起始码0x000001, 3bits
- 如果NALU类型为vps, sps, pps, 或者解码顺序为第一个AU的第一个NALU, 起始码前面再加一个0x00
- 视频流的首个NALU的起始码前加入0x00 实际分析中,不必要整的这么复杂,只要找到0x000001或者0x00000001即可
- 上图中的码流nal拆分为: 第一帧: 0000 0001 4001 0c01 ffff 0160 0000 0300 0003 0000 0300 0003 00ba 9702 40 第二帧: 00 0000 0142 0101 0160 0000 0300 0003 0000 0300 0003 00ba a00f 0804 47f9 65e4 91b6 1c5e 4924 fe79 fcf2 ffff ffcf e7f3 f3f9 d9 第三帧: 00 0000 0144 01c1 9095 8112 第四帧: 0000 0126 01af 1380 790b dc5c 557c 74…
- NAL类型分析 类型枚举定义
enum NALUnitType {
NAL_TRAIL_N = 0,
NAL_TRAIL_R = 1,
NAL_TSA_N = 2,
NAL_TSA_R = 3,
NAL_STSA_N = 4,
NAL_STSA_R = 5,
NAL_RADL_N = 6,
NAL_RADL_R = 7,
NAL_RASL_N = 8,
NAL_RASL_R = 9,
NAL_BLA_W_LP = 16,
NAL_BLA_W_RADL = 17,
NAL_BLA_N_LP = 18,
NAL_IDR_W_RADL = 19,
NAL_IDR_N_LP = 20,
NAL_CRA_NUT = 21,
NAL_VPS = 32,
NAL_SPS = 33,
NAL_PPS = 34,
NAL_AUD = 35,
NAL_EOS_NUT = 36,
NAL_EOB_NUT = 37,
NAL_FD_NUT = 38,
NAL_SEI_PREFIX = 39,
NAL_SEI_SUFFIX = 40,
};
类型判断方式为分隔符之后的第一个字节右移一位的值 第一帧:0x40 >> 1 , 得到0x20,十进制32,为NAL_VPS 第二帧:0x42 >> 1 , 得到0x21, 十进制33, 为NAL_SPS 第三帧:0x44 >> 1 , 得到0x22, 十进制34, 为NAL_PPS 第四帧:0x26 >> 1 , 得到0x13, 十进制19, 为NAL_IDR_W_RADL
- 代码如下
static int hevc_probe(char* pbuf, int buf_size)
{
unsigned int code = -1;
int vps = 0, sps = 0, pps = 0, irap = 0;
int i;
for (i = 0; i < buf_size - 1; i++) {
code = (code << 8) + pbuf[i];
if ((code & 0xffffff00) == 0x100) {
char nal2 = pbuf[i + 1];
int type = (code & 0x7E) >> 1;
if (code & 0x81) // forbidden and reserved zero bits
return 0;
if (nal2 & 0xf8) // reserved zero
return 0;
switch (type) {
case NAL_VPS: vps++; break;
case NAL_SPS: sps++; break;
case NAL_PPS: pps++; break;
case NAL_BLA_N_LP:
case NAL_BLA_W_LP:
case NAL_BLA_W_RADL:
case NAL_CRA_NUT:
case NAL_IDR_N_LP:
case NAL_IDR_W_RADL: irap++; break;
}
}
}
return 0;
}
以上主要解析了音视频开发中的,H265码流的码流格式、NALU-Type、码流分析、帧类型分析等等。有关H265更多的学习可以前往《音视频基础精通版》里面不仅是对H265的解析很全面,还有从音视频基础学习到精通的全面解析。
文末
H265码流结构
H265的视频流中也是存在多个GOP,每一个GOP里面包含多个视频编码帧。H265支持的视频编码帧类型有IDR帧、I帧、P帧、B帧,这些帧类型的含义和H264码流的帧类型的含义是一样,作用也是一样,比如IDR帧和I帧都是帧内压缩编码,IDR帧是即时解码刷新帧,也是关键帧;P帧是前向参考帧,B帧是双向参考帧。