To preserve the original framerate during FFmpeg encoding without triggering a reset or resampling, you must avoid using the
-r flag on the input stream, as this forces frame rate conversion. Instead, rely on the encoder’s native handling of timestamps by omitting explicit rate overrides and ensuring your output container supports variable frame rates if necessary. This approach maintains temporal integrity while allowing for efficient compression.
Understanding the Problem with -r
Many users encounter issues where their video’s frame rate changes unexpectedly after processing. The most common culprit is the misuse of the
-r flag. When placed before an input file, such as
ffmpeg -i input.mp4 -r 30 output.mp4, the
-r flag acts as an input filter. It tells FFmpeg to resample the incoming frames to match the specified rate. If the source is 60fps and you specify
-r 30, FFmpeg will drop half the frames or duplicate them to fit the new rate, fundamentally altering the timing. Even if you intend to keep the same rate, explicitly setting it can sometimes cause conflicts with how the encoder handles variable frame rates (VFR) versus constant frame rates (CFR).
This behavior is distinct from setting the output rate. Placing
-r after the input but before the output can set the *output* frame rate, but it still implies a conversion process if the internal timestamps do not align perfectly. For pure passthrough or encoding that respects the source timing, manual intervention via
-r is often the wrong tool.
Correct Passthrough Strategies
The goal is to let FFmpeg read the source timestamps and write them directly to the output without modification. There are two primary scenarios: copying streams without re-encoding, and encoding while preserving the source frame rate structure.
Scenario A: Stream Copying
If you do not need to change the codec or quality, use the copy command. This is the fastest method and guarantees zero alteration of any metadata, including frame rate.
ffmpeg -i input.mp4 -c copy output.mp4
This command copies all streams (video, audio, subtitles) exactly as they are. No decoding or encoding occurs, so the frame rate remains identical to the source.
Scenario B: Re-encoding with Preserved FPS
When you must re-encode (e.g., changing H.264 to H.265), you should avoid forcing a specific frame rate. Modern encoders like
libx264 and
libx265 are designed to handle the input frame rate intelligently. By omitting
-r, you allow the encoder to use the timestamps provided by the demuxer.
ffmpeg -i input.mp4 -c:v libx265 -crf 28 output.mp4
In this example, the video is re-encoded using the HEVC codec with a Constant Rate Factor (CRF) of 28. Because no
-r flag is present, FFmpeg preserves the original timing. If the source is Variable Frame Rate (VFR), the output will also be VFR, which is often preferred for streaming platforms and modern playback devices.
Handling Variable Frame Rate (VFR) Sources
A common misconception is that VFR is "bad." In reality, VFR is highly efficient because it uses fewer frames during static scenes and more during action. However, some older players or editing software struggle with VFR files. If your target platform requires Constant Frame Rate (CFR), you have two choices: convert to CFR during encoding or convert after encoding.
Converting to CFR During Encoding
If you specifically need a fixed frame rate (e.g., for broadcast standards), use the
setpts filter or the
fps video filter *after* the input but *before* the encoder. Note that this is different from
-r.
ffmpeg -i input.mp4 -vf fps=fps=24 -c:v libx264 -crf 23 output.mp4
Here, the
fps filter converts the video to a constant 24fps. This is an active conversion, not a passthrough. Use this only when a fixed rate is required. If you want to keep the original rate but ensure compatibility, consider converting to CFR in a second pass or using a tool dedicated to VFR-to-CFR conversion, such as
mkvmerge or specialized scripts.
Why 'fps=keep' Fails
Some guides suggest using
-vf fps=keep. This option does not exist in standard FFmpeg builds. Attempting to use it results in an error. The correct way to "keep" the frame rate is simply to not touch it at all. Let the encoder inherit the timestamp information from the input stream.
Verifying Your Output
After encoding, always verify the frame rate of the output file to ensure it matches your expectations. You can use FFprobe, a companion tool to FFmpeg, to inspect the stream details.
ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate -of default=noprint_wrappers=1:nokey=1 output.mp4
This command extracts the raw frame rate value from the video stream. Compare this output with the source file’s frame rate. If they match, your passthrough was successful. If they differ, review your command line for any stray
-r flags or filter settings that might have forced a conversion.
Common Pitfalls
- Mixing Input and Output Flags: Ensure
-r is not interpreted as an input resampler. Always check the position of flags relative to -i.
- Container Limitations: Some containers, like MP4, have strict requirements for certain codecs. While H.264/H.265 support VFR in MP4, other formats may not. Check container documentation if you experience sync issues.
- Audio Sync Drift: If you change video frame rates significantly, audio drift may occur. Using
-async 1 or adjusting audio timestamps can help, but preserving the original video rate avoids this entirely.
For more advanced encoding techniques, you might explore how to handle low-bitrate audio efficiently, which often complements video optimization strategies. See
FFmpeg vs LAME: Equivalent MP3 Encoding with Low CBR for insights into maintaining quality across media types. Additionally, if you are working with multiple streams, understanding how FFmpeg handles them is crucial to avoiding errors. Refer to
Error Starting Encoding with Multiple Video Streams in FFmpeg for troubleshooting complex inputs.
Frequently Asked Questions
Does removing -r guarantee the frame rate stays the same?
Yes, omitting the
-r flag allows FFmpeg to preserve the source timestamps and frame rate structure. The encoder will use the incoming frame timing unless explicitly told otherwise by filters or output flags.
What if my source is VFR and I need CFR?
You must actively convert it using the
fps video filter, such as
-vf fps=fps=30. There is no automatic "passthrough" mode for VFR-to-CFR conversion; it requires resampling the frames to a constant interval.
Can I use -r after the input to set output rate?
While technically possible, it is discouraged because it can conflict with the encoder’s internal handling of timestamps. It is safer to use video filters like
fps= for explicit rate changes or rely on the encoder’s defaults for preservation.
How do I check if my video is still VFR after encoding?
Use
ffprobe to inspect the stream. Look for the
avg_frame_rate and
r_frame_rate fields. If they differ significantly or show fractional values typical of VFR, the variable rate has been preserved.
Why did my video lose sync after encoding?
Sync issues often arise when video frame rates are changed without adjusting audio timestamps. Preserving the original frame rate by avoiding
-r prevents this mismatch, ensuring audio and video remain aligned.