Variable frame rate (VFR) means the time between video frames changes during the video. Recording settings, a system that cannot keep up, or the way a capture tool works can cause it. It does not always mean frames are saved only when the picture changes. With correct timestamps, VFR video stays in sync with its audio. Convert to constant frame rate (CFR) when your editor needs it or a test shows a real compatibility problem, not just because the file is VFR.

First play the original and a converted copy in the same player and compare the beginning, middle and end. If both are off by the same fixed amount, changing the frame rate will not fix it. If only your editor has a problem, try a short CFR copy in the editor before you convert a long recording. See Fix Audio Drift and Audio Out of Sync After Converting.

VFR vs CFR

Type Frame timing Typical source Editors and players
VFR (variable) Intervals vary frame to frame Some screen/phone/game capture Need software that reads timestamps
CFR (constant) Fixed interval (e.g. every 1/30 s) Many editing/delivery workflows A fixed frame rate alone does not make the codec compatible

Both can stay in sync. A tool that ignores presentation timestamps can play VFR wrongly. Damaged timestamps, data lost during capture or an audio offset cause problems too. CFR conversion duplicates or drops frames. It cannot bring back missing pictures or work out the correct lip sync.

Step 1: Detect VFR with ffprobe

A quick first check is to compare two rates that ffprobe reports: r_frame_rate and avg_frame_rate (the average over the whole file). r_frame_rate is FFmpeg’s guess at a base rate: the lowest rate that can represent every timestamp in the stream (similar to a least common multiple). It is not the real or intended frame rate. If the two values differ, the file may be VFR, but that alone does not prove it. In a true CFR file the two are usually equal or very close.

For a quick look at the file:

ffprobe -hide_banner input.mp4

This summary alone does not settle it. To read the two rate values directly:

ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate,avg_frame_rate,time_base -of json input.mp4
# 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

Equal values do not prove CFR either. Check the presentation timestamps of the decoded frames across the whole clip. Packet order and rounded durations can mislead you, especially with B-frames (which make the decode order differ from the display order). Steps that alternate slightly can also be a constant fractional rate stored in a coarse time base. Missing or damaged timestamps are a separate problem.

ffprobe -v error -select_streams v:0 -show_frames -show_entries frame=best_effort_timestamp_time -of json input.mp4

Read the best_effort_timestamp_time value of each frame. Other side-data fields may also appear; they are not frame times. The output can be long. Compare the times of consecutive frames, allowing for rounding. Do not pick your target rate from the average alone.

Step 2: Convert to CFR at 30 fps

Force a constant frame rate with -fps_mode cfr and set the target rate with -r. Choose the rate from the recording settings and what your editor or platform requires, not from the type of device. This example copies the audio, 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: output at a constant frame rate
  • -r 30: target 30 frames per second
  • -c:v libx264: re-encode the video at the fixed rate (needed to change frame timing)
  • -c:a copy: copy the audio unchanged (no quality loss)

Both CFR commands re-encode the video and duplicate or drop frames as needed. Copying the audio keeps it unchanged: an existing offset stays, and the audio codec still has to work in MP4. The commands let FFmpeg pick the streams, so not every audio track, subtitle or attachment is kept. Keep the original and use a different output file name.

Step 3: Choose 60 fps or a Fractional Target

If the footage was recorded at about 60 fps and your workflow needs 60 fps, use this command. It encodes with CRF 18 and AAC audio. A higher frame rate on its own does not raise quality.

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 means better quality and a larger file)
  • -c:a aac: re-encode the audio to AAC, which works widely in MP4

Converting a 30 fps source to 60 fps only duplicates frames. Motion does not get smoother. Match -r to the source unless you have a specific reason to raise it.

For 29.97 or 59.94 fps, use 30000/1001 or 60000/1001. These are not exactly 30 or 60. After converting, check the duration, frame timing, motion and audio sync in the editor you will use. A constant rate in ffprobe’s output does not by itself show that the problem is fixed.

For a small file, the browser VFR-to-CFR tool converts without installing anything. It has its own settings, is limited by browser memory, and does not offer every option shown here.

Timing Check and Option Compatibility

Synthetic Timing Check

Native FFmpeg 8.1 on Windows converted a generated 3-second VFR clip (50 video frames and a tone) once with each command above, on 2026-09-12.

Output Video frames Container duration Decoded frame interval
CFR 30 90 3.000 s About 0.033333 s
CFR 60 / AAC 180 3.008 s About 0.016667 s

The input settings, commands and output hashes let you repeat the check. Differences of a fraction of a millisecond are partly timestamp rounding. The duration is the container duration; it does not show that audio and video end at exactly the same point. The check covers frame timing only, not lip sync in a real recording, browser speed or picture quality.

Option Compatibility

In FFmpeg 8.x the option is -fps_mode cfr. Older tutorials use -vsync cfr (or -vsync 1). That still works, but -vsync is deprecated and may be removed in a later release, so use -fps_mode in new commands. Both do the same thing: 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
Check frame timing Use the JSON rate and timestamp commands in Step 1; the short summary is only a clue
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, CRF 18 / AAC ffmpeg -i input.mp4 -fps_mode cfr -r 60 -c:v libx264 -crf 18 -c:a aac output.mp4

If you only want to change the fps, see Change the Frame Rate.

FAQ

How do I know for sure my file is VFR?

The two rates are only a clue. Check the frame timestamps as shown above, tell real interval changes apart from rounding, and check the whole clip, not only the start. The kind of device that recorded it does not tell you.

Does VFR necessarily cause audio sync problems?

No. A player can use the presentation timestamps to keep frames with changing intervals in sync with the audio. CFR can help software that cannot handle VFR, but it does not fix every cause of drift. Fix Audio Drift explains how to tell this apart from a problem in the audio timing itself.

Do I have to re-encode the video to convert VFR to CFR?

Yes. A constant frame rate means duplicating or dropping frames to fit the fixed schedule, and that requires re-encoding the video. The audio can often be copied with -c:a copy.

What frame rate should I target?

Look at the recording settings and at what your editor or platform requires, including whether the rate is fractional. Device type and average fps do not tell you the intended rate. Encoding a 30 fps source at 60 fps duplicates frames and does not make motion smoother.

Should I use -vsync or -fps_mode?

Use -fps_mode cfr. In FFmpeg 8.x -vsync is deprecated. It still works, but use -fps_mode in new commands.