Skip to content

Instantly share code, notes, and snippets.

@aleek
Created August 18, 2021 07:45
Show Gist options
  • Select an option

  • Save aleek/d671b44b245691a440ef443f67050a8e to your computer and use it in GitHub Desktop.

Select an option

Save aleek/d671b44b245691a440ef443f67050a8e to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
#
# Shows GOP structure of video file. Useful for checking suitability for HLS and DASH packaging.
# Example:
#
# $ iframe-probe.py myvideo.mp4
# GOP: IPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP 60 CLOSED
# GOP: IPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP 60 CLOSED
# GOP: IPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP 60 CLOSED
# GOP: IPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP 60 CLOSED
# GOP: IPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP 60 CLOSED
# GOP: IPPPPPPPPPPPPPPPPP 18 CLOSED
#
# Key:
# I: IDR Frame
# i: i frame
# P: p frame
# B: b frame
#
# Usage for multiple video streams:
# ~/iframe-probe.py -a "-select_streams v:0" <file>
from __future__ import print_function
import json
import subprocess
import argparse
class BFrame(object):
def __repr__(self, *args, **kwargs):
return "B"
def __str__(self, *args, **kwargs):
return repr(self)
class PFrame(object):
def __repr__(self, *args, **kwargs):
return "P"
def __str__(self, *args, **kwargs):
return repr(self)
class IFrame(object):
def __init__(self):
self.key_frame = False
def __repr__(self, *args, **kwargs):
if self.key_frame:
return "I"
else:
return "i"
def __str__(self, *args, **kwargs):
return repr(self)
class GOP(object):
def __init__(self):
self.closed = False
self.frames = []
def add_frame(self, frame):
self.frames.append(frame)
if isinstance(frame, IFrame) and frame.key_frame:
self.closed = True
def __repr__(self, *args, **kwargs):
frames_repr = ''
for frame in self.frames:
frames_repr += str(frame)
gtype = 'CLOSED' if self.closed else 'OPEN'
return 'GOP: {frames} {count} {gtype}'.format(frames=frames_repr,
count=len(self.frames),
gtype=gtype)
parser = argparse.ArgumentParser(description='Dump GOP structure of video file')
parser.add_argument('filename', help='video file to parse')
parser.add_argument('-e', '--ffprobe-exec', dest='ffprobe_exec',
help='ffprobe executable. (default: %(default)s)',
default='ffprobe')
parser.add_argument('-a', '--extra-args', dest='ffprobe_extra_args',
help='extra ffprobe arguments. (default: %(default)s)',
default='')
args = parser.parse_args()
command = '"{ffexec}" -show_frames -print_format json {extra_args} "{filename}"'\
.format(ffexec=args.ffprobe_exec, filename=args.filename, extra_args=args.ffprobe_extra_args)
response_json = subprocess.check_output(command, shell=True, stderr=None)
frames = json.loads(response_json)["frames"]
gop_count = 0
gops = []
gop = GOP()
gops.append(gop)
for jframe in frames:
if jframe["media_type"] == "video":
frame = None
if jframe["pict_type"] == 'I':
if len(gop.frames):
# GOP open and new iframe. Time to close GOP
gop = GOP()
gops.append(gop)
frame = IFrame()
if jframe["key_frame"] == 1:
frame.key_frame = True
elif jframe["pict_type"] == 'P':
frame = PFrame()
elif jframe["pict_type"] == 'B':
frame = BFrame()
frame.json = jframe
gop.add_frame(frame)
for gop in gops:
print(gop)
# counter = 0
#
# last_frame_number = None
#
#
# for gop in gops:
# for frame in gop.frames:
# current_frame_number = int(frame.json[u'coded_picture_number'])
# print (current_frame_number)
#
#
# if last_frame_number is not None:
# difference = current_frame_number - last_frame_number
# if difference > 1:
# print("Difference is: %s" % difference)
#
# counter += 1
# if counter > 1000:
# break
#
# last_frame_number = int(frame.json[u'coded_picture_number'])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment