在h264编解码中,常常有I帧/IDR/B帧/P帧/IDR/NALU/GOP/,但往往没有关注细节。或者我们本身在实际应用中与使用过很多次,但对相关的技术名词不清楚。
在H264协议里定义了三种帧,完整编码的帧叫I帧,参考之前的I帧生成的只包含差异部分编码的帧叫P帧,还有一种参考前后的帧编码的帧叫B帧。
H264采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成I帧的算法,帧间压缩是生成B帧和P帧的算法。
I帧
简单地说,I帧是关键帧,属于帧内压缩。I帧表示关键帧,可以理解为这一帧画面的完整保留,解码时只需要本帧数据就可以完成(完整画面)。属于帧内压缩,其特点:
- 它是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输;
- 解码时仅用I帧的数据就可重构完整图像;
- I帧描述了图像背景和运动主体的详情;
- I帧不需要参考其他画面而生成;
- I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量);
- I帧是帧组GOP的基础帧(第一帧),在一组中只有一个I帧;
- I帧不需要考虑运动矢量;
- I帧所占数据的信息量比较大。
I帧(IDR)
IDR = instantaneous decoding refresh 即时解码刷新帧或强制刷新帧, IDR一定是I帧,但I帧不一定是IDR,为了区分帧序列的首个I帧和其他I帧,才定义首个I帧为IDR,解码器只可以从IDR开始解码,IDR表示一组新的帧序列GOP,在IDR帧之后的所有帧都不能引用该IDR之前的帧数据,在普通I帧之后的B、P帧可以引用该普通I帧之前的I帧
ID会导致DPB(decord picture buff 参考帧列表)清空,导致PPS、SPS参数更新。
P帧
P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。(也就是差别帧,P帧没有完整画面数据,只有与前一帧的画面差别的数据),是帧间压缩
P帧是以I帧为参考帧,在I帧中找出P帧“某点”的预测值和运动矢量,取预测差值和运动矢量一起传送。在接收端根据运动矢量从I帧中找出P帧“某点”的预测值并与差值相加以得到P帧“某点”样值,从而可得到完整的P帧。
P帧特点:
- P帧是I帧后面相隔1-2帧的编码帧。
- P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差)。
- 解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像。
- P帧属于前向预测的帧间编码。它只参考前面最靠近它的I帧或P帧。
- P帧可以是其后面P帧的参考帧,也可以是其前后的B帧的参考帧。
- 由于P帧是参考帧,它可能造成解码错误的扩散。
- 由于是差值传送,P帧的压缩比较高。
B帧
B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别(具体比较复杂,有4种情况),换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU消耗较高。
B帧特点:
- B帧是由前面的I或P帧和后面的P帧来进行预测的;
- B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量;
- B帧是双向预测编码帧;
- B帧压缩比最高,因为它只反映2参考帧间运动主体的变化情况,预测比较准确;
- B帧不是参考帧,不会造成解码错误的扩散。
GOP
简单讲就是一个关键帧(包含)到后面关键帧之间的帧序列。注意,不一定是上一个关键帧和下一个关键帧的关系。一般情况下,一个序列是一段图像编码后的数据流, 以I帧开始,到下一个I帧结束。
一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像。H.264 引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。
一个序列就是一段内容差异不太大的图像编码后生成的一串数据流。当运动变化比较少时,一个序列可以很长,因为运动变化少就代表图像画面的内容变动很小,所以就可以编一个I帧,然后一直P帧、B帧了。当运动变化多时,可能一个序列就比较短了,比如就包含一个I帧和3、4个P帧。
SPS
序列参数集 (Sequence Paramater Set, SPS)
SPS 记录了编码的 Profile、level、图像宽高等
如果其中的数据丢失或出现错误,那么解码过程很可能会失败
PPS
图像参数集 (Picture Paramater Set, PPS)
每一帧编码后数据所依赖的参数保存于 PPS 中
一般情况 SPS 和 PPS 的 NAL Unit 通常位于整个码流的起始位置。
封装文件一般进保存一次,位于文件头部,SPS/PPS 在整个解码过程中复用,不发生变化。
然而对于实时流,通常是从流中间开始解码,因此需要在每个I帧前添加SPS和PPS;
如果编码器在编码过程中改变了码流参数(如分辨率),需要重新调整SPS和PPS数据。