38

How can I check keyframe interval of a video file?

all I can see in ffmpeg output is:

  Metadata:
    metadatacreator : Yet Another Metadata Injector for FLV - Version 1.8
    hasKeyframes    : true
    hasVideo        : true
    hasAudio        : true
    hasMetadata     : true
    canSeekToEnd    : true
    datasize        : 256600272
    videosize       : 210054362
    audiosize       : 45214634
    lasttimestamp   : 5347
    lastkeyframetimestamp: 5347
    lastkeyframelocation: 256649267
  Duration: 01:29:07.24, start: 0.040000, bitrate: 383 kb/s
    Stream #0:0: Video: h264 (High), yuv420p, 720x304 [SAR 1:1 DAR 45:19], 312 kb/s, 25 tbr, 1k tbn, 50 tbc
    Stream #0:1: Audio: mp3, 44100 Hz, mono, s16p, 64 kb/s
rabotalius
  • 1,430
  • 5
  • 18
  • 27

3 Answers3

87

You can display the timestamp for each frame with ffprobe with awk to only output key frame info. Works in Linux and macOS.

ffprobe -loglevel error -select_streams v:0 -show_entries packet=pts_time,flags -of csv=print_section=0 input.mp4 | awk -F',' '/K/ {print $1}'

Or a slower method that works on any OS and does not require awk or similar additional processing tools:

ffprobe -loglevel error -skip_frame nokey -select_streams v:0 -show_entries frame=pkt_pts_time -of csv=print_section=0 input.mp4

Results:

0.000000
2.502000
3.795000
6.131000
10.344000
12.554000
16.266000
17.559000
...

See the ffprobe documentation for more info.

llogan
  • 121,796
  • 28
  • 232
  • 243
  • per my understand, select first video stream command should be -select_streams v:0, but not 0:v:0. am I wrong? – lucky1928 Sep 16 '15 at 16:14
  • @lucky1928 You're correct. I fixed the typo (`0:v:0` would be the syntax in `ffmpeg`). – llogan Sep 16 '15 at 17:42
  • Is the keyframe interval included in this output, somewhere? I can't see it. – voices Apr 28 '17 at 00:19
  • It isn't directly, but you can calculate the keyframe interval from this output. Count the frames from one keyframe (key_frame=1) to the next, this is the interval in frames. If you want the keyframe interval in seconds, multiply it by the framerate. Note that it may not be constant and can be different for each keyframe depending on the encoding parameters. A quick and dirty way to determine the interval for the first two keyframes: `ffprobe -select_streams v:0 -show_frames INPUT.MP4 2>/dev/null | awk -vf=0 '/key_frame=1/ {f=1; ++d} d!=2 && /key_frame/ {print} f && d==2 {exit}' | wc -l` – maetthu Oct 11 '17 at 15:29
  • 1
    Does it bother anyone else that the `-skip_frame` flag isn't mentioned in the documentation anywhere? How are we supposed to know about it if it's not in the documentation? – Multihunter May 31 '18 at 03:49
  • 1
    @Multihunter It is, but it is buried in ffmpeg-all. See `man ffmpeg-all` or the online [ffmpeg-all](https://ffmpeg.org/ffmpeg-all.html) documentation. Alternatively, refer to `ffmpeg -h full`. – llogan May 31 '18 at 17:24
  • 1
    This command will be very slow as it is decoding every frame. You can use `-show_entries packet=pts,flags` for a much faster result and filter for `flags=K` – tmm1 Jul 09 '19 at 18:25
  • @tmm1 Thanks, added. – llogan Aug 22 '19 at 20:21
  • 3
    The Windows/cross-platform command provided did NOT work properly, had to change `frame=pkt_pts_time` to `frame=pts_time`, as nothing was showing up. The field may have changed the name since the original post? – Francois Bertrand Jan 25 '22 at 19:38
3

The following command will give you the offsets of all key Frames in the Video

ffprobe -show_frames -select_streams v:0 \
        -print_format csv Video.mov 2> /dev/null |
stdbuf -oL cut -d ',' -f4 |
grep -n 1 |
stdbuf -oL cut -d ':' -f1

Note that the command might respond a little late. Have patience :-)

The ffprobe command gives you the frame level details in CSV format. Rest is a smart combination of cut and grep commands.

cut -d ',' -f4

filters the fourth column - this refers to the 'key_frame' flag.

grep -n 1

filters the key-frames only, and shows their line numbers in the CSV feed.

The

stdbuf -oL

with the cut command manipulates the buffer of the cut command.

0

Here's a command to get the keyframe interval of an input file/stream:

probtime=10 && ffprobe -hide_banner -of compact=p=0:nk=1 -select_streams v:0 -count_frames -show_entries stream=nb_read_frames -skip_frame nokey -v 0 -read_intervals "%+$probtime" -i INPUT.mp4 | awk -v probtime="$probtime" '{print probtime/$1}'

probtime - in seconds

result - keyframe interval (i.e. a keyframe is set every X seconds)

atyachin
  • 1,103
  • 1
  • 12
  • 14