3

As far as I understand ffmpeg-python is main package in Python to operate ffmpeg directly.

Now I want to take a video and save it's frames as separate files at some fps.

There are plenty of command line ways to do it, e.g. ffmpeg -i video.mp4 -vf fps=1 img/output%06d.png described here

But I want to do it in Python. Also there are solutions [1] [2] that use Python's subprocess to call ffmpeg CLI, but it looks dirty for me.

Is there any way to to make it using ffmpeg-python?

sgt pepper
  • 504
  • 7
  • 15
  • looks like [This](https://stackoverflow.com/questions/33311153/python-extracting-and-saving-video-frames) is what you are looking for. – Goldwave Sep 30 '20 at 18:12

4 Answers4

5

The following works for me:

ffmpeg
.input(url)
.filter('fps', fps='1/60')
.output('thumbs/test-%d.jpg', 
        start_number=0)
.overwrite_output()
.run(quiet=True)
norus
  • 122
  • 8
2

I'd suggest you try imageio module and use the following code as a starting point:

import imageio

reader = imageio.get_reader('imageio:cockatoo.mp4')

for frame_number, im in enumerate(reader):
    # im is numpy array
    if frame_number % 10 == 0:
        imageio.imwrite(f'frame_{frame_number}.jpg', im)
Senyai
  • 1,395
  • 1
  • 17
  • 26
1

You can also use openCV for that.

Reference code:

import cv2

video_capture = cv2.VideoCapture("your_video_path")
video_capture.set(cv2.CAP_PROP_FPS, <your_desired_fps_here>)

saved_frame_name = 0

while video_capture.isOpened():
    frame_is_read, frame = video_capture.read()

    if frame_is_read:
        cv2.imwrite(f"frame{str(saved_frame_name)}.jpg", frame)
        saved_frame_name += 1

    else:
        print("Could not read the frame.")
AreUMinee
  • 81
  • 7
  • method `.set` returns `False`. That means FPS couldn't be set directly to VideoCapture. I just skipped excess frames with `continue` – sgt pepper Oct 10 '20 at 20:48
0

@norus solution is actually good, but for me it was missing the ss and r parameters in the input. I used a local file instead of a url.

This is my solution:

  ffmpeg.input(<path/to/file>, ss = 0, r = 1)\
        .filter('fps', fps='1/60')\
        .output('thumbs/test-%d.jpg', start_number=0)\
        .overwrite_output()]
        .run(quiet=True)

ss is the starting second in the above code starts on 0 r is the ration, because the filter fps is set to 1/60 an r of 1 will return 1 frame per second, of 2 1 frame every 2 seconds, 0.5 a frame every half second....

Jorge
  • 2,181
  • 1
  • 19
  • 30