FFmpeg で動画を早送り・スロー再生にするときは、映像用の setpts と音声用の atempo を正しい比率で組み合わせます。比率が合っていないと音ずれが起きます。0.25 倍から 10 倍までの速度変更のほか、ピッチを保ったままの速度変更や、一部の区間だけの速度変更もできます。
速度変更の基本: setpts と atempo
FFmpeg の速度変更は「映像のタイムスタンプ」と「音声のテンポ」を別々に操作します。それぞれの方向を間違えると音ずれの原因になります。
| 用途 | フィルタ | 係数の意味 | 例(2 倍速) |
|---|---|---|---|
| 映像 | setpts=N*PTS |
小さいほど速い(PTS を圧縮) | setpts=0.5*PTS |
| 音声 | atempo=N |
大きいほど速い(再生速度倍率) | atempo=2.0 |
setpts の係数は再生速度倍率の逆数です。2 倍速にするには PTS を半分(0.5*PTS)に、半分速にするには PTS を倍(2*PTS)にします。一方、atempo には倍率をそのまま書きます。
速度・係数早見表
| 再生速度 | setpts 係数 | atempo 係数 |
|---|---|---|
| 0.25 倍(4 倍スロー) | 4*PTS |
0.5,atempo=0.5(2 段連結。単体では 0.5 未満を指定できない) |
| 0.5 倍(2 倍スロー) | 2*PTS |
0.5 |
| 1.0 倍(等速) | 1*PTS |
1.0 |
| 2.0 倍(早送り) | 0.5*PTS |
2.0 |
| 4.0 倍 | 0.25*PTS |
4.0 |
| 10.0 倍 | 0.1*PTS |
10.0 |
FFmpeg 4.1 以降、
atempoは単体で 0.5〜100 倍まで対応します。4.0 以前は 0.5〜2.0 なので、atempo=2.0,atempo=2.0のように連結します(後述)。
早送り(2 倍・4 倍・10 倍)
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_2x.mp4
setpts=0.5*PTS で映像のタイムスタンプを半分に圧縮し、atempo=2.0 で音声を 2 倍テンポに加速します。-map "[v]" -map "[a]" で filter_complex の出力を明示的にマップします。ラベルを付けた出力をマップし忘れると、Filter 'setpts:default' has output 0 (v) unconnected というエラーで止まります。
4 倍速
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.25*PTS[v];[0:a]atempo=4.0[a]" \
-map "[v]" -map "[a]" output_4x.mp4
20 秒の素材なら 5 秒に圧縮されます。atempo=4.0 は FFmpeg 4.1 以降であれば単体でそのまま動きます。
10 倍速
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.1*PTS[v];[0:a]atempo=10.0[a]" \
-map "[v]" -map "[a]" output_10x.mp4
10 倍速は、監視カメラ映像のダイジェストや、タイムラプスの代わりに使えます。音声は人の声として聞き取れなくなるので、後述の -an で音声をカットするほうが現実的です。
スロー再生(0.5 倍・0.25 倍)
0.5 倍速(半分速)
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=2*PTS[v];[0:a]atempo=0.5[a]" \
-map "[v]" -map "[a]" output_half.mp4
setpts=2*PTS で各フレームの表示時間を倍に伸ばし、atempo=0.5 で音声を半分のテンポに減速します。
0.25 倍速(4 倍スロー)
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=4*PTS[v];[0:a]atempo=0.5,atempo=0.5[a]" \
-map "[v]" -map "[a]" output_quarter.mp4
atempo=0.5 を連結することで合計 0.25 倍にできます。atempo 単体で指定できるのは 0.5 以上なので、0.5 倍より遅くするときはどのバージョンでも連結が必要です。
スローのカクつき:
setptsで時間を伸ばしただけではフレーム数は増えません。元が 30fps なら 0.25 倍では実効 7.5fps となりカクつきます。後述のminterpolateでフレーム補間できます。
音声を同期させる atempo の制約と回避
atempo 1 つで指定できる範囲は次のとおりです:
| FFmpeg バージョン | 単体での範囲 | 連結での実用範囲 |
|---|---|---|
| 4.0 以前 | 0.5〜2.0 | 連結で任意倍率 |
| 4.1 以降 | 0.5〜100.0 | 0.5 未満は連結が必要 |
0.25 倍速にする(連結)
# Wrong: atempo=0.25 は範囲外(0.5〜100)なのでエラーになる
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=4*PTS[v];[0:a]atempo=0.25[a]" \
-map "[v]" -map "[a]" output_bad.mp4
# 正しい: 0.5 を 2 段連結で 0.25
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=4*PTS[v];[0:a]atempo=0.5,atempo=0.5[a]" \
-map "[v]" -map "[a]" output_quarter_safe.mp4
古い FFmpeg で 8 倍速にする
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.125*PTS[v];[0:a]atempo=2.0,atempo=2.0,atempo=2.0[a]" \
-map "[v]" -map "[a]" output_8x.mp4
atempo=2.0 を 3 段連結して 8 倍にします。係数の積(2×2×2)が目標の倍率と一致するように組みます。
音を消して映像だけ速度変更
音声が要らないタイムラプスや監視カメラ映像の早送りでは、音声の処理を省くとコマンドが短くなります。
ffmpeg -i input.mp4 -vf "setpts=0.25*PTS" -an output_4x_silent.mp4
-an— 音声ストリームを削除-vf— 映像 1 系統だけならfilter_complexではなく-vfで十分
# スロー(音声なし)
ffmpeg -i input.mp4 -vf "setpts=2*PTS" -an output_slow_silent.mp4
音声を残したいが速度は合わせなくてよい場合は、-c:a copy で元の音声をそのまま使えます(ただし映像と長さが合わなくなります)。
ピッチを保ったまま速度変更(rubberband)
atempo もピッチ(音高)を保ったままテンポだけを変えるので、3 倍速にしても声が甲高くなることはありません。rubberband フィルタは Rubber Band ライブラリを使う別の時間伸縮フィルタで、atempo の代わりに使えます。
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]rubberband=tempo=2.0[a]" \
-map "[v]" -map "[a]" output_2x_pitch_keep.mp4
rubberband=tempo=2.0 で音声を 2 倍速にしつつ音程を維持します。インタビューや講義など、話の内容を聞き取りたい素材に向いています。
# rubberband でスロー再生(音程はそのまま)
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=2*PTS[v];[0:a]rubberband=tempo=0.5[a]" \
-map "[v]" -map "[a]" output_half_pitch_keep.mp4
rubberbandは--enable-librubberband付きの FFmpeg ビルドが必要です。Windows なら gyan.dev のフルビルド、macOS はbrew install ffmpeg-full(Homebrew のffmpegには入っていません)、Ubuntu は標準パッケージ(sudo apt install ffmpeg)で利用できます。ffmpeg -filters | grep rubberbandで確認できます。
部分的に速度を変える(時間範囲ごと)
「最初の 5 秒だけスロー、その後は等速」のような速度変更には、2 通りの方法があります。
方法 1: setpts 式で時間条件を書く(音声なし向け)
ffmpeg -i input.mp4 -vf "setpts='if(lt(T,5),2*PTS,PTS+5/TB)'" -an output_var.mp4
T は入力フレームの時刻(秒)です。5 秒未満のフレームは PTS を 2 倍にして 0.5 倍速にし、5 秒以降のフレームは伸びた 5 秒分だけ後ろにずらして等速のまま並べます(5/TB は 5 秒をタイムスタンプの単位に直した値)。20 秒の動画なら 25 秒になります。ずらさずに if(lt(T,5),2,1)*PTS と書くと、スロー部分と後半の時刻が重なってフレームが捨てられます。
方法 2: trim + setpts で分割して concat(音声同期可能)
ffmpeg -i input.mp4 -filter_complex \
"[0:v]trim=0:5,setpts=2*PTS[v1];[0:a]atrim=0:5,asetpts=PTS-STARTPTS,atempo=0.5[a1]; \
[0:v]trim=5:20,setpts=PTS-STARTPTS[v2];[0:a]atrim=5:20,asetpts=PTS-STARTPTS[a2]; \
[v1][a1][v2][a2]concat=n=2:v=1:a=1[v][a]" \
-map "[v]" -map "[a]" output_var_audio.mp4
trim / atrim で時間範囲を切り出し、それぞれ速度を変えてから concat で連結します。音声同期が必要ならこちらを使います。可変速度は複雑なので、まず -an 版で映像だけ確認し、音声は後付けするのが楽です。
フレームレートを保ちつつスロー(minterpolate)
setpts=2*PTS だけのスローは元のフレームを引き延ばすだけでフレーム数が増えません。minterpolate フィルタはモーションベクトルから中間フレームを生成するので、滑らかなスローになります。
ffmpeg -i input.mp4 -vf "setpts=4*PTS,minterpolate=fps=60:mi_mode=mci" -an output_smooth_slow.mp4
setpts=4*PTS— 4 倍スローminterpolate=fps=60— 出力フレームレートを 60fps にmi_mode=mci— Motion Compensated Interpolation(推定中間フレームを生成)
mi_mode 値 |
意味 | 用途 |
|---|---|---|
dup |
フレーム複製のみ | 高速処理、品質低 |
blend |
クロスフェード混合 | 中間品質、軽量 |
mci |
モーション補間(推奨) | 高品質スロー |
minterpolateは CPU 負荷が高く、HD 動画では実時間の数十倍かかることもあります。長尺は-ss/-toで範囲を絞ってからかけるのが現実的です。
速度変更後にコーデックを変える
速度変更では映像を再エンコードするので、同じコマンドで圧縮設定も指定できます。
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" \
-map "[v]" -map "[a]" -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k output_optimized.mp4
-crf 23— 標準品質(18〜28 が実用範囲、低いほど高品質)-preset medium— 速度と圧縮率のバランス-c:a aac -b:a 128k— AAC 128kbps の標準音声
H.265 で容量を抑えたい場合は -c:v libx265 -crf 28 に変更します。
トラブルシューティング
1. 音だけ・映像だけが速くなる
原因: setpts か atempo のどちらか片方しか書いていないか、-map が抜けています。
# Wrong: 映像しか速くならない(音声は元のまま流れて長さが合わない)
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" output_bad.mp4
# 正しい: 両方を filter_complex で処理し、map で出力に明示
ffmpeg -i input.mp4 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" \
-map "[v]" -map "[a]" output_ok.mp4
2. 「Value 3.000000 for parameter ‘tempo’ out of range」エラー
原因: FFmpeg 4.0 以前で atempo に 2.0 を超える値を指定しています(0.5 未満の値はどのバージョンでも同じエラーになります)。
解決: バージョンを上げるか、atempo=2.0,atempo=1.5 のように連結します(積で 3.0)。
3. 音声と映像のリップシンクが少しだけズレる
原因: setpts の係数と atempo の係数を掛けた値が 1 になっていません。たとえば 0.333*PTS と atempo=3.0 では 0.999 になり、1 時間で約 1.2 秒ずれます。
解決: setpts=N*PTS と atempo=1/N が逆数の関係になるように、厳密に合わせます。0.5*PTS ↔ atempo=2.0、PTS/3 ↔ atempo=3.0 など。割り切れない倍率は PTS/3 のように割り算で書きます。
4. スローにしたらフレームがカクつく
原因: setpts だけだと既存フレームを伸ばすため、実効 fps が低下します。
解決: minterpolate=fps=60:mi_mode=mci を後段に追加します(前述)。
5. 出力ファイルの長さがおかしい
原因: concat に渡す各区間のタイムスタンプが 0 から始まっていないか、-shortest を付け忘れています。
解決: 各セグメント内で setpts=PTS-STARTPTS / asetpts=PTS-STARTPTS を入れて時間原点をリセットします。映像と音声の長さが違うまま出力されるときは、-shortest を付けると短いほうに合わせて終わります。
FAQ
Q1. 音と映像のどちらかだけが速くなるのはなぜですか?
A. -vf を使うと音声は処理されません。-filter_complex で映像と音声を別々に書き、-map "[v]" -map "[a]" で出力にマップしてください。-vf を使う場合も、-af "atempo=N" を併用すれば両方を処理できます。
Q2. 10 倍速にしたら音が壊れて聞こえます。
A. 10 倍速では、音程を保っても言葉としては聞き取れません。早送りのプレビューが目的なら、-an で音声を消すのが定石です。
Q3. スローモーションがカクつくのは仕様ですか?
A. はい、setpts は時間を引き延ばすだけでフレームを増やしません。元 30fps を 0.25 倍にすると実効 7.5fps です。minterpolate=fps=60:mi_mode=mci でフレームを補間できます。
Q4. 速度変更後にコーデックを変えたいです。
A. 速度変更は再エンコードを伴うので、同じコマンドで -c:v libx264 -crf 23 -c:a aac -b:a 128k を指定すれば変えられます。フィルタと出力コーデックは独立して指定できます。
Q5. iPhone のスロー動画を更にスローにできますか?
A. できます。iPhone のスロー素材は 240fps または 120fps で撮影されます(カメラと設定によります)。240fps の素材なら、setpts=2*PTS を適用しても 120fps 相当のなめらかさが残ります。ファイルによって違うので、ffprobe -show_streams で r_frame_rate を確認してから倍率を決めてください。
Q6. 速度変更しても字幕(埋め込み)の同期は維持されますか?
A. ハードサブ(焼き付け)なら映像と一緒に再エンコードされるため自動同期します。ソフトサブは別ストリームなので、字幕の時刻も同じ倍率で変える必要があります。-itsoffset は時刻を一定量ずらすだけなので、速度変更には使えません。2 倍速なら ffmpeg -i subs.srt -c copy -bsf:s "setts=ts=TS/2:duration=DURATION/2" subs_2x.srt で、字幕の開始時刻と表示時間を半分にできます。