I am using ffmpeg-python 0.2.0 with Python 3.10.0. Displaying videos in VLC 3.0.17.4.
I am making an animation from a set of images. Each image is displayed for different amount of time.
I have the basics in place with inputting images and concatenating streams, but I can't figure out how to correctly set frame duration.
Consider the following example:
stream1 = ffmpeg.input(image1_file)
stream2 = ffmpeg.input(image2_file)
combined_streams = ffmpeg.concat(stream1, stream2)
output_stream = ffmpeg.output(combined_streams, output_file)
ffmpeg.run(output_stream)
With this I get a video with duration of a split second that barely shows an image before ending. Which is to be expected with two individual frames.
For this example, my goal is to have a video of 5 seconds total duration, showing the image in stream1 for 2 seconds and the image in stream2 for 3 seconds.
Attempt 1: Setting t
for inputs
stream1 = ffmpeg.input(image1_file, t=2)
stream2 = ffmpeg.input(image2_file, t=3)
combined_streams = ffmpeg.concat(stream1, stream2)
output_stream = ffmpeg.output(combined_streams, output_file)
ffmpeg.run(output_stream)
With this, I get a video with the duration of a split second and no image displayed.
Attempt 2: Setting frames
for inputs
stream1 = ffmpeg.input(image1_file, frames=48)
stream2 = ffmpeg.input(image2_file, frames=72)
combined_streams = ffmpeg.concat(stream1, stream2)
output_stream = ffmpeg.output(combined_streams, output_file, r=24)
ffmpeg.run(output_stream)
In this case, I get the following error from ffmpeg:
Option frames (set the number of frames to output) cannot be applied to input url ########## -- you are trying to apply an input option to an output file or vice versa. Move this option before the file it belongs to.
I can't tell if this is a bug in ffmpeg-python or if I did it wrong.
Attempt 3: Setting framerate
for inputs
stream1 = ffmpeg.input(image1_file, framerate=1/2)
stream2 = ffmpeg.input(image2_file, framerate=1/3)
combined_streams = ffmpeg.concat(stream1, stream2)
output_stream = ffmpeg.output(combined_streams, output_file)
ffmpeg.run(output_stream)
With this, I get a video with the duration of a split second and no image displayed. However, when I set both framerate values to 1/2, I get an animation of 4 seconds duration that displays the first image for two seconds and the second image for two seconds. This is the closest I got to a functional solution, but it is not quite there.
I am aware that multiple images can be globbed by input, but that would apply the same duration setting to all images, and my images each have different durations, so I am looking for a different solution.
Any ideas for how to get ffmpeg-python to do the thing is much appreciated.
A simple solution is adding loop=1
and framerate=24
to the "first example":
import ffmpeg
image1_file = 'image1_file.png'
image2_file = 'image2_file.png'
output_file = 'output_file.mp4'
stream1 = ffmpeg.input(image1_file, framerate=24, t=2, loop=1)
stream2 = ffmpeg.input(image2_file, framerate=24, t=3, loop=1)
combined_streams = ffmpeg.concat(stream1, stream2)
output_stream = ffmpeg.output(combined_streams, output_file)
ffmpeg.run(output_stream)
loop=1
- Makes the input image repeating in a loop (the repeated duration is set by t=2
and t=3
).framerate=24
- Images don't have framerate (opposed to video), so they are getting the default framerate (25fps) if framerate is not specified.framerate=24
sets the input framerate to 24fps (and prevents framerate conversion).