The two filters you actually need
FFmpeg can speed up or slow down video, but the math trips people up the first time. The filter you want is setpts. For audio sync, you pair it with atempo. They work independently: you control video speed through presentation timestamps, and audio speed through a time-stretching algorithm. Get both right and the result is clean. Ignore one of them and you end up with video that's out of sync or missing audio entirely.
This guide covers both, plus time-lapse, slow motion, and running speed changes at scale through the RenderIO API.
How setpts works
PTS stands for presentation timestamp. Every video frame has one, which tells the decoder when to display that frame. setpts lets you multiply all of them by a constant.
The math is inverted from what you might expect:
setpts=0.5*PTS→ frames display twice as fast → 2x speed upsetpts=2.0*PTS→ frames display twice as slow → 2x slow motionsetpts=0.25*PTS→ 4x fastersetpts=4.0*PTS→ 4x slower
Think of it this way: if you cut the timestamp in half, the player reaches the end of the video in half the time. That's a speed up. If you double the timestamp, the player takes twice as long. That's slow motion.
Speed up video (video only)
The simplest form strips audio and doubles the speed:
The -an flag disables audio. It's there because if you change video speed without touching audio, they'll be out of sync, and FFmpeg doesn't always warn you about this.
Speed presets:
If you want to slow down instead:
The audio sync problem and how atempo fixes it
Here's the issue: if you use setpts to speed up video and do nothing with audio, the audio keeps playing at normal speed. After a few seconds, the audio and video are noticeably out of sync. By the end of a minute-long clip at 2x speed, the video has finished and the audio is still playing.
The fix is atempo. This is an audio filter that changes playback speed while preserving pitch (unlike asetrate, which changes pitch along with speed).
The atempo value is the inverse of the setpts multiplier:
| Desired speed | setpts value | atempo value |
| 0.5x (half speed) | 2.0 | 0.5 |
| 1.5x | 0.667 | 1.5 |
| 2x | 0.5 | 2.0 |
| 4x | 0.25 | 4.0 (see chaining note below) |
atempo range limit: chain it for extreme speeds
atempo only accepts values between 0.5 and 2.0. If you try atempo=4.0 directly, FFmpeg throws an error. For speeds beyond that range, you chain multiple atempo filters:
The chaining approach works cleanly. Each filter stage gets valid input, and you can go as far as you need.
For a reference sheet of these commands alongside other FFmpeg operations, the FFmpeg cheat sheet has them organized by category.
Time-lapse with FFmpeg
Time-lapse is just extreme speed-up, often 30x to 120x or more. You have two approaches: PTS manipulation or frame rate reduction. They produce different results.
PTS approach (keeps all frames, speeds up playback):
Frame drop approach (keeps every Nth frame, better for large multipliers):
The frame drop approach is more efficient for very long clips. You're not processing every frame, just sampling them. The PTS approach is simpler and works better for moderate speed-ups (10x-30x) where you want smoother motion.
For a proper time-lapse from a long recording (e.g., a 2-hour sunset), the frame drop approach is the right call:
Slow motion from 60fps or 120fps footage
If your camera records at 60fps or 120fps, you can create proper slow motion by conforming it to 24fps or 30fps. This is different from setpts slow motion. You're telling FFmpeg "this footage was shot at 120fps, play it back at 30fps" rather than artificially stretching the timestamps.
This gives you clean slow motion because the actual frames are there, so you're just playing them back slower. setpts slow motion on 30fps footage will stutter because FFmpeg has to duplicate frames to fill the gaps.
For setpts slow motion on standard footage, you can ask FFmpeg to interpolate frames with minterpolate, though this adds processing time and artifacts on complex scenes:
Batch speed changes via API
Running speed changes locally works fine for one-off tasks. When you're producing content at scale, processing dozens of clips per day across different platforms, you want to batch these through an API instead of tying up your machine.
This is exactly the kind of workload RenderIO is built for. You send the FFmpeg command over HTTP, it runs in a cloud sandbox, and you get a download URL back. No FFmpeg to install, no Lambda timeout issues, no local CPU usage. The FFmpeg API complete guide covers the full setup, but here's what a speed change looks like:
For batch processing, you'd loop through your clips and fire off a request per video:
If you're building a social media content pipeline that needs multiple speed variations per clip, say a normal version, a 1.5x version for Stories, and a 2x version for YouTube Shorts previews, you can use RenderIO's parallel processing to generate all three at once. The batch processing guide for social media covers the full multi-platform pattern.
You can also change video speed through the browser without installing anything using the change video speed tool, useful for quick one-offs before you commit to automating the whole pipeline.
Common mistakes
No audio handling
If you use -vf "setpts=..." without touching audio, the output has mismatched audio unless you also add -an or the matching atempo. FFmpeg doesn't always warn you. It'll just mux them together and let you discover the problem on playback.
atempo out of range
Values outside 0.5-2.0 will fail. Chain the filter instead of trying to pass 3.0 or 4.0 directly.
PTS resets on concatenated footage
If your input is a concatenated file with PTS resets (common with some cameras), add -vf "setpts=PTS-STARTPTS" before the speed filter to normalize timestamps first: -vf "setpts=PTS-STARTPTS,setpts=0.5*PTS".
Codec compatibility after speed change
After changing speed significantly, re-encode with a codec that handles your target bitrate well. For web delivery, -c:v libx264 -crf 22 -c:a aac is reliable. For a full reference on encoding flags, see the FFmpeg cheat sheet.
Frame rate mismatch for timelapse
If you're creating a time-lapse and the output looks choppy, check the output frame rate. For very extreme speed-ups, add -r 30 to enforce a consistent output frame rate: -vf "setpts=0.01*PTS" -r 30.