FFmpeg 中的时间基与时间戳
时间基与时间戳的概念
在 FFmpeg 中,时间基(time_base)是时间戳(timestamp)的基本单位。时间戳值乘以时间基,可以得到实际的时刻值(以秒等为单位)。
例如,如果一个视频帧的 pts=5760, time_base=1/16000 ,那么可以计算出此视频帧的 显示时刻
=
p
t
s
∗
t
i
m
e
_
b
a
s
e
=
5760
∗
1
/
16000
=
0.36
s
\begin{aligned} & = pts*time\_base\\ & = 5760 * 1 / 16000\\ & = 0.36 s \end{aligned}
=pts∗time_base=5760∗1/16000=0.36s
三种时间基 tbr、tbn 和 tbc
不同的封装格式具有不同的时间基。在 FFmpeg 处理音视频过程中的不同阶段,也会采用不同的时间基。
FFmepg 中有三种时间基,命令行中 tbr、tbn 和 tbc 的打印值就是这三种时间基的倒数:
tbn:对应容器中的时间基。值是 AVStream.time_base 的倒数
tbc:对应编解码器中的时间基。值是 AVCodecContext.time_base 的倒数
tbr:从视频流中猜算得到,可能是帧率或场率(帧率的 2 倍)
相关函数
在ffmpeg中可以使用av_rescale_q
函数将pts转换到指定时间基下
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const;
- 第一个参数:原pts
- 第二个参数:原time_base
- 第三个参数:新time_base
- 返回值:新pts
在ffmpeg中可以使用av_q2d
函数将pts转化为以ms为单位的时间
double pts = frame->pts * av_q2d(tb);
例子
下面代码中每取出一个解码帧就打印其pts转换前后的信息
int ret = avcodec_receive_frame(video_dec_ctx, frame);
if(ret >= 0)
{
AVRational tb = video_dec_ctx->pkt_timebase;
double pts = av_rescale_q(frame->pts, video_dec_ctx->pkt_timebase, tb);
pts = pts * av_q2d(tb);
spdlog::get("file_logger")->info("Video: pts = {}, pkt_timebase = {}/{}, tb = {}/{}, new_pts {}",
frame->pts, video_dec_ctx->pkt_timebase.num, video_dec_ctx->pkt_timebase.den, tb.num, tb.den, pts);
frame->pts = frame->best_effort_timestamp;
}
log日志如下
[2024-07-04 17:20:43.492] [file_logger] [info] Video: pts = 1280, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.08
[2024-07-04 17:20:43.499] [file_logger] [info] Video: pts = 1920, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.12
[2024-07-04 17:20:43.505] [file_logger] [info] Video: pts = 2560, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.16
[2024-07-04 17:20:43.512] [file_logger] [info] Video: pts = 3200, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.2
[2024-07-04 17:20:43.520] [file_logger] [info] Video: pts = 3840, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.24
[2024-07-04 17:20:43.526] [file_logger] [info] Video: pts = 4480, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.28
[2024-07-04 17:20:43.533] [file_logger] [info] Video: pts = 5120, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.32
[2024-07-04 17:20:43.545] [file_logger] [info] Video: pts = 5760, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.36
[2024-07-04 17:20:43.547] [file_logger] [info] Video: pts = 6400, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.4
[2024-07-04 17:20:43.561] [file_logger] [info] Video: pts = 7040, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.44
[2024-07-04 17:20:43.612] [file_logger] [info] Video: pts = 7680, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.48
[2024-07-04 17:20:43.657] [file_logger] [info] Video: pts = 8320, pkt_timebase = 1/16000, tb = 1/16000, new_pts 0.52
值得一提的是video_dec_ctx->pkt_timebase
一般为0,通常需要我们手动赋值。我们可以在创建解码器时从stream中获取该值
dec_ctx->pkt_timebase = videoStream->time_base;