FFMPEG
Chapter 1 Time
1 Definition
1.time_base
#define AV_TIME_BASE 1000000
#define AV_TIME_BASE_Q (AVRational){1, AV_TIME_BASE}
AV_TIME_BASE_Q指的是1微秒(1/1000000)。
2.pts & dts
PTS(Presentation Time Stamp) : 显示时间戳
DTS(Decoding Time Stamp) :解码时间戳
注意这里的显示时间并不是现实世界里的时间,不是秒、分之类的,而是ffmpeg中的时间刻度。将在下面的例子中有详细的讲解。
3.r_frame_rate
the lowest framerate with which all timestamps can be represented accurately (it is the least common multiple of all framerates in the stream).
在所有时间戳都能够精确显示的最小时间。
4.AVRational
typedef struct AVRational{
int num; ///< Numerator
int den; ///< Denominator
} AVRational;
5.av_q2d(AVRational )
将一个AVRational变成一个浮点数,可以理解为在这里面做了一次除法。
Parameters:
a AVRational to convert
Return:
a in floating-point form
因为AVRational有两个成员,一个是den分母,一个是num分子,所以实际的计算公式如下
r
e
s
=
A
V
R
a
t
i
o
n
a
l
.
n
u
m
/
A
V
R
a
t
i
o
n
a
l
.
d
e
n
res = AVRational.num / AVRational.den
res=AVRational.num/AVRational.den
那为什么要使用一个函数做这件事呢?我的思考是可能存在分母为0的时候,需要进行合法性判断。
6.av_rescale_q(int64_t a, AVRational bq, AVRational cq)
转化时间基,将一种时间基转化为另一种。
7.tbr,tbn,tbc
tbr: 帧率
tbn: 文件层的时间精度
tbc: 视频层的时间精度
8.av_packet_rescale_ts()
void av_packet_rescale_ts(AVPacket * pkt,AVRational tb_src, AVRational tb_dst )
将包的时间基转化为另一种。
2 Usage
可以看一段雷霄骅的代码,该段代码用于为裸流中的包写入pts,dts以及duration。这段代码的地址为ffmpeg推流器。
if(pkt->pts == AV_NOPTS_VALUE){
// Write PTS
AVRational time_base1 = ifmt_ctx->streams[videoIndex]->time_base;
// Duration between two frames
int64_t calc_duration = (double)AV_TIME_BASE/av_q2d(ifmt_ctx->streams[videoIndex]->r_frame_rate);
pkt->pts = (double)(frame_index*calc_duration)/(double)(av_q2d(time_base1)*AV_TIME_BASE);
pkt->dts = pkt->pts;
pkt->duration = (double)calc_duration/(double)(av_q2d(time_base1)*AV_TIME_BASE);
}
注:ifmt_ctx为输入文件的AVFormatContext
在进行代码分析之前首先要知道,
av_q2d(time_base)为每个时间刻度是多少秒,pts指的是第几个时间刻度。那么pts*av_q2d(time_base)就是实际显示时间戳。
- 第一行获取ifmt_ctx的stream的时间基。
- 第二行代码计算每帧多少秒。其中AV_TIME_BASE为1秒,而av_q2d对r_frame_rate计算的结果是,每个时间刻度的帧数,该帧数通常为25帧,30帧。因而用AV_TIME_BASE除以该数,可以得到每帧多少秒。
- 第三行,给pkt的pts赋值。其实这里的思路很简单,现在你知道每帧耗时多少秒,那么如果想获得pts是不是首先要获取每帧耗时*现在帧的序号。但是pts的定义是什么,pts决定了该视频帧什么时候显示。这个时刻并不是现在的秒或者具体时间,而是时间刻度。所以需要除以每个时间刻度多少秒。这样该式子就是,每帧所需时间数(单位为秒)/ (1个时间刻度等于的秒数)。举个更具体的例子就是,假设第二步,1帧为1/30秒,现在在ffmpeg中,1个时间刻度是10秒,那么该帧就是1/300的时间刻度。
- 第四行只是简单的赋值操作。
- 第五行获取包的时间长度。这个同理3,如果3能够理解,这个也没什么问题。