要理解 FFmpeg 里的时间基(Time Base)时间戳(Timestamp),核心可以先记住一个类比:

时间基 = 时钟的 “最小刻度”(比如钟表的 1 秒、1 分钟,尺子的 1 毫米、1 厘米);

时间戳 = 用这个 “最小刻度” 数出来的 “刻度数”(比如钟表显示 3 分钟 = 3 个 “1 分钟刻度”,尺子量 5 厘米 = 5 个 “1 厘米刻度”)。

FFmpeg 里所有时间相关的计算,本质都是「时间戳 × 时间基 = 实际时间」,先把这个核心公式刻在脑子里,再往下看就顺了。

一、先搞懂:为什么需要 “时间基”?

日常我们用 “秒、毫秒” 描述时间,但 FFmpeg 处理音视频时,直接用秒 / 毫秒会有两个问题:

  1. 精度不够:比如 25 帧 / 秒的视频,每一帧的间隔是 40 毫秒(0.04 秒),如果用秒做单位,小数运算容易丢精度;
  2. 适配性差:不同音视频格式(比如 H.264、MP4、RTP)的时间刻度不一样(比如有的用 90kHz 时钟,有的用 25fps 帧率),需要统一的 “刻度换算规则”。

所以 FFmpeg 引入 “时间基”—— 本质是一个分数值(1 / 刻度频率),代表 “每 1 个时间戳单位对应的实际秒数”,比如:

  • 时间基 = 1/90000(秒 / 单位)→ 1 个时间戳单位 = 1/90000 秒 ≈ 11.1 微秒;
  • 时间基 = 1/25(秒 / 单位)→ 1 个时间戳单位 = 0.04 秒(25 帧视频的每帧间隔)。

二、时间基(AVRational):FFmpeg 的 “时间刻度”

FFmpeg 中时间基用 AVRational 结构体表示,核心是两个整数:num(分子)和 den(分母),时间基的实际值 = num/den(秒 / 单位)。

举几个通俗例子:

时间基(num/den) 实际含义(1 个时间戳单位 =?秒) 典型用途
1/90000 ≈11.1 微秒 视频编码(H.264/H.265)、RTP 传输(通用标准)
1/25 0.04 秒(40 毫秒) 25 帧 / 秒的视频帧时序
1/44100 ≈22.7 微秒 44.1kHz 采样率的音频帧
1/1000 1 毫秒 播放器显示、用户侧时间展示

关键结论:时间基越小(分母越大),刻度越细,精度越高;FFmpeg 不同模块(封装、编码、解码)会用不同时间基,核心是 “换算”。

三、时间戳:FFmpeg 的 “刻度数”

FFmpeg 里的时间戳(比如 PTS/DTS),本质就是 “以当前时间基为刻度,数出来的刻度数量”,没有单位,必须结合时间基才能算出实际时间。

举个最直观的例子:

假设一段 25 帧 / 秒的视频,第 10 帧的 PTS 时间戳是 100,时间基是 1/1000(毫秒):

  • 实际显示时间 = 100 × (1/1000) = 0.1 秒(100 毫秒)→ 符合 25 帧 / 秒(每帧 40 毫秒,第 10 帧本就该在 400 毫秒?别急,换个时间基再看)。

如果同样是第 10 帧,时间基换成 1/25:

  • 时间戳就该是 1(因为 1 × (1/25) = 0.04 秒?不对,第 10 帧应该是 10×0.04=0.4 秒)→ 时间戳 = 10(10 × 1/25 = 0.4 秒)。

核心:同一个实际时间,不同时间基对应的时间戳数值不同,比如 0.4 秒:

  • 时间基 1/1000 → 时间戳 = 400(400×1ms=400ms);
  • 时间基 1/25 → 时间戳 = 10(10×0.04s=0.4s);
  • 时间基 1/90000 → 时间戳 = 36000(36000×1/90000=0.4s)。

四、FFmpeg 里的核心换算:时间基转换

实际开发中,最常见的操作是 “把 A 时间基的时间戳,转换成 B 时间基的时间戳”,公式就 1 个:

目标时间戳 = 原始时间戳 × (原始时间基 / 目标时间基)

用 FFmpeg 自带函数就是 av_rescale_q(),本质就是帮你算这个公式(避免浮点误差)。

实操例子(通俗版):

比如视频编码时,编码器要求时间基是 1/90000,而你的视频是 25 帧 / 秒(时间基 1/25),第 5 帧的时间戳(1/25 基)是 5,要转成编码器的时间戳:

目标时间戳 = 5 × (1/25 ÷ 1/90000) = 5 × (90000/25) = 18000

验证:18000 × (1/90000) = 0.2 秒,5 × (1/25)=0.2 秒 → 实际时间一致,只是刻度数不同。

五、新手最容易踩的坑(通俗避坑)

混淆 “时间戳数值” 和 “实际时间”:比如看到 PTS=9000,别直接以为是 9000 秒!先看时间基:如果是 1/90000,实际是 9000×1/90000=0.1 秒

不同模块时间基不一致

AVStream(流)的时间基:比如 MP4 文件的流时间基可能是 1/1000000;

AVCodecContext(编码器 / 解码器)的时间基:通常是 1/90000;

必须用av_rescale_q()换算,不能直接加减。

帧率和时间基的关系:25 帧 / 秒 ≠ 时间基一定是 1/25,但 25 帧 / 秒的视频,相邻帧的时间戳差值(以 1/25 为基)一定是 1;以 1/90000 为基,差值就是 90000/25=3600。

六、一句话总结(记死就行)

  • 时间基:FFmpeg 的 “时间尺子刻度”,用分数表示(num/den),1 个刻度 = num/den 秒;
  • 时间戳:用这个尺子量出来的 “刻度数”,没有单位;
  • 实际时间 = 时间戳 × (num/den);
  • 不同尺子(时间基)量同一个时间,刻度数(时间戳)不一样,换算就行。

七、为什么非要做时间基转换?

FFmpeg 不是一个单一模块,而是由封装、编码、解码、播放、网络传输等多个 “独立部门” 组成的系统,每个部门都有自己的 “时间刻度习惯”:

  1. 编码部门(编码器):习惯用高精度细刻度(比如 1/90000 的时间基,≈11.1 微秒),因为视频编码需要精准控制帧的时序,差一点就会导致编码错位;
  2. 封装部门(比如 MP4 文件):习惯用中等精度刻度(比如 1/1000000,1 微秒),方便文件存储和跨播放器兼容;
  3. 播放部门:习惯用毫秒级刻度(1/1000),因为人眼和耳朵对毫秒级的时间差才敏感,太细的刻度反而没必要;
  4. 网络传输部门(比如 RTP):又有自己的标准(必须用 1/90000 的时间基,这是行业协议规定的)。

如果不做转换,就会出现 “鸡同鸭讲” 的局面:

比如编码器输出了一个 “时间戳 = 18000、时间基 = 1/90000” 的帧(实际时间 0.2 秒),直接丢给播放部门,播放部门以为时间基是 1/1000,就会算成 18000 毫秒(18 秒)—— 结果就是这一帧要等 18 秒才播,直接音画严重不同步。

八、时间基转换的核心思想

一句话概括:把 “同一实际时间”,从 A 模块的 “时间刻度”,翻译成 B 模块能识别的 “时间刻度”,保证时间的 “本质不变”,只是表述形式变了

再拿生活例子说:你有一块 12 小时制的手表(显示 “下午 2 点”),要告诉用 24 小时制的机场工作人员登机时间,就得转换成 “14 点”——实际时间没变(都是下午 2 点),只是刻度表述换了,这就是时间基转换的核心逻辑。

在 FFmpeg 里,这个思想的数学体现就是我们之前说的公式:目标时间戳 = 原始时间戳 × (原始时间基 / 目标时间基)本质就是 “先把原始时间戳换算成实际秒数,再用目标时间基重新计算刻度数”,保证实际时间不跑偏。

九、时间基转换的核心目的(最终要解决啥问题)

适配不同模块的 “接口要求”

每个模块都有硬性的 “时间基标准”,比如 H.264 编码器强制要求输入 1/90000 的时间基,你给它 1/25 的时间基,编码器直接报错不干活;封装 MP4 时,必须按 MP4 格式的时间基要求写入,否则播放器读不出正确时序。转换就是为了满足这些 “接口规则”。

保证全链路的时间同步

这是最关键的目的 —— 从采集→编码→封装→传输→解码→播放,整个链路的音视频帧必须对应同一个 “实际时间”,才能实现音画同步。比如音频帧的实际时间是 0.2 秒,视频帧也必须是 0.2 秒,不管经过多少模块,通过时间基转换就能锁定这个 “实际时间”,不会出现 “声音已经播到 1 秒,画面还停在 0.5 秒” 的尴尬。

平衡精度和效率,避免计算误差

细刻度(比如 1/90000)精度高,但数值会很大(0.2 秒对应 18000 的时间戳),计算时容易溢出;粗刻度(比如 1/1000)数值小,计算快,但精度不够。转换可以在不同环节切换刻度:需要精准编码时用细刻度,需要高效播放时用粗刻度,既保证精准又不浪费性能。

兼容行业标准,实现跨系统协作

比如 RTP 传输音视频流时,行业协议规定必须用 1/90000 的时间基,不管你本地用的是什么时间基,都得转换成这个标准刻度,否则其他设备(比如监控摄像头、流媒体服务器)就无法识别你的流,没法实现设备间的互通。

一句话总结

时间基转换就是 FFmpeg 的 “时间翻译官”,核心是统一时间的 “表述语言”,目的是让各个模块能协同工作、保证音视频同步、兼容行业标准

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐