H264 编解码协议详解
原文链接
1.、什么是 H264?
H264 是 MPEG-4 标准所定义的最新编码格式,同时也是技术含量最高、代表最新技术水平的视频编码格式之一,标准写法应该是H.264
H264 视频格式是经过有损压缩的,但在技术上尽可能做的降低存储体积下获得较好图像质量和低带宽图像快速传输。
2、一些相关名词解释
下图为 H264 码流分层图
2.1、VCL & NAL
H264 原始码流是由一个接一个 NALU(NAL Unit) 组成,它的功能分为两层,VCL(Video Coding Layer)视频编码层和 NAL(Network Abstraction Layer)网络提取层。
- VCL:包括核心压缩引擎和块、宏块和片的语法级别定义,设计目标是尽可能地独立于网络进行高效的编码;
- NAL:负责将 VCL 产生的比特字符串适配到各种各样的网络和多元环境中,覆盖了所有片级以上的语法级别;
NAL是 H.264 为适应网络传输应用而制定的一层数据打包操作。传统的视频编码算法编完的视频码流在任何应用领域下(无论用于存储、传输等)都是统一的码流模式,视频码流仅有视频编码层 VCL(Video Coding Layer)。而 H.264 可根据不同应用增加不同的 NAL 片头,以适应不同的网络应用环境,减少码流的传输差错。
在 VCL 进行数据传输或存储之前,这些编码的 VCL 数据,被映射或封装进NAL单元(NALU)。
一个 NALU = 一组对应于视频编码的 NALU 头部信息 + 一个原始字节序列负荷(RBSP,Raw Byte Sequence Payload)
一个原始的 H.264 NALU 单元常由 [StartCode] [NALU Header] [NALU Payload] 三部分组成,其中 Start Code 用于标示这是一个NALU 单元的开始,必须是 “00 00 00 01”
一个 slice 编码之后被打包进一个 NALU,所以 slice = NALU
2.2、片(slice)
一个片 = Slice Header + Slice Data
那么为什么要设置片呢?
设置片的目的是为了限制误码的扩散和传输,应使编码片相互间是独立的。某片的预测不能以其他片中的宏块为参考图像,这样某一片中的预测误差才不会传播到其他片中。
在上图中,可以看到每个图像中,若干宏块(Macroblock)被排列成片。一个视频图像可编成一个或更多个片,每片包含整数个宏块 (MB),每片至少包含一个宏块。
slice | 意义 |
---|---|
I slice | 只包含 I 宏块 |
P slice | 包含 P 和 I 宏块 |
B slice | 包含 B 和 I 宏块 |
SP slice | 包含 P 或 I 宏块,用于不同码流之间的切换 |
SI slice | 一种特殊类型的编码宏块 |
slice 组成
每一个 slice 总体来看都由两部分组成,一部分作为 slice header,用于保存 slice 的总体信息(如当前 slice 的类型等),另一部分为 slice body,通常是一组连续的宏块结构(或者宏块跳过信息)
2.3、宏块(Macroblock)
刚才在片中提到了宏块,那么什么是宏块呢?
宏块是视频信息的主要承载者。一个编码图像通常划分为多个宏块组成.包含着每一个像素的亮度和色度信息。视频解码最主要的工作则是提供高效的方式从码流中获得宏块中像素阵列。
一个宏块由一个 16×16 亮度像素和附加的一个 8×8 Cb 和一个 8×8 Cr 彩色像素块组成。
宏块分类 | 意义 |
---|---|
I 宏块 | 利用从当前片中已解码的像素作为参考进行帧内预测 |
P 宏块 | 利用前面已编码图像作为参考进行帧内预测 |
B 宏块 | 利用双向的参考图像(当前和未来的已编码图像帧)进行帧内预测 |
2.4、帧(frame)和场(filed)
视频的一场和一帧用来产生一个编码图像,一帧通常是一个完整的图像,当采集视频信号时,如果采用隔行扫描(奇、偶数行),则扫描下来的一帧图像就被分成了两个部分,这每一部分都被称为 [场],根据次序,分为 [顶场] 和 [底场]。
人眼可察觉到的电视视频图像刷新中的闪烁为 0.02 秒,即当电视系统的帧率低于 50 帧/秒,人眼可感觉得出画面的闪烁。常规如 PAL 制式电视系统帧率为 25 帧/秒、NTSC 制式的则为 30 帧/秒,如果采用逐行扫描将不可避免地在视频刷新时产生闪烁现象。而另一方面如果单纯的提高帧率达到避免闪烁刷新效果,则会增加系统的频带宽度。
这便引出了隔行扫描技术及 [场] 的概念
在隔行扫描中,每一帧包含两个场(top field)和(bottom field),其中每个 field 包含一帧中一半数量的水平线,top field 包含所有奇数线,bottom field 则包含所有偶数线。则在电视显示过程中,电子枪每发射一行隔一行—先发射奇数行13579…(top field)回头再发射2468…(bottom field)利用两次扫描来完成一幅图像,因为视觉的滞留性,我们看到的效果是差不多的。如在 NTSC 视频中 frame 的频率为30次/秒-àfield的频率则为 60 次/秒,大于了人眼可察觉闪烁的频率。
方式 | 作用域 |
---|---|
帧编码方式 | 活动量较小或者静止的图像宜采用 |
场编码方式 | 活动量较大的运动图像 |
2.5、I 帧、P 帧、B 帧与 pts/dts
帧的分类 | 中文 | 意义 |
---|---|---|
I 帧 | 帧内编码帧,又称 intra picture | I 帧通常是每个 GOP(MPEG 所使用的一种视频压缩技术)的第一个帧,经过适度地压缩,做为随机访问的参考点,可以当成图象。I帧可以看成是一个图像经过压缩后的产物 |
P 帧 | 前向预测编码帧,又称 predictive-frame | 通过充分将低于图像序列中前面已编码帧的时间冗余信息来压缩传输数据量的编码图像,也叫预测帧 |
B 帧 | 双向预测帧,又称 bi-directional interpolated prediction frame | 既考虑与源图像序列前面已编码帧,也顾及源图像序列后面已编码帧之间的时间冗余信息来压缩传输数据量的编码图像,也叫双向预测帧 |
- I frame: 自身可以通过视频解压算法解压成一张单独的完整的图片;
- P frame:需要参考其前面的一个 I frame 或者 B frame 来生成一张完整的图片;
- B frame: 则要参考其前一个 I 或者 P帧 及其后面的一个 P 帧来生成一张完整的图片;
pts/dts
名称 | 意义 |
---|---|
PTS(Presentation Time Stamp) | PTS 主要用于度量解码后的视频帧什么时候被显示出来 |
DTS(Decode Time Stamp) | DTS 主要是标识内存中的 bit 流什么时候开始送入解码器中进行解码 |
DTS 与 PTS 的不同:
DTS 主要用户视频的解码,在解码阶段使用。PTS主要用于视频的同步和输出,在 display 的时候使用。再没有 B frame 的时候输出顺序是一样的。
2.6、GOP
GOP 是画面组,一个 GOP 是一组连续的画面。
GOP 一般有两个数字,如 M = 3,N = 12,M 制定 I 帧与 P 帧之间的距离,N 指定两个 I 帧之间的距离。那么现在的 GOP 结构是
I BBP BBP BBP BB I
增大图片组能有效的减少编码后的视频体积,但是也会降低视频质量,至于怎么取舍,得看需求了。
2.7、IDR
一个序列的第一帧叫做 IDR帧(Instantaneous Decoding Refresh,立即解码刷新)。
I 帧和 IDR 帧都是使用帧内预测,本质上是同一个东西,在解码和编码中为了方便,将视频序列中第一个 I 帧和其他 I 帧区分开,所以把第一个 I 帧称作 IDR,这样就方便控制编码和解码流程。
IDR 帧的作用是立刻刷新,使错误不致传播,从 IDR 帧开始,重新算一个新的序列开始编码。
H.264 引入 IDR 帧是为了解码的重同步,当解码器解码到 IDR 帧时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会,IDR 帧之后的帧永远不会使用 IDR 之前的图像的数据来解码。
3、H264 码流分层结构
如上图,在 H264 中,句法元素共被组织成:序列、图像(帧)、片、宏块、子宏块五个层次。
句法元素的分层结构有助于更有效地节省码流。例如,在一个图像中,经常会在各个片之间有相同的数据,如果每个片都同时携带这些数据,势必会造成码流的浪费。更为有效的做法是将该图像的公共信息抽取出来,形成图像一级的句法元素,而在片级只携带该片自身独有的句法元素。
4、NALU Header & RBSP 结构
如上图:NALU = NAL Header + RBSP
4.1、NALU Header
前面已经说到,每个 NALU 由一个字节的 Header 和 RBSP(Raw Byte Sequence Payload) 组成。
NALU Header 由三部分组成,forbidden_bit(1bit),nal_ref_idc(2bits)代表优先级,nal_unit_type(5bits)代表该 NALU 的类型。
1 bit,H264 规定此位必须为 0
用于表示当前 NALU 的重要性,值越大,越重要
解码器在解码处理不过来的时候,可以丢掉重要性为 0 的 NALU
- nal_ref_idc 不等于 0 时, NAL unit 的内容可能是 SPS/PPS/参考帧 的片
- nal_ref_idc 等于 0 时,NAL unit 的内容可能是非参考图像的片
- 当某个图像的片的 nal_ref_id 等于 0 时,该图像的所有片均应等于 0
nal_unit_type 是否包含 VCL 层编码数据分为 VCL NAL units 和 non-VCL NAL units;
VCL NAL units 中包含 VCL 层编码输出的数据, 而 non-VCL NAL units 则不包含。
nal_unit_type | the content of NAL unit |
---|---|
1 ~ 5 | VCL NAL units |
others(SPS/PPS .etc) | non-VCL NAL units |
所有的值对于类型如下:
4.2、RBSP
上图是 RBSP 序列举例
上图是 RBSP 的描述
SODB 与 RBSP
SODB 数据比特串 -> 是编码后的原始数据.
RBSP 原始字节序列载荷 -> 在原始编码数据的后面添加了 结尾比特。一个 bit “1” 若干比特 “0”,以便字节对齐。
上一篇: ffmpeg库srt参数详解
下一篇: spring API的下载方法