想给视频加速/慢放,声音还不变调?彻底搞懂变速与变调(附 WSOLA 原理与慢动作补帧)
做教程要加速去掉废话、做慢动作回放精彩瞬间、或者把一段语音压成 1.5 倍速听——这些都需要"变速"。但新手常踩的坑是:视频加速了,声音也跟着变尖变调,像花栗鼠(chipmunk)一样难听;或者反过来,只把画面加速了、声音还是原速,结果音画完全对不上。这篇文章讲清楚视频和音频各自的变速方法,以及怎么做到变速不变调,顺带聊聊背后的 WSOLA 算法原理,并给出慢动作补帧方案。
一、视频变速和音频变速是两件事
很多人以为"加速"是一个开关,其实底层是两个独立操作:
- 视频变速:改变帧的呈现节奏,用
setpts滤镜(Presentation TimeStamp 缩放); - 音频变速:改变采样播放速度,用
atempo滤镜(基于 WSOLA 算法); - 两者必须同时处理且倍数一致,否则音画对不上。
只改一条,就会出现"画面快声音慢"或"声音尖画面正常"的诡异结果。
二、只改视频速度(声音不动会怪)
# 加速 2 倍
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" -c:a copy output.mp4
setpts=0.5*PTS 表示每帧时间戳减半 → 速度翻倍。注意这里音频用 -c:a copy 没变,结果会是"画面快进但声音正常速度"——音画不同步,一般不是你想要的。仅在你明确只要画面变速时用。
三、音频变速不变调(关键)
单纯 atempo 在合法范围内不会改变音高,因为它内部用 WSOLA(Waveform Similarity Overlap-Add)算法:它不是简单把采样率倍乘(那会变调),而是把音频切成小块、在重叠区域找最相似的波形拼接,从而在不改变音高的前提下改变播放速度。
# 1.5 倍速,声音不变调
ffmpeg -i input.mp4 -filter:a "atempo=1.5" -vn output.mp4
atempo 的合法范围是 0.5 ~ 2.0。超出范围需要叠加:
# 4 倍速 = 2.0 * 2.0
ffmpeg -i input.mp4 -filter:a "atempo=2.0,atempo=2.0" -vn output.aac
四、视频+音频一起变速(推荐做法)
同时处理,保证同步:
# 加速 2 倍,声音不变调
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" output.mp4
如果速度不在 0.5~2.0,音频叠加 atempo:
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.25*PTS[v];[0:a]atempo=2.0,atempo=2.0[a]" -map "[v]" -map "[a]" output.mp4
五、要"变调"的特效(故意搞怪)
有时你就是想要花栗鼠效果(比如搞笑视频、变声),那就主动变调:
# 用 rubberband 主动升高音高(变调不变速或变速)
ffmpeg -i input.mp4 -filter:a "rubberband=pitch=2.0" -vn out.aac
rubberband 滤镜(需编译 librubberband)能分别控制 tempo(速度)和 pitch(音高),非常灵活:只变速不变调、只变调不变速、或两者都变,全看你传哪些参数。
六、更高质量音频变速:rubberband
相比 atempo,rubberband 在极端速度下保真更好,且能精细控制音高:
# 变速 1.5 倍且保持音高
ffmpeg -i input.mp4 -filter:a "rubberband=tempo=1.5" -vn out.aac
# 只升调不变速(变声)
ffmpeg -i input.mp4 -filter:a "rubberband=pitch=1.5" -vn out.aac
七、慢动作怎么做才流畅
单纯 setpts=2*PTS 只是让每帧停留更久,不会新增画面,所以慢动作会有卡顿感。要真·流畅慢放,得补帧(光流/帧插值):
# 用 minterpolate 插帧做平滑慢动作
ffmpeg -i input.mp4 -filter:v "minterpolate='mi_mode=mci:me_mode=bidir:mc_mode=aobmc:vsbmc=1:fps=60'" -c:a copy slow.mp4
代价是计算量大、可能引入伪影,但慢动作观感明显更顺。注意音频在慢放下会变调(因为时间拉长),如需保持音高要配合 atempo 反向处理——但通常慢动作回放会把原音去掉或用新配乐。
八、批量处理
for f in *.mp4; do
ffmpeg -i "$f" -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" "fast_$f"
done
九、常见翻车现场
| 现象 | 根因 | 解法 |
|---|---|---|
| 声音变尖 | atempo 超出范围或没用 WSOLA | 用 0.5~2.0 内,或 rubberband |
| 音画不同步 | 只改了视频没改音频 | 同时改音频 atempo,倍数一致 |
| 速度超过 2 倍失败 | atempo 范围限制 | 叠加 atempo=2.0,atempo=2.0 |
| 慢动作卡顿 | 帧率没跟着补 | 用 minterpolate 插帧 |
| 处理后没声音 | 漏了 -map 音频 |
确认 map 了音频流 |
十、常见问题
Q:能不能只变调不变速? 能,rubberband=pitch=2 只升音高不改速度,适合变声搞笑。
Q:慢动作怎么做得流畅? 单纯 setpts=2*PTS 只是每帧停留更久,不新增画面;要真流畅慢放得用插帧(minterpolate 滤镜)。
Q:语音 1.5 倍速听不清? 适当加 highpass 提清晰度,或选 rubberband 保真。
Q:变速后时长怎么算? 速度 N 倍,时长约为原来的 1/N;音频和视频一致即可。
Q:WSOLA 和直接改采样率有什么区别? 直接改采样率(如 44100→88200)会变调且快放,WSOLA 通过波形重叠拼接保持音高,这是"不变调变速"的关键。
十一、端到端实战:把 1 小时教程压成 12 分钟速览
# 加速 5 倍(2.0×2.0 叠加),声音不变调
ffmpeg -i tutorial.mp4 \
-filter_complex "[0:v]setpts=0.2*PTS[v];[0:a]atempo=2.0,atempo=2.5[a]" \
-map "[v]" -map "[a]" -c:v libx264 -crf 23 -c:a aac fast.mp4
注意音频 2.0*2.5=5.0 倍,视频 0.2=1/5,两边倍数一致,音画同步。
十二、慢动作 + 插帧完整流程
# 1) 先把视频慢 4 倍(setpts=4*PTS)
# 2) 插帧到 120fps 让慢动作顺滑
ffmpeg -i input.mp4 -filter_complex \
"[0:v]setpts=4*PTS,minterpolate=mi_mode=mci:fps=120[v]" \
-map "[v]" -c:v libx264 -crf 18 slow_smooth.mp4
慢动作通常不保留原声(会变调且拖沓),可后续配乐;若坚持保留人声,需对音频反向 atempo=0.25 并 loudnorm 修正。
十三、更多 FAQ
Q:变速后音频和视频时长对不上? 必然因为一端没变;确保 setpts 倍数 = atempo 总倍数。
Q:为什么 atempo 最多 2.0? 这是算法稳定区间,超出用多段叠加(2.0×2.0=4.0)。
Q:手机拍慢动作怎么变速回正常? 手机慢动作文件本身已是高帧率,用 setpts=0.25*PTS 提速即可(配合插帧反向)。
Q:能不能只对某时间段变速? 能,用 enable='between(t,5,15)' 限定滤镜作用区间。
Q:WSOLA 和 rubberband 怎么选? 普通变速 atempo 够用;极端速度或需独立控 pitch 用 rubberband(音质更好)。
小结
变速要视频音频同步改:setpts 管画面、atempo(或 rubberband)管声音,两者倍数必须一致。想不变调就待在 atempo 0.5~2.0 内或用 rubberband;想搞怪变调就主动调 pitch。慢动作要流畅得额外插帧,别只靠 setpts。