I'm trying to figure out how to specify a specific list of images to be converted into a video. I do know that we can do something like:
ffmpeg -i image_04%d.png
That would pick all the images from the folder that match the sequence. However in my case the image files are no necessarily in the order as its name implies. The reason is that the order is kept on a database and the file names are essentially the database row id.
How could I specify the correct input sequence? I'm essentially calling ffmpeg from code and not from the command line. So any changes ideas to the code are also welcomed.
Thanks!
Well, the solution was to patch the image2 class to support a list with the numbers to pick from. Than I provided to ffmpeg the input file pattern along with an array of numbers with the specified order to read the input. This worked perfectly.
Your application could create symbolic links starting at 0001 that respect the order of the original frames, then pass that sequence into ffmpeg. Once the video is complete delete the symlinks and you're done.
Here is a script along Kevin's idea which works for me. You might want to replace the file name pattern (shot*.png) and the output filename movie.mp4. All frame_ ... files are removed by the script when finished.
Let's say we have a list of file names in the correct order like this:
and we want to create an animated GIF out of these with a certain frame rate e.g.
FPS=30
. This can be done like in the other answers by creating symbolic links e.g. named001.png
to035.png
and then use:Another way is to make use of
ffmpeg
's concat-feature. Unfortunately this is a tad easier said than done, because the the feature expects video streams, meaning the images need to be looped as long as needed.The command to concatenate three images with 500ms inbetween is this:
Tested with
ffmpeg version 3.0.1-3
.Explanation:
The concat demuxer expects a file with a list of relative file names prepended by the keyword
file
. In order to not clutter the current working directory (or maybe we don't have writing permissions), we use process substition<( ... )
. But this creates a file in/dev/fd/
and if relative file names are used, then this results in error messages like this:That's why the absolute path is given. But absolute paths are not allowed by default, resulting in:
In order to solve that
-safe 0
is used.When trying to specify an input frame rate with
-r
errors like this occur:
The resulting GIF works like expected anyway. Using the
duration
option ofconcat
explicitly solves these warnings/errors.Note the comment for
-r
My take on this is that the above warnings from concat, which notify you that it couldn't find a playing length for images, don't result in bad behavior because the framerate is forced after the concat warnings with
-r
, which works, but may not be the intended way. I would only use this when manually writing ffmpeg commands, but not in scripts.Putting together a small script to work with the list of file names specified in the beginning:
The uncommented line in the code above will give a H264-encoded mkv.
Heterogenous image types
If your image list contains images of different types, e.g. by replacing
hjruIcoN0aTn.png
withhjruIcoN0aTn.jpg
inframes
, then this usage ofconcat
won't work. Images in other formats than the first specified will be dropped and throw errors like:In this case you will have to use the concat filter instead of the simple demuxer. The command with the three files from above will then have to be changed to this:
Explanation:
Each options used is explained really well here. Note that the
-framerate
option is specific to the image importer and is at least technically different from-r
, practically in this case they produce the same results.The
-thread_queue_size
seems to be necessary, because we extend one image for a quite long 500ms, resulting in these error messages:The description of the option gave me reason to think that the overly large delay is at fault:
Putting all this in a script again:
For some very weird reason the above command doesn't work as is !!!. In my case it dropped 33 of the 35 frames specified without a warning or error message:
The reason that this is weird is, that it works perfectly like intended for double the delay, i.e. each image being shown for 2 frames, i.e. changing
1/$FPS
to2/$FPS
:This fact suggests an easy workaround: encode with double the framerate and display each image for 2 frames. But that is wasteful and not favorable anyway.