1

I'm conducting a test with a 10-second video that plays at a rate of 1 frame per second. My goal is to capture a specific frame as a snapshot. Currently, I use the following ffmpeg command for this purpose:

ffmpeg -y -ss 6.3 -i input.mp4 -frames:v 1 -q:v 1 output.png

I want to extract the frame that is displayed at the 6.3-second mark in my video player. However, the command I'm using gives me the frame from the 7.0-second mark instead. Is there a way to accurately capture the frame at 6.0 seconds, ideally without making assumptions about the video's (constant) frame rate?

1 Answer 1

0

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


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


The above solution was tested using FFmpeg version 5.1.2-full_build-www.gyan.dev (with Windows 10).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .