FFmpeg时间基相关函数大杂烩

FFmpeg时间基相关函数大杂烩

目录

一、核心时间基概念速记

二、时间基转换「主函数表」(最重要)

三、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 提供了一系列的函数和工具来帮助开发者处理与时间基相关的问题。


一、核心时间基概念速记

名字

类型

含义

AVRational

{int num, den}

时间单位:1 / den

time_base

AVRational

一单位 pts 等于多少秒

pts / dts

int64_t

时间戳(单位是 time_base)

AV_TIME_BASE

1000000

ffmpeg 内部时间:微秒

公式一句话:

真实时间(s) = pts × num / den

二、时间基转换「主函数表」(最重要)

函数

原型 / 参数

用途

常见场景

av_rescale_q()

(a, src_tb, dst_tb)

pts 从 A 时间基 → B 时间基

99% 用这个

av_rescale_q_rnd()

(a, src, dst, enum AVRounding)

同上 + 四舍五入 / ceil

音频 / 精确对齐

av_rescale()

(a, b, c)

a*b/c防止溢出

自己算 ratio

av_rescale_rnd()

(a, b, c, rnd)

带 round 的整数 rescale

底层封装

av_mul_q()

(AVRational a, AVRational b)

rational 乘法

推导 time_base

av_div_q()

(a, b)

rational 除法

fps ↔ duration

av_add_q()/av_sub_q()

(a,b)

rational 加减

偏移时间

记住一句话:FFmpeg 里永远用av_rescale_q()做 pts 转换


三、AVRational 工具函数表

函数

作用

示例

av_make_q(num, den)

构造 AVRational

AVRational tb = av_make_q(1, 1000);

av_d2q(d, max)

double → AVRational

tb = av_d2q(1.0/44100, 100000);

av_q2d(tb)

tb → double 秒

sec = pkt->pts * av_q2d(tb);

av_inv_q(tb)

倒数

fps → 每帧秒数

av_reduce()

约分 rational

内部用


四、FFmpeg 内置时间基常量

常量 / API

含义

AV_TIME_BASE

1000000(微秒)

AV_TIME_BASE_Q

(AVRational){1, AV_TIME_BASE}

av_get_time_base_q()

返回AV_TIME_BASE_Q

音视频同步常用目标:

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 参数详解

行为

用途

AV_ROUND_ZERO

向 0 取整

不推荐

AV_ROUND_INF

远离 0

很少用

AV_ROUND_DOWN

向下

✅ seek(避免越界)

AV_ROUND_UP

向上

buffer size

AV_ROUND_NEAR_INF

四舍五入

✅ 显示时间 / 音频对齐

AV_ROUND_PASS_MINMAX

保留 INT64_MIN/MAX

内部用

推荐记忆:

seek → AV_ROUND_DOWN ui ms → AV_ROUND_NEAR_INF

七、Stream / Codec / Frame 时间基到底用哪个?

这是新手地狱,直接给结论表:

对象

pts 所在 timebase

怎么转

AVPacket

AVStream::time_base

av_rescale_q(pkt->pts, st->time_base, dst)

AVFrame(video)

AVCodecContext::pkt_timebasest->time_base

解码后一般继承 stream

AVFrame(audio)

解码后建议转成1/sample_rate

自己算

avformat_seek_file()

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,单位是AVRational

2️.转换只用av_rescale_q()/av_rescale_q_rnd()

3️.seek / 显示 / 同步各选一个主时钟,统一 rescale 再比