转自FFmpeg 音视频(DTS / PTS) - 特拉法尔加的文章 - 知乎
https://zhuanlan.zhihu.com/p/100029853
直播、短视频的兴起彻底带火了音视频领域。说到音视频处理,FFmpeg 三剑客(ffplay、ffprobe)就是一个不不可不备谈及的问题。
简单总结下平常工作中会用到的一些音视频知识点。因为本人也不是专业做音视频的,只是作为入门级别的了解。
帧
帧是音视频中的一个非常重要的概念。简单来说,帧就是一个一个静态的图像,帧快速的变化,因为人眼的视觉暂留效应,就会有动图的感觉。
当然,一般的视频为了控制大小和压缩率,会使用一定的帧压缩算法。每一帧不一定都能恢复出完整的图像。这也就是常说的 I 、B、P 帧的区别。
- I帧:I帧(Intra-coded picture, 帧内编码帧,常称为关键帧)包含一幅完整的图像信息,属于帧内编码图像,不含运动矢量,在解码时不需要参考其他帧图像。因此在I帧图像处可以切换频道,而不会导致图像丢失或无法解码。I帧图像用于阻止误差的累积和扩散。在闭合式GOP中,每个GOP的第一个帧一定是I帧,且当前GOP的数据不会参考前后GOP的数据。
- P帧:P帧(Predictive-coded picture, 预测编码图像帧)是帧间编码帧,利用之前的I帧或P帧进行预测编码。
- B帧:B帧(Bi-directionally predicted picture, 双向预测编码图像帧)是帧间编码帧,利用之前和(或)之后的I帧或P帧进行双向预测编码。B帧不可以作为参考帧。B帧具有更高的压缩率,但需要更多的缓冲时间以及更高的CPU占用率,因此B帧适合本地存储以及视频点播,而不适用对实时性要求较高的直播系统。
简而言之:
- I frame: 自身可以通过视频解压算法解压成一张单独的完整的图片。
- P frame:需要参考其前面的一个I frame 或者P frame来生成一张完整的图片
- **B frame: **则要参考其前一个I或者P帧及其后面的一个P帧来生成一张完整的图片。
两个I frame之间形成一个GOP,在x264中同时可以通过参数来设定bf的大小,即:I 和 P 或者两个 P 之间 B 的数量。
通过上述基本可以说明如果有B frame 存在的情况下一个GOP的最后一个frame一定是P.
作者:lihua pi
链接:https://zhuanlan.zhihu.com/p/36736134
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
视频压缩中,每帧代表一幅静止的图像。而在实际压缩时,会采取各种算法减少数据的容量,其中IPB就是最常见的。简单地说,I帧是关键帧,属于帧内压缩。就是和AVI的压缩是一样的。 P是向前搜索的意思。B是双向搜索。他们都是基于I帧来压缩数据。I帧表示关键帧,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面)P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。(也就是差别帧,P帧没有完整画面数据,只有与前一帧的画面差别的数据)B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别(具体比较复杂,有4种情况),换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累~。从上面的解释看,我们知道I和P的解码算法比较简单,资源占用也比较少,I只要自己完成就行了,P呢,也只需要解码器把前一个画面缓存一下,遇到P时就使用之前缓存的画面就好了,如果视频流只有I和P,解码器可以不管后面的数据,边读边解码,线性前进,大家很舒服。 但网络上的电影很多都采用了B帧,因为B帧记录的是前后帧的差别,比P帧能节约更多的空间,但这样一来,文件小了,解码器就麻烦了,因为在解码时,不仅要用之前缓存的画面,还要知道下一个I或者P的画面(也就是说要预读预解码),而且,B帧不能简单地丢掉,因为B帧其实也包含了画面信息,如果简单丢掉,并用之前的画面简单重复,就会造成画面卡(其实就是丢帧了),并且由于网络上的电影为了节约空间,往往使用相当多的B帧,B帧用的多,对不支持B帧的播放器就造成更大的困扰,画面也就越卡。一般平均来说,I的压缩率是7(跟JPG差不多),P是20,B可以达到50,可见使用B帧能节省大量空间,节省出来的空间可以用来保存多一些I帧,这样在相同码率下,可以提供更好的画质
DTS / PTS
H264(目前最常用的一种视频编码格式)里有两种时间戳:DTS(Decoding Time Stamp)和PTS(Presentation Time Stamp)。 顾名思义,前者是解码的时间,后者是显示的时间。
FFmpeg 中用 AVPacket 结构体来描述解码前或编码后的压缩包,用 AVFrame 结构体来描述解码后或编码前的信号帧。 对于视频来说,AVFrame 就是视频的一帧图像。这帧图像什么时候显示给用户,就取决于它的 PTS。DTS 是 AVPacket 里的一个成员,表示这个压缩包应该什么时候被解码。 如果视频里各帧的编码是按输入顺序(也就是显示顺序)依次进行的,那么解码和显示时间应该是一致的。可事实上,在大多数编解码标准(如H.264或HEVC)中,编码顺序和输入顺序并不一致。 于是才会需要PTS和DTS这两种不同的时间戳。
可以通过 ffprobe -show_packets 看一下packets 信息
ffprobe -show_frames 看一下帧信息
PTS 主要用于度量解码后的视频帧什么时候被显示出来
DTS 主要是标识读入内存中的bit流在什么时候开始送入解码器中进行解码
总结
PTS是真正录制和播放的时间戳,而DTS是解码的时间戳。
对于普通的无 B-frame 视频(H264 Baseline 或者 VP8),PTS/DTS 应该是相等的,因为没有延迟编码。
对于有B-frame 的视频,I-frame 的 PTS 依然等于 DTS, P-frame 的 PTS > DTS, B-frame 的 PTS<DTS 。
可以简单地这样理解:
若视频没有 B-frame ,则 I 和 P 都是解码后即刻显示。
若视频含有 B-frame,则 I 是解码后即刻显示,P 是先解码后显示,B是后解码先显示。(B 和P的先、后是相对的)。