Variable frame rate (VFR) is video where the time between frames isn’t fixed — the source records frames whenever something changes rather than at a steady cadence. Many screen recorders, phone cameras, and game-capture tools often produce VFR. It’s efficient for recording, but it’s also the hidden root cause behind a huge share of “my audio is out of sync” problems, because a steady audio clock can’t stay aligned with a wandering video clock. Many editors and players also assume constant frame rate (CFR) and mishandle VFR outright. This article shows how to detect VFR with ffprobe and convert it to CFR with FFmpeg.
Tested with: FFmpeg 8.1
What You’ll Learn
- What VFR and CFR are, and why VFR causes sync problems
- How to suspect VFR with
ffprobeby comparingr_frame_rateandavg_frame_rate(a heuristic) - How to convert VFR to CFR with
-fps_mode cfrand a target rate - That FFmpeg 8.x uses
-fps_mode(the old-vsyncstill works but is deprecated)
If you arrived here because your audio drifts or went out of sync, converting to CFR is often the fix. See also Fix Audio Drift and Audio Out of Sync After Converting.
VFR vs CFR
| Type | Frame timing | Typical source | Editor/player friendliness |
|---|---|---|---|
| VFR (variable) | Intervals vary frame to frame | Screen/phone/game capture | Often mishandled; can drift |
| CFR (constant) | Fixed interval (e.g. every 1/30 s) | Broadcast, most encoders | Universally supported |
With CFR, every frame sits at a predictable point in time, so a steady audio clock stays locked to the picture. With VFR, the frame intervals wander, and any tool that assumes a fixed rate gradually misaligns the audio — which shows up as drift that worsens over the clip.
Step 1: Detect VFR with ffprobe
A quick way to suspect VFR is to compare two reported rates: r_frame_rate and avg_frame_rate (the average across the file). It’s important to understand what r_frame_rate actually is: it is FFmpeg’s guess at a base rate — the lowest rate that can represent all the timestamps in the stream (an LCM-like value), not the “real” or intended frame rate. So when r_frame_rate and avg_frame_rate differ, that’s a heuristic that the file may be VFR — it is not proof on its own. For a true CFR file the two are usually equal or nearly so.
Run a quick inspection of the file:
ffprobe -hide_banner input.mp4
In the stream summary, FFmpeg prints values like 30 fps and 29.97 tbr. To read the two rates explicitly, look at the video stream’s r_frame_rate and avg_frame_rate fields. When they diverge, treat it as a strong hint that the file is VFR — then confirm before converting.
# Illustrative comparison (not a command)
r_frame_rate = 60/1 <- FFmpeg's base-rate guess (LCM-like)
avg_frame_rate = 47/1 <- actual average; differs => suspect VFR
A close or identical pair points to CFR; a noticeable gap is a sign of VFR. To confirm VFR rather than just suspect it, check whether the actual per-frame durations vary — for example by inspecting per-frame timestamps (ffprobe -show_frames / -show_packets and looking at how pkt_duration / the gaps between timestamps change). Genuinely varying frame durations mean VFR; uniform durations mean the file is effectively CFR even if the two reported rates differ.
Step 2: Convert to CFR at 30 fps
To convert, force constant frame rate with -fps_mode cfr and pick a target rate with -r. Use a rate that matches your source’s nominal cadence (commonly 30 for screen/phone capture). Here the audio is copied untouched, so only the video is re-encoded.
ffmpeg -i input.mp4 -fps_mode cfr -r 30 -c:v libx264 -c:a copy output.mp4
-fps_mode cfr— force constant frame rate output-r 30— target 30 frames per second-c:v libx264— re-encode video onto the steady timeline (required to change frame timing)-c:a copy— copy the audio as-is (no quality loss)
Re-encoding the video is unavoidable when forcing CFR, because FFmpeg has to duplicate or drop frames to hit the fixed cadence. The audio can usually be copied.
Step 3: Convert to CFR at 60 fps (Higher Quality)
For higher-motion content (gameplay, fast action) where you want 60 fps and a higher quality target, raise the rate and lower the CRF. Here the audio is re-encoded to AAC, which is the safe choice if the source audio codec isn’t ideal for the output container.
ffmpeg -i input.mp4 -fps_mode cfr -r 60 -c:v libx264 -crf 18 -c:a aac output.mp4
-r 60— target 60 frames per second-crf 18— higher quality than the default (lower CRF = better quality, larger file)-c:a aac— re-encode audio to AAC for broad MP4 compatibility
Pick the target rate deliberately: encoding a 30 fps source to 60 fps just duplicates frames and doesn’t add real smoothness, so match -r to what your source actually delivers unless you have a specific reason to upscale the rate.
Important: -fps_mode vs the Deprecated -vsync
In FFmpeg 8.x the correct option is -fps_mode cfr. You may still see older tutorials using -vsync cfr (or -vsync 1). That syntax still works for now, but -vsync is deprecated and may be removed in a future release. Prefer -fps_mode in any new command. They map to the same underlying behavior — cfr forces a constant frame rate by duplicating or dropping frames as needed.
| Option | Status in FFmpeg 8.x | Use it? |
|---|---|---|
-fps_mode cfr | Current, recommended | Yes |
-vsync cfr / -vsync 1 | Deprecated, still functional | No (legacy only) |
Summary Table
| Goal | Command |
|---|---|
| Suspect VFR | ffprobe -hide_banner input.mp4 (compare r_frame_rate vs avg_frame_rate) |
| Convert to CFR 30, keep audio | ffmpeg -i input.mp4 -fps_mode cfr -r 30 -c:v libx264 -c:a copy output.mp4 |
| Convert to CFR 60, high quality | ffmpeg -i input.mp4 -fps_mode cfr -r 60 -c:v libx264 -crf 18 -c:a aac output.mp4 |
To set a frame rate without the VFR-to-CFR framing (just changing fps), see Change the Frame Rate.
FAQ
How do I know for sure my file is VFR?
Comparing r_frame_rate and avg_frame_rate is only a heuristic: r_frame_rate is FFmpeg’s guess at a base rate (an LCM-like value), not the real frame rate, so a mismatch merely suggests VFR. To confirm it, inspect the actual per-frame durations (e.g. per-frame timestamps via ffprobe -show_frames / -show_packets): if the gaps between frames vary, the file is truly VFR; if they’re uniform, it’s effectively CFR despite the mismatch. Screen, phone, and game captures are VFR far more often than not.
Why does VFR cause audio sync problems?
Audio plays on a steady sample clock, but VFR video frames arrive at irregular intervals. Any tool that assumes a constant rate gradually misaligns the two, producing drift that worsens over the clip. Converting to CFR gives the audio a fixed cadence to lock onto — see Fix Audio Drift.
Do I have to re-encode the video to convert VFR to CFR?
Yes. Forcing a constant frame rate requires duplicating or dropping frames to hit the fixed cadence, which means re-encoding the video. The audio, however, can often be copied with -c:a copy.
What frame rate should I target?
Match -r to your source’s nominal rate — usually 30 for screen/phone capture or 60 for gameplay. Encoding a 30 fps source to 60 fps just duplicates frames without adding real smoothness.
Should I use -vsync or -fps_mode?
Use -fps_mode cfr. In FFmpeg 8.x -vsync is deprecated; it still works but should be considered legacy. New commands should use -fps_mode.
Related Articles
- Change the Frame Rate
- Fix Audio Sync
- Fix Audio Drift
- Audio Out of Sync After Converting
- Fix Audio Delay Manually
Tested with FFmpeg 8.1 — verified with our command-check script
Primary sources: ffmpeg.org/ffmpeg.html / ffmpeg.org/ffmpeg-filters.html#aresample