1. I帧/P帧/B帧
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帧适合本地存储以及视频点播,而不适用对实时性要求较高的直播系统。
2. DTS和PTS
DTS(Decoding Time Stamp, 解码时间戳),表示压缩帧的解码时间。
PTS(Presentation Time Stamp, 显示时间戳),表示将压缩帧解码后得到的原始帧的显示时间。
音频中DTS和PTS是相同的。视频中由于B帧需要双向预测,B帧依赖于其前和其后的帧,因此含B帧的视频解码顺序与显示顺序不同,即DTS与PTS不同。当然,不含B帧的视频,其DTS和PTS是相同的。下图以一个开放式GOP示意图为例,说明视频流的解码顺序和显示顺序

采集顺序指图像传感器采集原始信号得到图像帧的顺序。
编码顺序指编码器编码后图像帧的顺序。存储到磁盘的本地视频文件中图像帧的顺序与编码顺序相同。
传输顺序指编码后的流在网络中传输过程中图像帧的顺序。
解码顺序指解码器解码图像帧的顺序。
显示顺序指图像帧在显示器上显示的顺序。
采集顺序与显示顺序相同。编码顺序、传输顺序和解码顺序相同。
以图中“B[1]”帧为例进行说明,“B[1]”帧解码时需要参考“I[0]”帧和“P[3]”帧,因此“P[3]”帧必须比“B[1]”帧先解码。这就导致了解码顺序和显示顺序的不一致,后显示的帧需要先解码。
3. FFmpeg中的时间基与时间戳
3.1 时间基与时间戳的概念
在FFmpeg中,时间基(time_base)是时间戳(timestamp)的单位,时间戳值乘以时间基,可以得到实际的时刻值(以秒等为单位)。例如,如果一个视频帧的dts是40,pts是160,其time_base是1/1000秒,那么可以计算出此视频帧的解码时刻是40毫秒(40/1000),显示时刻是160毫秒(160/1000)。FFmpeg中时间戳(pts/dts)的类型是int64_t类型,把一个time_base看作一个时钟脉冲,则可把dts/pts看作时钟脉冲的计数。
3.2 三种时间基tbr、tbn和tbc
不同的封装格式具有不同的时间基。在FFmpeg处理音视频过程中的不同阶段,也会采用不同的时间基。
FFmepg中有三种时间基,命令行中tbr、tbn和tbc的打印值就是这三种时间基的倒数:
- tbn: Time Based Number) 对应容器中的时间基。值是AVStream.time_base的倒数 基于时间的时间单元数目。
- tbc:(Time Base Corrector) 对应编解码器中的时间基。值是AVCodecContext.time_base的倒数 基于时间基的校正器。
- tbr:(Time Based Rate 从视频流中猜算得到,可能是帧率或场率(帧率的2倍) 基于时间的帧率。
使用ffprobe探测媒体文件格式,如下:
ffprobe a.mp4

3.3 内部时间基AV_TIME_BASE
除以上三种时间基外,FFmpeg还有一个内部时间基AV_TIME_BASE(以及分数形式的AV_TIME_BASE_Q)
// Internal time base represented as integer
#define AV_TIME_BASE 1000000
// Internal time base represented as fractional value
#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE}
AV_TIME_BASE及AV_TIME_BASE_Q用于FFmpeg内部函数处理,使用此时间基计算得到时间值表示的是微秒。
3.4 时间值形式转换
av_q2d()将时间从AVRational形式转换为double形式。AVRational是分数类型,double是双精度浮点数类型,转换的结果单位是秒。转换前后的值基于同一时间基,仅仅是数值的表现形式不同而已。
av_q2d()实现如下:
/**
* Convert an AVRational to a `double`.
* @param a AVRational to convert
* @return `a` in floating-point form
* @see av_d2q()
*/
static inline double av_q2d(AVRational a){
return a.num / (double) a.den;
}
av_q2d()使用方法如下:
时刻值:timestamp(单位秒) = pts × av_q2d(stream->time_base);
时长值:duration(单位秒) = stream->duration × av_q2d(stream->time_base);
);
3.5 时间基转换函数
av_rescale_q()用于不同时间基的转换,用于将时间值从一种时间基转换为另一种时间基。
/**
* Rescale a 64-bit integer by 2 rational numbers.
*
* The operation is mathematically equivalent to `a × bq / cq`.
*
* This function is equivalent to av_rescale_q_rnd() with #AV_ROUND_NEAR_INF.
*
* @see av_rescale(), av_rescale_rnd(), av_rescale_q_rnd()
*/
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;
av_packet_rescale_ts()用于将AVPacket中各种时间值从一种时间基转换为另一种时间基。
/**
* Convert valid timing fields (timestamps / durations) in a packet from one
* timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be
* ignored.
*
* @param pkt packet on which the conversion will be performed
* @param tb_src source timebase, in which the timing fields in pkt are
* expressed
* @param tb_dst destination timebase, to which the timing fields will be
* converted
*/
void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);
3.6 转封装过程中的时间基转换
容器中的时间基(AV

本文详细介绍了FFmpeg中视频编码的I帧、P帧、B帧概念,以及DTS和PTS在解码过程中的作用。同时,重点阐述了FFmpeg中时间基的概念,包括内部时间基AV_TIME_BASE和不同封装格式的时间基转换,以及在转封装和转码过程中如何处理时间戳和时间基。此外,还讨论了如何通过setpts滤镜实现视频的快进和慢放效果。
最低0.47元/天 解锁文章
3686

被折叠的 条评论
为什么被折叠?



