H2.64和H2.65编码区别
AAC音频格式ADTS头详解
RTP载荷H264(实战细节)
RTP载荷H265(实战细节)
通过H264了解视频帧
H2.64编码码流:
H2.65编码码流:
1.概述
H2.64/H2.65码流的组成形式:
序列(GOP),图像(I帧,p帧等),片组(slice group),片(slice),宏块(macroblock),块(block),子块(sub-block),像素(YUV,RGB)。
在H2.64/H2.65码流中是以序列为单位组成的,一个序列包含很多帧图像,一帧图像又可以分为一个或者若干个片,片是由宏块组成的,宏块是编码处理的基本单位。
编码采用双层架构:
VLC:视频编码层
NAL:网络适配层 //主要负责格式化数据并添加头信息,保证介质间的有效传输。
2. NALU头
编码后的数据以NALU为单位在各网络之间传输,NALU是编码框架的网络适配层。NALU分为NAL头和载荷(RBSP)。
2.1 H2.65的头部结构(2字节)
nal_unit_head{
forbidden_zero_bit(1bit): 禁止位
nal_unit_type(6bit): NALU类型
nuh_reserved_zero_6bits(6bit):
nuh_temporal_id_plis1(3bit):
};
在实际引用中通过nal_unit_type字段获取NALU的单元类型(sps,pps,帧等),计算方法如下:
int nal_type = (buf[0] & 0x7E) >>1 或者 int nal_type = (buf[0]>>1)&0x3f
buf[0]为起始码后的第一个字节。
H2.65的NALU单元类型如下:
Type | 类型描述 |
19 | I帧 |
32 | VPS |
33 | SPS |
34 | PPS |
35 | 访问单元分隔符 |
1 | P帧 B帧 |
39 40 | SEI |
只写了几个重要的类型。其余类型用到的话网上可查。
2.2 H2.64的头部结构(1字节)
nal_unit_head{
forbidden_zero_bit(1bit):禁止位
nal_ref_idc(2bit):
nal_unit_type(5bit):NALU类型
};
H2.64获取NALU类型的计算方法:
int nal_type = buf[0] &1F
Buf[0]为起始码后的第一个字节。
H2.64的NALU单元类型如下:
type | 类型描述 |
0 | 未定义 |
1 | 一个非IDR图像的编码条带(P帧或者B帧) |
2 | 编码条带数据分割块A |
3 | 编码条带数据分割块B |
4 | 编码条带数据分割块C |
5 | IDR图像的编码条带 |
6 | 辅助增强信息SEI |
7 | 序列参数集SPS |
8 | 图像参数集PPS |
9 | 访问单元分隔符 |
10 | 序列结尾 |
11 | 流结尾 |
红色填充为实际应用中常用的,11之后的类型不常用就没列举,用到的可以网络查询。
3. 起始码
为了区分哪个NALU是哪个,就引入了起始码的概念,起始码为00000001(4字节)或者000001(3字节)。
那么什么时候用三字节什么时候用四字节呢?
视频流编码的时候马,一帧数据可能会分割成一个或者若干个片(slice),一个NALU单元包含一个片(slice),NALU与片(slice)的关系:
由最上面的码流结构可以知道,一个I帧被分为多个NALU,也就是多个片slice,只有该帧的第一个片的起始码为00000001(四字节),该帧其他片为000001(三字节),SPS,PPS的起始码固定00000001(四字节)。