Producing GIFs with variable frame times using FFmpeg


guides

Your GIF animation does not have to have a constant frame delay!

Whether it is to reduce file size or to comply with a limit (such as the 12.5/100 million pixel limit imposed on GIF files uploaded to Wikipedia), it is sometimes desirable to vary the frame time/duration within a single animation.

This guide may also help with producing animations or videos in formats other than GIF, such as MP4 videos.

Procedure

Setup

FFmpeg is a command-line tool which runs on Windows, Mac and Linux. You should download and install it before starting.

This guide requires you to have exported the individual frames from your animation, in an acceptable image format (such as JPEG or PNG). If you have an existing video or animation which you would like to modify, you should first extract the frames from the original animation.

Copy all the image files corresponding to the frames of your animation to some folder.

Produce a directory listing. By this I mean that you should produce a text file containing the names of each of your frames, in the order you would like them to be displayed. In my experience it is usually easiest to use a command like dir on Windows (or ls on Linux), piping the output to a file and then manually touching up the listing. You can use the ‘find and replace’ operation in your favourite text editor to produce the desired output, which should be something like the following:

/path/to/frame01.png
/path/to/frame02.png
/path/to/frame03.png

Producing an input file for the concat demuxer

In a similar way as above, modify your directory listing such that each line is of the form file '/path/to/framexx.png', replacing /path/to/framexx.png with the path to the given frame.

You should also insert a new line with the content duration x below every line of your directory listing, replacing x with the desired frame time (in seconds) of the frame specified on the line immediately above. These duration values do not have to be all the same; if you are following this guide, you probably want to set varying frame durations in this step.

Finally, you should duplicate the line specifying the location of the last frame of your animation and move it to the bottom of the file.

In the case of the example above, a suitable input file might look like this:

file '/path/to/frame01.png'
duration 1
file '/path/to/frame02.png'
duration 0.5
file '/path/to/frame03.png'
duration 0.5
file '/path/to/frame03.png'

This input file corresponds to an animation with 3 frames, the first of which is displayed for 1 second, and the others for 0.5 seconds each.

FFmpeg command

The command you should try first is ffmpeg -f concat -i input.txt out.gif, where input.txt is the path to the input file you created earlier, and output.gif is where you would like your animation to be saved.

If running this command returns the error Unsafe file name, you should try adding -safe 0 immediately after -f concat (separating these with spaces).

You should examine the GIF animation which was produced. If you notice any artefacts, such as strange colours, you should try modifying the command by adding -vf split[x][z];[z]palettegen[y];[x][y]paletteuse immediately before out.gif (separating these with spaces).

This was enough for me to produce a satisfactory animation. If you face any difficulty, you should check the links below before looking for another solution.

Sources

Alternative – using Ezgif for small GIF animations

Ezgif is a reliable website, and you should use it instead of the procedure described above if you know your animation will be small. How small? I don’t know.

Try loading your animation in one of the supported formats and click the ‘Frames’ tab to edit the frame delay of each individual frame, making sure to double check the units used to display the frame time at the bottom of the page.

If, after doing this and attempting to save the modified animation, the website produces an error (even after repeated attempts), you’re out of luck, probably because your animation is too large.