We may apply frames duplication, and use select
filter:
ffmpeg -y -ss 5 -i input.mp4 -copyts -vf "fps=10,select=gte(t\,6.3)" -frames:v 1 -update 1 output.png
-ss 5
- Starts about a second before the relevant time (optionally skipping the beginning of the file, for saving time).
-copyts
- Copy the timestamps of the input frames to the output (without it we have to subtract the start time: select=gte(t\,6.3-5)
.
fps=10
- Increase the frame rate to 10fps for improving the time accuracy - since we want to select 6.3 seconds, we need 0.1 seconds accuracy.
Note that this part is not entirely framerate independent - we may use fps=1000
for better accuracy.
select=gte(t\,6.3)
- selects all frames with timestamps above 6.3 seconds.
Testing:
Building an input video file with advancing counter at 1fps (for testing):
ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=10 input.mp4
Executing the above command:
ffmpeg -y -ss 5 -i input.mp4 -copyts -vf "fps=10,select=gte(t\,6.3)" -frames:v 1 -update 1 output.png
We can verify that we captured the frame at 6.0 seconds:
![enter image description here](https://cdn.statically.io/img/i.sstatic.net/UXTb2.png)
Testing with variable frame rate (VFR video):
Building an input video file with variable frame rate:
ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=10 -fps_mode:v passthrough -vf setpts="N*N/TB" input.mp4
Checking the timestamps using FFprobe:
ffprobe -of default=noprint_wrappers=1 -show_entries packet=pts_time input.mp4
pts_time=0.000000
pts_time=16.000000
pts_time=4.000000
pts_time=1.000000
pts_time=9.000000
pts_time=25.000000
pts_time=81.000000
pts_time=49.000000
pts_time=36.000000
pts_time=64.000000
Capture frame at 10.3 seconds:
ffmpeg -y -ss 5 -i input.mp4 -copyts -vf "fps=10,select=gte(t\,10.3)" -frames:v 1 -update 1 output.png
Output:
![enter image description here](https://cdn.statically.io/img/i.sstatic.net/zIEkH.png)
The above solution was tested using FFmpeg version 5.1.2-full_build-www.gyan.dev (with Windows 10).