目录
一、核心时间基概念速记
二、时间基转换「主函数表」(最重要)
三、AVRational 工具函数表
四、FFmpeg 内置时间基常量
五、不同场景「怎么选函数」对照表
1️. Packet PTS → 毫秒(最常用)
2️. Frame PTS → 秒(double)
3️. 音频 frame → 下一帧 pts(防抖动)
4️. Seek 时间戳(必须 round)
5️. 音视频同步(master clock = audio clock)
六、av_rescale_q_rnd 的 rounding 参数详解
七、Stream / Codec / Frame 时间基到底用哪个?
八、完整“黄金模板”
九、时间基“血泪坑”速查表
十、一句话总结
觉得有用,就请您帮忙点赞转发收藏吧,您的鼓励是我创作的动力,多谢看官。
由于能力水平有限,文中的错误或不严谨的地方在所难免,还请批评指正。
FFmpeg 在处理视频和音频时,经常需要与时间基(time base)相关联的操作。时间基是视频和音频处理中的一个核心概念,它定义了帧之间的时间间隔。FFmpeg 提供了一系列的函数和工具来帮助开发者处理与时间基相关的问题。
一、核心时间基概念速记
名字 | 类型 | 含义 |
|---|---|---|
|
| 时间单位: |
|
| 一单位 pts 等于多少秒 |
|
| 时间戳(单位是 time_base) |
|
| ffmpeg 内部时间:微秒 |
公式一句话:
真实时间(s) = pts × num / den二、时间基转换「主函数表」(最重要)
函数 | 原型 / 参数 | 用途 | 常见场景 |
|---|---|---|---|
|
| pts 从 A 时间基 → B 时间基 | ✅99% 用这个 |
|
| 同上 + 四舍五入 / ceil | 音频 / 精确对齐 |
|
|
| 自己算 ratio |
|
| 带 round 的整数 rescale | 底层封装 |
|
| rational 乘法 | 推导 time_base |
|
| rational 除法 | fps ↔ duration |
|
| rational 加减 | 偏移时间 |
记住一句话:FFmpeg 里永远用av_rescale_q()做 pts 转换
三、AVRational 工具函数表
函数 | 作用 | 示例 |
|---|---|---|
| 构造 AVRational |
|
| double → AVRational |
|
| tb → double 秒 |
|
| 倒数 | fps → 每帧秒数 |
| 约分 rational | 内部用 |
四、FFmpeg 内置时间基常量
常量 / API | 含义 |
|---|---|
|
|
|
|
| 返回 |
音视频同步常用目标:
dst_tb = AV_TIME_BASE_Q; // 微秒 dst_tb = av_make_q(1,1000); // 毫秒五、不同场景「怎么选函数」对照表
1️. Packet PTS → 毫秒(最常用)
int64_t ms = av_rescale_q(pkt->pts, stream->time_base, av_make_q(1, 1000));用av_rescale_q
2️. Frame PTS → 秒(double)
double sec = pkt->pts * av_q2d(stream->time_base);用av_q2d(只读不写)
3️. 音频 frame → 下一帧 pts(防抖动)
AVRational tb = codec_ctx->pkt_timebase; int64_t next_pts = av_rescale_q( frame->nb_samples, av_make_q(1, frame->sample_rate), tb );推导音频时钟
4️. Seek 时间戳(必须 round)
int64_t seek_ts = av_rescale_q_rnd( target_ms, av_make_q(1, 1000), stream->time_base, AV_ROUND_DOWN // 或 AV_ROUND_NEAR_INF ); avformat_seek_file(fmt_ctx, audio_idx, INT64_MIN, seek_ts, INT64_MAX, 0);seek 必须用_rnd
5️. 音视频同步(master clock = audio clock)
double vid_clk = vid_pkt->pts * av_q2d(vid_tb); double aud_clk = aud_pkt->pts * av_q2d(aud_tb); double diff = aud_clk - vid_clk;六、av_rescale_q_rnd 的 rounding 参数详解
宏 | 行为 | 用途 |
|---|---|---|
| 向 0 取整 | 不推荐 |
| 远离 0 | 很少用 |
| 向下 | ✅ seek(避免越界) |
| 向上 | buffer size |
| 四舍五入 | ✅ 显示时间 / 音频对齐 |
| 保留 INT64_MIN/MAX | 内部用 |
推荐记忆:
seek → AV_ROUND_DOWN ui ms → AV_ROUND_NEAR_INF七、Stream / Codec / Frame 时间基到底用哪个?
这是新手地狱,直接给结论表:
对象 | pts 所在 timebase | 怎么转 |
|---|---|---|
|
|
|
|
| 解码后一般继承 stream |
| 解码后建议转成 | 自己算 |
| AVStream::time_base | 别用 AV_TIME_BASE |
经典错误:
avformat_seek_file(fmt_ctx, idx, ..., ms, ..., 0); // ❌ ms 直接塞八、完整“黄金模板”
static int64_t pts_ms(AVPacket *pkt, AVStream *st) { return av_rescale_q_rnd( pkt->pts, st->time_base, av_make_q(1, 1000), AV_ROUND_NEAR_INF ); } static int64_t pts_us(AVFrame *frm, AVStream *st) { return av_rescale_q(frm->pts, st->time_base, AV_TIME_BASE_Q); }九、时间基“血泪坑”速查表
坑 | 结果 |
|---|---|
pkt pts 当秒用 | 快进 1000 倍 |
seek 用微秒直接塞 | seek 到天边 |
audio frame 用 video timebase | 声音飞走 |
rescale 不 rnd | 帧跳 |
pkt/dts 混用 | B 帧倒放 |
十、一句话总结
FFmpeg 时间基只有三条铁律:
1️.pts 永远是
int64_t,单位是AVRational2️.转换只用
av_rescale_q()/av_rescale_q_rnd()3️.seek / 显示 / 同步各选一个主时钟,统一 rescale 再比