FFmpeg Seek to Frame Number Instead of Time
FFmpeg natively seeks using time duration rather than frame numbers. However, you can easily target a specific frame by either calculating the timestamp using the video’s frame rate (FPS) or by using FFmpeg’s video filters to select the exact frame number. This article provides straightforward methods to achieve both, allowing you to seek and extract specific frames efficiently.
Method 1: The Calculation Method (Fastest)
The fastest way to seek to a specific frame is to convert the frame
number into a time value. Because FFmpeg can seek instantly using the
-ss parameter, calculating the time is highly
efficient.
Use this formula to find the time in seconds: Time (seconds) = Target Frame Number / Frame Rate (FPS)
For example, if you want to seek to frame 300 in a video that runs at 30 FPS: 300 / 30 = 10 seconds.
You can then run the following command to seek to that position and extract a single frame:
ffmpeg -ss 10 -i input.mp4 -vframes 1 output.pngMethod 2: The Select Filter Method (Most Accurate)
If you do not know the frame rate, or if the video has a variable
frame rate (VFR), calculating the time might not be accurate. In this
case, you can use the select filter to target the exact
frame number by index (where the first frame is 0).
To extract frame 300 using the filter method, run:
ffmpeg -i input.mp4 -vf "select=eq(n\,300)" -vframes 1 output.pngNote: This method is slower than the calculation method because FFmpeg must decode the video from the very beginning to count the frames accurately.
Method 3: Combined Method for Large Videos (Fast & Accurate)
For very long videos, using the select filter alone can
take a long time. You can combine both methods by using -ss
to seek close to your target frame, and then using the
select filter to land on the exact frame.
If you want to seek to frame 9000 in a 30 FPS video (which is roughly 300 seconds):
ffmpeg -ss 295 -i input.mp4 -vf "select=eq(n\,150)" -vframes 1 output.pngIn this command: 1. -ss 295 fast-forwards the video to
295 seconds (frame 8850). 2. The select=eq(n\,150) filter
tells FFmpeg to find the 150th frame after the seek point (8850
+ 150 = 9000).