Using ffprobe to evaluate keyframes

Note: It appears this needs to be updated as ffprobe no longer outputs pict_type

ffprobe is quite a good little tool for evaluating keyframes in a video and here is a simple statement that can show you an easy way to view the GOP structure of a video:

ffprobe -show_frames out_gop12.ts |grep ‘media_type=video|pict_type|coded_picture_number’|less

Now on doing this I am seeing that ffmpeg and x264 aren’t necessarily following the GOP structure that I have set which has a max keyframe distance of 12.

Sample output:

media_type=video

pict_type=I

coded_picture_number=0

media_type=video

pict_type=P

coded_picture_number=1

media_type=video

pict_type=I

coded_picture_number=2

media_type=video

pict_type=P

coded_picture_number=3

media_type=video

pict_type=P

coded_picture_number=4

media_type=video

pict_type=P

coded_picture_number=5

media_type=video

pict_type=B

coded_picture_number=7

media_type=video

pict_type=P

coded_picture_number=6

media_type=video

pict_type=B

coded_picture_number=10

media_type=video

pict_type=B

coded_picture_number=9

media_type=video

pict_type=B

coded_picture_number=11

media_type=video

pict_type=P

coded_picture_number=8

media_type=video

pict_type=B

coded_picture_number=14

Here is a good post with some more info on the topic
I have also created a little Python script that will process the output to show you when keyframes occur:

#!/usr/bin/python

importos

import re

importsys

import subprocess

#infile = sys.argv[1]

infile= “/tmp/ffmpeg_main_profile/out_gop12.ts

lines_past_type = 20

line_count = 0

print_line = False

gop = 12

frame = 0

found_iframe = False

cmd = “ffprobe -show_frames %s” % infile

# -print_format json

process = subprocess.Popen(cmd,shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE

,cwd=target_dir)

whileTrue:

line = process.stdout.readline()

if line != ”:

#the real code does filtering here

#print line.rstrip()

if (line.rstrip()==“media_type=video”):

print_line = True

if (print_line and (line_count < lines_past_type)):

#print line.rstrip()

if re.match(r‘pict_type=I.*’,line):

found_iframe = True

#print line.rstrip()

match = re.match(r‘coded_picture_number=(.*)’,line)

if (match):

frame =  match.group(1)

if (found_iframe):

print “I Frame: %s” % frame

div12 = float(frame) / 12

found_iframe = False

line_count+=1

if (line_count >= lines_past_type):

print_line = False

line_count = 0

else:

break