提示

返回博客列表

24fps 转 25fps 不只是改个数字:帧率转换、PAL/NTSC 与音频补偿

客户有批 23.976fps 的电影素材,要在 PAL 制式的电视渠道播出(25fps)。

我当时的做法很直接:

bash ffmpeg -i film.mov -r 25 -c:v libx264 out.mp4

出来的文件帧率确实是 25,但有两个问题:时长短了 4%(90 分钟变成 86 分 20 秒),而且声音变尖了(音调升高)。客户那边排期按 90 分钟排的,直接对不上。

后来才搞明白:帧率转换不是"改个标签",它有三种完全不同的语义——改变时长(加速)、保持时长(增删帧)、或者生成新帧(插值)。而 24→25 在广播行业有一套约定俗成的做法(加速 4%,音高也跟着升,观众已经习惯了)。

TL;DR:三种转换方式:-r / fps 滤镜(增删帧,保持时长,画面可能顿挫)、setpts(改时间戳,改变时长,等于加速/减速)、minterpolate(运动补偿生成新帧,最平滑但慢)。24→25(PAL 加速)的标准做法:setpts=PTS/1.0427 + 音频 atempo=1.0427。关键区别:atempo 变速不变调(time-stretch,推荐);asetrate 变速且变调(模拟磁带加速,传统 PAL 加速就是这个效果)。另外:29.97 和 30 差 0.1%——一小时累积 3.6 秒,长节目必须处理,短视频可以忽略。

目录

一、先解释 23.976 和 29.97 这两个怪数字

故事的起点:1950 年代美国给黑白电视加彩色信号。为了不破坏已有的黑白接收机,彩色副载波要"塞进"现有频谱,结果帧率被微调了 0.1%:

30 fps  →  30 × 1000/1001 = 29.970 fps
24 fps  →  24 × 1000/1001 = 23.976 fps(严格写法 24000/1001)

常见帧率对照:

名称 精确值 用途
23.976 24000/1001 电影、北美流媒体
24 24/1 部分数字制作
29.97 30000/1001 北美电视(NTSC 遗留)
25 25/1 欧洲/中国电视(PAL)
50 / 59.94 50 / 60000/1001 高清电视

这个 0.1% 会累积:一小时的 29.97fps 内容若按 30fps 处理,时间轴会差 3.6 秒。

二、三种转换方式

方式 命令 时长 画面 适合
① 增删帧 -r 25 或 fps=25 不变 重复/丢帧,可能顿挫 保持时长优先
② 改时间戳 setpts=PTS/1.0427 变短(加速) 完全流畅 PAL 加速、需要"变快"
③ 插值 minterpolate=fps=60 不变 生成新帧,最平滑 慢动作、升帧率

① 增删帧(保持时长)

ffmpeg -i in.mp4 -r 25 -c:v libx264 out.mp4          # 输出选项
ffmpeg -i in.mp4 -vf "fps=25" -c:v libx264 out.mp4   # 滤镜形式,更可控

23.976 → 25 用这种方式会产生重复帧(每秒多约 1 帧),快速运动时有轻微顿挫。优点:时长不变,音频不用动,音画天然同步。

② 改时间戳(改变时长)

-vf "setpts=PTS/1.0427"     # 加速(时长变短)
-vf "setpts=PTS*1.0427"     # 减速(时长变长)

画面完全流畅(没有重复帧),但时长变了,所以音频必须同步处理。

③ 插值(最平滑,最慢)

-vf "minterpolate=fps=60:mi_mode=mci:mc_mode=aobmc:vsbmc=1"

运动补偿生成中间帧。代价:比普通转码慢 10~50 倍,快速运动/遮挡处有伪影。只在真正需要平滑慢放时用。

三、24 → 25:PAL 加速

ffmpeg -i film_23976.mov \
  -vf "setpts=PTS/1.0427" \
  -af "atempo=1.0427" \
  -c:v libx264 -crf 18 -preset slow \
  -c:a aac -b:a 192k \
  film_pal_25.mp4

系数怎么算:

源 系数(25/源)
23.976(24000/1001) 1.042709
24(24/1) 1.041667

先确认源的实际帧率再选系数:

ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate,avg_frame_rate -of csv=p=0 film.mov
# 24000/1001,24000/1001

视频和音频必须用同一个系数,否则每秒差一点,几分钟后就明显不同步。

四、atempo 和 asetrate:变不变调的区别

这是最容易搞混的一对:

滤镜 原理 音调 时长
atempo=X 时间拉伸(WSOLA) 不变 变为 1/X
asetrate=R 改采样率标记 变(按 R/原采样率升高) 变为 原/R×原采样率
  • atempo=1.0427:快 4.27%,音调不变(现代做法,推荐);
  • asetrate=48000*1.0427:又快又尖——这就是传统 PAL 加速的效果(音调升高约 0.7 个半音)。
做法 音调 什么时候用
atempo(现代) 不变 一般交付的默认选择
asetrate(传统) 升高 客户明确要求"与播出版本一致"时

atempo 范围限制 0.5~2.0,超出要串联:

-af "atempo=2.0,atempo=2.0"     # 4 倍速
-af "atempo=0.5,atempo=0.5"     # 0.25 倍速

asetrate 的另一个用途(变调不变速,配 atempo 反向拉回):

# 升高一个半音(×1.0595),时长保持不变
-af "asetrate=48000*1.0595,atempo=1/1.0595"

五、29.97 ↔ 30:那 0.1% 要不要管

场景 要不要处理
短视频(< 10 分钟) 不用(误差 < 0.6 秒)
长节目(> 1 小时) 必须(字幕会跑偏)
多机位/字幕对齐 必须
上传到视频平台 一般不用(平台会处理)

处理方式(保持时长):

ffmpeg -i in.mp4 -vf "fps=30" -c:v libx264 out.mp4

最常见的坑是字幕:字幕按 29.97 时间轴做、视频按 30 处理,一小时后字幕偏 3.6 秒。长节目一定要确认视频和字幕用同一帧率基准。

六、50/60 → 25/30:最简单的一种

整数倍减半,直接丢帧,无副作用:

ffmpeg -i in_50.mp4 -vf "fps=25" -c:v libx264 out_25.mp4

音频完全不用动,画面也不会顿挫(只是运动细腻度下降)。

七、慢动作与快动作

# 2 倍慢放(不插值,有效帧率降低会顿)
-vf "setpts=PTS*2" -af "atempo=0.5"

# 平滑慢放(先插到高帧率再减速)
-vf "minterpolate=fps=120:mi_mode=mci,setpts=PTS*4" -af "atempo=0.5,atempo=0.5"

# 4 倍快放
-vf "setpts=PTS/4" -af "atempo=2.0,atempo=2.0"

八、验证

# 1. 时长
ffprobe -v error -show_entries format=duration -of csv=p=0 out.mp4
# 2. 实际帧率
ffprobe -v error -select_streams v:0 -show_entries stream=avg_frame_rate -of csv=p=0 out.mp4
# 3. 音视频时长是否一致(差 < 0.5 秒)
ffprobe -v error -select_streams v:0 -show_entries stream=duration -of csv=p=0 out.mp4
ffprobe -v error -select_streams a:0 -show_entries stream=duration -of csv=p=0 out.mp4

最实用的主观检查:看结尾的口型——系数错了的话开头看不出来,结尾会明显偏。

九、命令速查表

需求 视频 音频
23.976→25 加速(不变调) setpts=PTS/1.0427 atempo=1.0427
23.976→25 加速(传统变调) setpts=PTS/1.0427 asetrate=48000*1.0427
25→23.976 setpts=PTS*1.0427 atempo=0.959
29.97→30(保持时长) fps=30 无
30→29.97(保持时长) fps=30000/1001 无
60→30 fps=30 无
2 倍慢放 setpts=PTS*2 atempo=0.5
4 倍快放 setpts=PTS/4 atempo=2.0,atempo=2.0

十、坑清单

  1. 只用 -r 25 做 PAL 加速 → 时长没变且有重复帧。要用 setpts + 音频同步。
  2. 视频加速了音频没动 → 音画失步。
  3. 视频和音频系数不同 → 缓慢失步,结尾最明显。
  4. 23.976 用了 24 的系数 → 每小时差 3.6 秒。先 probe 确认。
  5. 以为 atempo 会变调 → 不会;要变调用 asetrate。
  6. atempo 超范围 → 报错,串联多个。
  7. 慢放只用 setpts → 有效帧率降低、画面顿,要插值。
  8. minterpolate 用于快速运动 → 伪影明显,先小段评估。
  9. 忘了字幕时间轴 → 长节目字幕跑偏。
  10. 变速后没复核时长 → 客户排期对不上。
  11. 多次累积转换 → 每次重编码累积画质损失。从原始素材一次转到位。
  12. -r 和 fps 的效果混淆 → -r 是输出选项(也可能触发帧重采样),fps 是滤镜;行为在不同版本略有差异,实测确认。
  13. 变速后关键帧间隔变了 → ABR 档位可能不对齐,要重设 -g。
  14. 音频编码参数没跟上 → 变速后重编码音频时注意码率。
  15. 交付说明里没写"已做 PAL 加速" → 客户拿到后发现时长变了会疑惑。写进交付文档。

最后说说这次的体会。

这类"历史遗留"问题在音视频领域特别多。23.976 这个数字本身就是 1950 年代的技术妥协,它不合理,但它无处不在。类似的还有:

  • 丢帧时间码(第 43 篇讲过);
  • 隔行扫描(PAL/NTSC 的遗产);
  • 44.1kHz(CD 的遗产);
  • 响度标准的地区差异(第 42 篇)。

理解这些"不合理"的由来,比记住它们的数值重要——因为记住数值你只会照抄,而理解了由来,你才能判断"这个场景要不要管它"。

比如 0.1% 这个事:

  • 知道它是 NTSC 彩色的遗留 → 知道它只在北美体系出现;
  • 知道它会累积(每小时 3.6 秒)→ 就能判断"短视频不用管、长节目必须管"。

不需要每次都查规范,只要理解了原理,判断就是自然的。

还有一点很实际:帧率转换的验收一定要看结尾。开头几秒的差异太小看不出来,但累积误差在结尾最明显。我现在检查任何"时间轴相关"的处理,都是开头、中间、结尾各抽一段看——这是那次排期事故留下的习惯。

想亲手试试?用 VidDown 一键解析下载

粘贴视频链接即可解析,多平台支持、网页端即用;下载桌面客户端解锁海外平台本地解析,开通会员更享不限次下载。

顶部