编码主要是想办法压缩视频的大小。
使用帧间编码技术可以去除时间上的冗余信息,具体包括以下几个部分。
使用帧内编码技术可以去除空间上的冗余信息。
对于视频,ISO同样也制定了标准:Motion JPEG即MPEG,MPEG算法是适用于动态视频的压缩算法,它除了对单幅图像进行编码外,还利用图像序列中的相关原则去除冗余,这样可以大大提高视频的压缩比。截至目前,MPEG的版本一直 在不断更新中,主要包括这样几个版本:Mpeg1(用于VCD)、Mpeg2(用于 DVD)、Mpeg4 AVC(现在流媒体使用最多的就是它了)。
相比较于ISO制定的MPEG的视频压缩标准,ITU-T制定的H.261、 H.262、H.263、H.264一系列视频编码标准是一套单独的体系。其中, H.264集中了以往标准的所有优点,并吸取了以往标准的经验,采用的是简洁设计,这使得它比Mpeg4更容易推广。现在使用最多的就是H.264标准,H.264创造了多参考帧、多块类型、整数变换、帧内预测等新的压缩技术,使用了更精细的分像素运动矢量(1/4、1/8)和新一代的环路滤波器, 这使得压缩性能得到大大提高,系统也变得更加完善
在H264中,三种类型的帧数据分别为
视频压缩中,每帧都代表着一幅静止的图像。而在进行实际压缩时,会采取各种算法以减少数据的容量,其中IPB帧就是最常见的一种。
基于上面的定义,我们可以从解码的角度来理解IPB帧。 I帧自身可以通过视频解压算法解压成一张单独的完整视频画面, 所以I帧去掉的是视频帧在空间维度上的冗余信息。 P帧需要参考其前面的一个I帧或者P帧来解码成一张完整的视频画面。 B帧则需要参考其前一个I帧或者P帧及其后面的一个P帧来生成一 张完整的视频画面,所以P帧与B帧去掉的是视频帧在时间维度上的冗余信息。
以一个经典的例子去讲解这个知识点可能会比较直观一点。如图
【免费分享】资料包括《Andoird音视频开发必备手册+音视频学习视频+学习文档资料包+大厂面试真题+2022最新学习路线图》等
有需要的点击下方链接领取
FFmpegWebRTCRTMPRTSPHLSRTP播放器-音视频流媒体高级开发
I帧记录的就是完整的信息,这里不用多说。看一下I帧与P帧的关系。首先我们看原始的图片,P帧比I帧多了一个小方块。所以P帧最后的存储的就只是一个小方块的信息。可以理解为I帧与P帧组合起来就得到原始的图片了。
同理,来看一下B帧。可以看到B帧与I帧,p帧的组合才会形成原始图片。
在H264中图像以序列为单位进行组织,一个序列是一段图像编码后的数据流。 一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像。
H.264 引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。
IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。 一个序列就是一段内容差异不太大的图像编码后生成的一串数据流。当运动变化比较少时,一个序列可以很长,因为运动变化少就代表图像画面的内容变动很小,所以就可以编一个I帧,然后一直P帧、B帧了。当运动变化多时,可能一个序列就比较短了,比如就包含一个I帧和3、4个P帧。 在视频编码序列中,GOP即Group of picture(图像组),指两个I帧之间的距离,Reference(参考周期)指两个P帧之间的距离。两个I帧之间形成一组图片,就是GOP(Group Of Picture)。
【GOP示意图】
【为什么会有PTS和DTS的概念】
通过上面的描述可以看出:P帧需要参考前面的I帧或P帧才可以生成一张完整的图片,而B帧则需要参考前面I帧或P帧及其后面的一个P帧才可以生成一张完整的图片。这样就带来了一个问题:在视频流中,先到来的 B 帧无法立即解码,需要等待它依赖的后面的 I、P 帧先解码完成,这样一来播放时间与解码时间不一致了,顺序打乱了,那这些帧该如何播放呢?这时就引入了另外两个概念:DTS 和 PTS。
【PTS和DTS】
先来了解一下PTS和DTS的基本概念:
DTS(Decoding Time Stamp):即解码时间戳,这个时间戳的意义在于告诉播放器该在什么时候解码这一帧的数据。 PTS(Presentation Time Stamp):即显示时间戳,这个时间戳用来告诉播放器该在什么时候显示这一帧的数据。
虽然 DTS、PTS 是用于指导播放端的行为,但它们是在编码的时候由编码器生成的。
在视频采集的时候是录制一帧就编码一帧发送一帧的,在编码的时候会生成 PTS,这里需要特别注意的是 frame(帧)的编码方式,在通常的场景中,编解码器编码一个 I 帧,然后向后跳过几个帧,用编码 I 帧作为基准帧对一个未来 P 帧进行编码,然后跳回到 I 帧之后的下一个帧。编码的 I 帧和 P 帧之间的帧被编码为B 帧。
之后,编码器会再次跳过几个帧,使用第一个 P 帧作为基准帧编码另外一个 P 帧,然后再次跳回,用 B 帧填充显示序列中的空隙。这个过程不断继续,每 12 到 15 个 P 帧和 B 帧内插入一个新的 I 帧。P 帧由前一个 I 帧或 P 帧图像来预测,而 B 帧由前后的两个 P 帧或一个I帧和一个P帧来预测,因而编解码和帧的显示顺序有所不同,如下所示:
过程大概如上图所以。我们接下来一步一步讲解上面的过程。
首先是我们的帧序号,一开始,帧序号是按照顺序来的,这一点没有疑问。然后这些顺序帧也都是有类型的。如上所述第一帧是I帧,第二帧是B帧,依次类推得到我们的帧类型了。我们要正常播放肯定就是需要按照我们原始的需要播放,也就是按照1...7这种需要播放。所以我们的PTS也是1...7这样顺序显示的。
现在到编码顺序了,这里也是关键点了,**编解码器编码一个I帧,然后向后跳过几个帧,用编码I帧作为基准帧对一个未来P帧进行编码。然后跳回到I帧之后的下一个帧。编码的I帧和P帧之间的帧被编码为B帧。**如下图。
我们根据第一到七步的顺序,得到编码顺序对应的帧序号为
而这些序号对应的帧类型为。
那解码的时间戳为顺序的,即1234567
到这里发现问题了没有?如果我们按照解码的时间戳来显示的话,那么显示的顺序就是IPBBPBB和我们原来的IBBPBBP顺序是不一样的。这样相当于修改了我们的视频了。所以需要按照PTS去调整。怎么调整呢?
首先看接受到的视频流(帧类型)这一行。这一行对应的原始的,根据这一行的帧类型,去需要帧类型对应的帧序号,也就得到了对应的PTS这一行的数据。
那么最后,对应的PTS这个数据去调整DTS,也就得到了调整后的DTS。这整一个过程有点绕,大家看不懂的话,慢慢的多看几遍就能理解了。