7

I'm trying to select say 10 frames from a given video, possibly with highest variety and scenes. I would like to experiment with various selection scenarios, but the good thing is that the notion of I-frame inherently means scene changes! So I would like to get the I-frames. But maybe there are many I-frames, so probably I have to sample them.

How can I get the list of all I-frames's frame_number in a video in FFMpeg or Python? I would like to use the list to select only 10 of them and save them as PNG/JPEG.

Tina J
  • 579

5 Answers5

8

This seems like an X/Y problem, so I'll propose several different commands:

List of timestamps

If you want to output a list of timestamps for each keyframe:

ffprobe -v error -skip_frame nokey -show_entries frame=pkt_pts_time -select_streams v -of csv=p=0 input
0.000000
2.502000
3.795000
6.131000
10.344000
12.554000

Note the -skip_frame nokey.

select filter

Another method is to use the select filter with the scene option to output your thumbnails:

ffmpeg -i input -vf "select=gt'(scene,0.4)',scale=160:-1" -vsync vfr %04d.png
llogan
  • 63,280
4

This will output all the i frames as PNG images.

ffmpeg -i 2.flv -vf "select=eq(pict_type\,I)" -vsync vfr frame-%02d.png

Credit to this comment a similar superuser.com question. How to extract all key frames from a video clip?

Hope that helps. Cheers.

Ian

iangetz
  • 147
1

Getting insights from here, I was able to do it with ffprobe:

    def iframes():
        if not os.path.exists(iframe_path):
            os.mkdir(iframe_path)
        command = 'ffprobe -v error -show_entries frame=pict_type -of default=noprint_wrappers=1'.split()
        out = subprocess.check_output(command + [filename]).decode()
        f_types = out.replace('pict_type=','').split()
        frame_types = zip(range(len(f_types)), f_types)
        i_frames = [x[0] for x in frame_types if x[1]=='I']
        if i_frames:
            cap = cv2.VideoCapture(filename)
            for frame_no in i_frames:
                cap.set(cv2.CAP_PROP_POS_FRAMES, frame_no)
                ret, frame = cap.read()
                outname = iframe_path+'i_frame_'+str(frame_no)+'.jpg'
                cv2.imwrite(outname, frame)
            cap.release()
            print("I-Frame selection Done!!")
if __name__ == '__main__':
    iframes()     

Tina J
  • 579
0

For get frame type of all frames in video you can use the following python function. See original solution here.

def get_frames_metadata(file):
    command = '"{ffexec}" -show_frames -print_format json "{filename}"'.format(ffexec='ffprobe', filename=file)
    response_json = subprocess.check_output(command, shell=True, stdeone)
    frames = json.loads(response_json)["frames"]
    frames_metadata, frames_type, frames_type_bool = [], [], []
    for frame in frames:
        if frame["media_type"] == "video":
            video_frame = json.dumps(dict(frame), indent=4)
            frames_metadata.append(video_frame)
            frames_type.append(frame["pict_type"])
            if frame["pict_type"] == "I":
                frames_type_bool.append(True)
            else:
                frames_type_bool.append(False)
    print(frames_type)
    return frames_metadata, frames_type, frames_type_bool

Output result:

['I', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P', 'I', 'P']

Where I and P it is frame type.

josh
  • 3
0

Iframes don't necessarily mean scene changes, but scene changes and splice points should occur on iframes.

ffprobe -show_frames -skip_frame nokey -show_entries frame=pts_time,pkt_pos -select_streams v -of csv video.ts

Gives you a list of iframes and the pts, and packet position

    frame,72667.595200,376
    frame,72669.597200,229924
    frame,72671.599200,444620
    frame,72673.601200,668528
    frame,72675.603200,884540
    frame,72677.605200,1094724

.....

Or the easier way, iframes.

python3 -mpip install iframes

$ iframes video.ts

72667.5952
72669.5972
72671.5992
72673.6012
72675.6032
72677.6052

...

Fu Tzu
  • 1