H2.64编码码流:
H2.65编码码流:
H2.64/H2.65码流的组成形式:
序列(GOP),图像(I帧,p帧等),片组(slice group),片(slice),宏块(macroblock),块(block),子块(sub-block),像素(YUV,RGB)。
在H2.64/H2.65码流中是以序列为单位组成的,一个序列包含很多帧图像,一帧图像又可以分为一个或者若干个片,片是由宏块组成的,宏块是编码处理的基本单位。
编码采用双层架构:
VLC:视频编码层
NAL:网络适配层 //主要负责格式化数据并添加头信息,保证介质间的有效传输。
编码后的数据以NALU为单位在各网络之间传输,NALU是编码框架的网络适配层。NALU分为NAL头和载荷(RBSP)。
- 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 |
只写了几个重要的类型。其余类型用到的话网上可查。
- 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之后的类型不常用就没列举,用到的可以网络查询。
为了区分哪个NALU是哪个,就引入了起始码的概念,起始码为00000001(4字节)或者000001(3字节)。
那么什么时候用三字节什么时候用四字节呢?
视频流编码的时候马,一帧数据可能会分割成一个或者若干个片(slice),一个NALU单元包含一个片(slice),NALU与片(slice)的关系:
由最上面的码流结构可以知道,一个I帧被分为多个NALU,也就是多个片slice,只有该帧的第一个片的起始码为00000001(四字节),该帧其他片为000001(三字节),SPS,PPS的起始码固定00000001(四字节)。