FFmpeg/时间基与数据包时间戳

用整数运算换算音视频时间戳

FFmpeg 将时间戳按源、目标时间基换算为整数,并在乘除过程中处理舍入与溢出。

n7.1音视频处理核验 2026-10-09
相关概念

工程问题#

音频采样、视频编码和封装使用不同时间基。直接计算 a × b / c 可能在中间乘法溢出;转成浮点数又可能丢失大时间戳的精度。

实际实现#

av_packet_rescale_ts 对有效的 PTS、DTS 和正数时长调用 av_rescale_q。后者把两个时间基组合成整数比例,再交给 av_rescale_rnd;当比例分子、分母不超过 INT_MAX 时,把 a 拆成商与余数,较大比例则使用分段乘法与逐位除法。

处理流程#

  1. 跳过 AV_NOPTS_VALUE,保留未定义的 PTS 和 DTS
  2. 将两个 AVRational 时间基组合成整数比例 b/c
  3. 根据舍入方式计算偏移量,并按参数范围选择换算分支
  4. 检查结果能否用 int64_t 表示,再更新数据包时间字段

源码片段#

固定版本 · 原文摘录
libavutil/mathematics.cn7.1 · L77–L90
查看原文件
77    if (rnd == AV_ROUND_NEAR_INF)78        r = c / 2;79    else if (rnd & 1)80        r = c - 1;8182    if (b <= INT_MAX && c <= INT_MAX) {83        if (a <= INT_MAX)84            return (a * b + r) / c;85        else {86            int64_t ad = a / c;87            int64_t a2 = (a % c * b + r) / c;88            if (ad >= INT32_MAX && b && ad > (INT64_MAX - a2) / b)89                return INT64_MIN;90            return ad * b + a2;
av_rescale_rnd

先按舍入模式设置偏移 r。在 b、c 不超过 INT_MAX 的分支,把较大的 a 拆为商 ad 和余数对应项 a2,合并前检查结果上限;较大的 b、c 由后续未展示的分段乘法分支处理。

libavcodec/packet.cn7.1 · L533–L541
查看原文件
533void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)534{535    if (pkt->pts != AV_NOPTS_VALUE)536        pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb);537    if (pkt->dts != AV_NOPTS_VALUE)538        pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb);539    if (pkt->duration > 0)540        pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb);541}
av_packet_rescale_ts

完整函数只换算有效的 PTS、DTS 和正数 duration。它调用 av_rescale_q,并保留 AV_NOPTS_VALUE;这说明整数换算函数如何用于实际数据包接口。

第一段是整数比例较小的计算分支,完整函数还处理无效参数、负数、特殊值与宽乘法;第二段为实际调用该换算逻辑的完整数据包函数。

收益与取舍#

工程分析

带来的收益

  • 避免直接 a*b 造成的中间结果溢出
  • 不同调用点共用明确的整数舍入规则

付出的代价

  • 目标时间基更粗时仍会量化,不能把整数换算理解为无误差
  • 合法范围和舍入方向必须由调用方确定;不可表示的结果以 INT64_MIN 返回

可比较的选择

浮点时间戳换算表达简单,但大整数转换可能丢失精度,舍入也需要额外约定。

直接使用更宽的整数类型可简化中间乘法,但依赖编译器和目标平台对宽整数的支持,仍需检查结果范围。

版本与适用范围#

FFmpeg n7.1 的时间基换算。展示的是数值运算与数据包字段处理,不是音频信号重采样或视频帧率转换。av_rescale_q 默认使用就近舍入,恰好一半时远离零。

参考来源#

源码、官方文档与原始论文
01
FFmpeg · av_rescale_rnd / av_rescale_q

libavutil/mathematics.c · av_rescale_rnd / av_rescale_q

源码n7.1
02
FFmpeg · av_packet_rescale_ts

libavcodec/packet.c · av_packet_rescale_ts

源码n7.1
03
FFmpeg 7.1 · 整数换算与舍入 API

libavutil/mathematics.h · AVRounding / av_rescale_rnd

官方文档7.1
2 个匹配案例