Extracting frames from video file with ffmpeg

Here is a bit of code to extract individual frames from a video:

The code expects that ffmpeg is installed and in your PATH.

the inputs to the function:
filename = video file name
saved_directory is a path to save the files.
frame_list is a list of dictionaries where each dictionary contains ‘frame_number’ and ‘filename’.
frame_number is the index of the frame to extract.
filename is the name of the image after its been extracted
example of frame list:
first_item = {‘frame_number’:10, ‘filename’:‘frame_10.jpg’}
second_item = {‘frame_number’:20, 'filename:‘frame_20.jpg’}
frame_list = [first_item, second_item]

import os, sys, glob, shutil
import subprocess
import binascii

def extract_frame_list(filename, frame_list, saved_directory="saved"):
    frame_list = sorted(frame_list, key=lambda x: x['frame_number'])
    if not os.path.exists(saved_directory):
        os.makedirs(saved_directory)
    frames_used = []
    frames_used.append(frame_list[0]['frame_number'])
    portion = "select=\'eq(n\,{})".format(frame_list[0]['frame_number'])
    for instance in frame_list[1:]:
        while instance['frame_number'] in frames_used:
            instance['frame_number'] += 1
        frame_index = int(instance['frame_number'])
        portion += '+eq(n\,{})'.format(frame_index)
        frames_used.append(frame_index)
    portion += "\'"
    print("portion = ", portion)
    random_string = binascii.b2a_hex(os.urandom(5)).decode()
    command_list =  ["ffmpeg", "-i", filename, "-qscale:v", "1", "-vf", portion, "-vsync", "0", "{}/{}_frames%d.jpg".format(saved_directory, random_string)]
    print(command_list)
    subprocess.call(command_list)
    for i in range(1, len(frame_list)+1):
        os.rename("{}/{}_frames{}.jpg".format(saved_directory, random_string,i), os.path.join(saved_directory, frame_list[i-1]['filename']))
    return len(frame_list)
6 Likes

made some fixes to the above code.

See also ffmpy.
Also, I find it useful to use ThreadPoolExecutor from concurrent.futures to leverage multi-cores.