Using -r 0.1
sets the output framerate to 0.1Hz, but it's not guaranteed to get frame from the input video exactly every 10 seconds (I am not sure why).
One way for solving it is using select filter.
Example (without GPU acceleration):
ffmpeg -i input.mp4 -vf "select=bitor(gte(t-prev_selected_t\,10)\,isnan(prev_selected_t))" -vsync 0 f%09d.jpg
ffmpeg -i input.mp4 -vf "select=bitor(gte(t-prev_selected_t\,10)\,isnan(prev_selected_t))" -vsync 0 f%09d.jpg
bitor(gte(t-prev_selected_t\,10)
is1
when difference between "passed" timestamps is grater of equal 10 seconds.
When expression is evaluated to1
, the frame is "selected" and passed to the output.bitor
withisnan(prev_selected_t)
passes the first frame, whereprev_selected_t
isNaN
(has no value).-vsync 0
applies "passthrough" - Each frame is passed with its timestamp from the demuxer to the muxer.
Here is an example with scale_cuda
and thumbnail_cuda
:
ffmpeg \
-loglevel error \
-hwaccel cuvid \
-hwaccel_output_format cuda \
-c:v h264_cuvid \
-i "$video_file" \
-filter:v "scale_cuda=w=-1:h=100,thumbnail_cuda=2,hwdownload,format=nv12,select=bitor(gte(t-prev_selected_t\,10)\,isnan(prev_selected_t))" \
-vsync 0 \
-color_range 2 \
f%09d.jpg
- Due to the usage of
thumbnail_cuda
filter, we have to place theselect
filter at the end.
Testing:
Build synthetic video with frame counter at 10fps:
ffmpeg -y -f lavfi -r 10 -i testsrc=size=128x72:rate=1:duration=1000 -vf setpts=N/10/TB -vcodec libx264 -pix_fmt yuv420p input.mp4
ffmpeg -y -f lavfi -r 10 -i testsrc=size=128x72:rate=1:duration=1000 -vf setpts=N/10/TB -vcodec libx264 -pix_fmt yuv420p input.mp4
Output frames after executing the above command:
As you can see, the selected frames are exactly every 10 seconds.