To speed up or slow down a video with FFmpeg, change the video with setpts and the audio with atempo, using matching ratios. If the ratios don’t match, the sound drifts out of sync. You can use any speed from 0.25× to 10×, keep the pitch, or change the speed of only one section.

Speed Basics: setpts and atempo

FFmpeg changes the video and the audio separately. For the video, it changes the presentation timestamps (PTS: when each frame is shown). For the audio, it changes the tempo. If you get the direction wrong, they go out of sync.

Stream Filter Coefficient meaning Example (2× speed)
Video setpts=N*PTS Smaller = faster (compresses PTS) setpts=0.5*PTS
Audio atempo=N Larger = faster (playback multiplier) atempo=2.0

The setpts coefficient is the reciprocal of the speed. To play 2× as fast, halve the PTS (0.5*PTS). To play at half speed, double the PTS (2*PTS). atempo takes the speed itself.

Speed / coefficient cheat sheet

Playback speed setpts coefficient atempo coefficient
0.25× (4× slow) 4*PTS 0.5,atempo=0.5 (chained; a single atempo can’t go below 0.5)
0.5× (2× slow) 2*PTS 0.5
1.0× (normal) 1*PTS 1.0
2.0× (fast) 0.5*PTS 2.0
4.0× 0.25*PTS 4.0
10.0× 0.1*PTS 10.0

Since FFmpeg 4.1, a single atempo accepts 0.5–100×. FFmpeg 4.0 and older accept only 0.5–2.0, so you chain several, such as atempo=2.0,atempo=2.0 (see below).

Speed Up (2×, 4×, 10×)

2× speed (with synced audio)

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 halves the video timestamps, and atempo=2.0 doubles the audio tempo. Map the labeled filter_complex outputs with -map "[v]" -map "[a]". If you leave them unmapped, FFmpeg stops with an error such as Filter 'setpts:default' has output 0 (v) unconnected.

4× speed

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

A 20-second clip becomes 5 seconds. On FFmpeg 4.1 and later, a single atempo=4.0 works.

10× speed

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× suits security camera digests and timelapse-like summaries. At this speed, speech can’t be understood, so it is usually better to drop the audio with -an.

Slow Down (0.5×, 0.25×)

0.5× (half speed)

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 shows each frame twice as long, and atempo=0.5 halves the audio tempo.

0.25× (4× slow)

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

Two atempo=0.5 filters in a row give 0.25×. On every version, a single atempo cannot go below 0.5, so anything slower than 0.5× needs a chain.

Slow motion made with setpts can look choppy. setpts only stretches time; it does not create new frames. A 30fps source slowed to 0.25× plays at an effective 7.5fps. To create in-between frames, see the minterpolate section below.

atempo Limits and Workarounds

The range a single atempo accepts:

FFmpeg version Single-instance range Practical range with chaining
4.0 and older 0.5 – 2.0 Any ratio via chaining
4.1 and newer 0.5 – 100.0 Chain below 0.5

0.25× by chaining (no atempo=0.25)

# Wrong: atempo=0.25 is out of range (0.5–100) and errors
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
# Correct: chain two 0.5 instances → 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

8× on old FFmpeg

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

Three atempo=2.0 filters in a row give 2 × 2 × 2 = 8×. The values multiplied together must equal the target speed.

Speed Up Video Only

For silent timelapses or sped-up security footage, you can drop the audio. The command is then simpler.

ffmpeg -i input.mp4 -vf "setpts=0.25*PTS" -an output_4x_silent.mp4
  • -an — drop the audio stream
  • -vf — with only a video chain, -vf is enough; you don’t need filter_complex
# Slow with no audio
ffmpeg -i input.mp4 -vf "setpts=2*PTS" -an output_slow_silent.mp4

To keep the original audio unchanged, use -c:a copy. The video then ends up shorter or longer than the audio track, so they no longer match.

Pitch-Preserving Speed Change (rubberband)

atempo already keeps the pitch while it changes the tempo, so speech at 3× does not sound like a chipmunk. The rubberband filter is another time-stretching filter, built on the Rubber Band library. You can use it instead of 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 doubles the tempo and keeps the original pitch. It suits interviews, lectures and other speech that must stay easy to follow.

# Slow-mo with rubberband (pitch unchanged)
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 needs an FFmpeg build with --enable-librubberband. On Windows, use the full build from gyan.dev. On macOS, use brew install ffmpeg-full (Homebrew’s plain ffmpeg does not include it). On Ubuntu, the standard package works (sudo apt install ffmpeg). To check, run ffmpeg -filters | grep rubberband.

Variable-Speed Sections

To play, for example, the first 5 seconds slowly and the rest at normal speed, you have two options.

Option 1: setpts expression with a time conditional (video only)

ffmpeg -i input.mp4 -vf "setpts='if(lt(T,5),2*PTS,PTS+5/TB)'" -an output_var.mp4

T is the input frame’s time in seconds. Frames before 5 s get their PTS doubled (0.5× speed). Frames from 5 s on keep normal speed but are pushed back by the extra 5 seconds (5/TB is 5 seconds in timestamp units). A 20-second clip becomes 25 seconds. Without that offset, if(lt(T,5),2,1)*PTS makes the slowed part overlap the rest, and frames get dropped.

Option 2: trim + setpts + concat (audio supported)

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 and atrim cut out the time ranges. Each range gets its own speed, and concat joins them. Use this when the audio must stay in sync. Variable speed takes some trial and error, so start with the -an version, check the cuts, then add the audio.

Smooth Slow-Mo with Frame Interpolation

setpts=2*PTS alone only stretches the existing frames; no frames are added. The minterpolate filter creates in-between frames from motion vectors, which gives smooth slow motion.

ffmpeg -i input.mp4 -vf "setpts=4*PTS,minterpolate=fps=60:mi_mode=mci" -an output_smooth_slow.mp4
  • setpts=4*PTS — 4× slow
  • minterpolate=fps=60 — output frame rate of 60fps
  • mi_mode=mci — Motion Compensated Interpolation (creates in-between frames)
mi_mode Meaning Use case
dup Duplicate frames only Fast, low quality
blend Cross-fade blend Mid quality, light
mci Motion-compensated (recommended) High-quality slow-mo

minterpolate uses a lot of CPU. HD video can take tens of times longer than its running time. For long clips, cut out the part you need with -ss / -to first.

Re-encode After Speed Change

A speed change already re-encodes the video, so you can set the codec options in the same command.

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 — standard quality (18–28 is the practical range, lower = better)
  • -preset medium — a balance of speed and compression
  • -c:a aac -b:a 128k — common AAC 128kbps audio

For smaller files, use H.265 with -c:v libx265 -crf 28.

Troubleshooting

1. Only the audio (or only the video) sped up

Cause: the command has only setpts or only atempo, or the -map is missing.

# Wrong: video sped up but audio still 1× — total length mismatches
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" output_bad.mp4
# Correct: both sides processed via filter_complex, mapped explicitly
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”

Cause: atempo above 2.0 on FFmpeg 4.0 or older. (A value below 0.5 gives the same error on every version.)
Fix: update FFmpeg, or chain filters, such as atempo=2.0,atempo=1.5 (the product is 3.0).

3. Slight lipsync drift between audio and video

Cause: the setpts and atempo coefficients are not exact reciprocals of each other.
Fix: make setpts=N*PTS and atempo=1/N exact inverses: 0.5*PTS ↔ atempo=2.0, PTS/3 ↔ atempo=3.0. For ratios that don’t divide evenly, write a division such as PTS/3. 0.333*PTS with atempo=3.0 drifts by about 1.2 seconds per hour.

4. Slow-mo looks choppy

Cause: setpts stretches the existing frames without adding new ones, so the effective fps drops.
Fix: chain minterpolate=fps=60:mi_mode=mci after setpts (see above).

5. Output duration looks wrong

Cause: the concat segments don’t reset their timestamps, or -shortest is missing.
Fix: add setpts=PTS-STARTPTS / asetpts=PTS-STARTPTS to each segment so its timestamps start at zero. If the video and audio still come out with different lengths, add -shortest so the output ends with the shorter stream.

FAQ

Q1. Why does only the video (or only the audio) end up sped up?
A. -vf does not change the audio. Use -filter_complex with one chain for the video and one for the audio, then map both with -map "[v]" -map "[a]". If you prefer -vf, add -af "atempo=N" for the audio.

Q2. At 10× speed the audio sounds broken. Is that normal?
A. Yes. At 10×, speech can’t be understood, even with the pitch kept. For fast-forward previews, drop the audio with -an.

Q3. My slow-motion is choppy. What’s wrong?
A. Nothing. setpts only stretches time; it does not create new frames. A 30fps source at 0.25× has an effective 7.5fps. Add minterpolate=fps=60:mi_mode=mci to create in-between frames.

Q4. Can I switch codecs in the same command after speed change?
A. Yes. A speed change always re-encodes, so add -c:v libx264 -crf 23 -c:a aac -b:a 128k (or the codec you want) to the same command. Filters and output codecs are set separately.

Q5. Can I slow down an iPhone slow-mo clip even further?
A. Yes. iPhone slow motion is recorded at 240fps or 120fps, depending on the camera and settings. A 240fps clip still has an effective 120fps after setpts=2*PTS. Files differ, so check r_frame_rate with ffprobe -show_streams before you pick a speed.

Q6. Will embedded subtitles stay in sync after a speed change?
A. Burned-in subtitles (hard subs) are re-encoded with the video, so they stay in sync. Soft subtitles are a separate stream, so their times must be scaled by the same factor. -itsoffset only shifts all times by a fixed amount, so it can’t follow a speed change. For 2× speed, ffmpeg -i subs.srt -c copy -bsf:s "setts=ts=TS/2:duration=DURATION/2" subs_2x.srt halves both the start times and the display durations.


Primary source: ffmpeg.org/ffmpeg-filters.html#setpts / ffmpeg.org/ffmpeg-filters.html#atempo