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 で、字幕の開始時刻と表示時間を半分にできます。

関連記事