Extracting the index of key frames from a video using ffmpeg

Solution 1:

Like @dstob mentioned, you can use ffprobe to get the I-frames and their associated information. ffprobe comes with some of the static builds on the download page and can be built from source as well.

This is assuming you're on Linux/Unix:

Extract frames and frame types

ffprobe -select_streams v -show_frames \
-show_entries frame=pict_type \
-of csv bbb480.avi \
| grep -n I | cut -d ':' -f 1

The grep command filters lines with I in them, and counts their index (using the -n option). The cut command selects the first column of the output only (the index). Note that this index is 1-based, not 0-based.

Rename output files based on index

You can actually pipe these indices to a list:

ffprobe -select_streams v -show_frames \
-show_entries frame=pict_type \
-of csv bbb480.avi \
| grep -n I | cut -d ':' -f 1 > frame_indices.txt

Then make a list of all the thumbnails too:

ls -1 thumbnails*.jpeg > thumbnails.txt

Then paste those two together:

paste thumbnails.txt frame_indices.txt > combined.txt

The list now contains the name of the thumbnail and the index. Perform a rename based on that:

while read -r thumbnail index; do
  newIndex=$(echo $index - 1 | bc) # subtract 1 from the index
  mv -- "$thumbnail" "thumbnail-$newIndex.jpeg"  # rename file
done < combined.txt

The above will rename thumbnail-01.jpeg to thumbnail-0.jpeg. Note that there is no zero-padding on the output index. If you want to zero-pad it to, say, 5 digits, use printf:

newIndex=$(printf '%05d' $(echo $index - 1 | bc))

On Windows, you'd do the exact same with ffprobe but parse the output differently. No idea how to perform the renaming there though.

Solution 2:

If you wish to use FFMPEG as originally stated, You can list all or partial listing as well as create jpg with the following:

ffmpeg.exe \
  -i "C:\Users\UserName\Desktop\jpegs and list\VideoName.mp4" \
  -t 15 \
  -vf select="eq(pict_type\,PICT_TYPE_I)" \
  -vsync 2 \
  -s 160x90 \
  -f image2 thumbnails-%02d.jpeg \
  -loglevel debug 2>&1| for /f "tokens=4,8,9 delims=. " %d in ('findstr "pict_type:I"') do echo %d %e.%f>>"keyframe_list.txt"

Remove -t 15 for no time limit or change to suit. Remove -s 160x90 -f image2 thumbnail-%02d.jpeg or change to suit for thumbnail removal.