Skip to main content
Code formatting.
Source Link
Giacomo1968
  • 56.1k
  • 23
  • 167
  • 214

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) is 1 when difference between "passed" timestamps is grater of equal 10 seconds.
    When expression is evaluated to 1, the frame is "selected" and passed to the output.
  • bitor with isnan(prev_selected_t) passes the first frame, where prev_selected_t is NaN (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 the select 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:

enter image description here enter image description here enter image description here enter image description here enter image description here
enter image description here enter image description here enter image description here enter image description here enter image description here

As you can see, the selected frames are exactly every 10 seconds.

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


  • bitor(gte(t-prev_selected_t\,10) is 1 when difference between "passed" timestamps is grater of equal 10 seconds.
    When expression is evaluated to 1, the frame is "selected" and passed to the output.
  • bitor with isnan(prev_selected_t) passes the first frame, where prev_selected_t is NaN (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 the select 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


Output frames after executing the above command:

enter image description here enter image description here enter image description here enter image description here enter image description here
enter image description here enter image description here enter image description here enter image description here enter image description here

As you can see, the selected frames are exactly every 10 seconds.

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

  • bitor(gte(t-prev_selected_t\,10) is 1 when difference between "passed" timestamps is grater of equal 10 seconds.
    When expression is evaluated to 1, the frame is "selected" and passed to the output.
  • bitor with isnan(prev_selected_t) passes the first frame, where prev_selected_t is NaN (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 the select 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

Output frames after executing the above command:

enter image description here enter image description here enter image description here enter image description here enter image description here
enter image description here enter image description here enter image description here enter image description here enter image description here

As you can see, the selected frames are exactly every 10 seconds.

Source Link
Rotem
  • 2.6k
  • 3
  • 10
  • 12

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


  • bitor(gte(t-prev_selected_t\,10) is 1 when difference between "passed" timestamps is grater of equal 10 seconds.
    When expression is evaluated to 1, the frame is "selected" and passed to the output.
  • bitor with isnan(prev_selected_t) passes the first frame, where prev_selected_t is NaN (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 the select 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


Output frames after executing the above command:

enter image description here enter image description here enter image description here enter image description here enter image description here
enter image description here enter image description here enter image description here enter image description here enter image description here

As you can see, the selected frames are exactly every 10 seconds.