Search code examples
animationffmpegimagemagickapng

FFMPEG control delay and looping for generating APNG


I have a (random selection) of JPG images that I want to use to make into an APNG animation using ffmpeg (to test the process). They are all the same dimensions (256x256). But I cannot seem to get the correct syntax to control the frame delay and loop control (to loop forever). Is it possible to set these parameters using ffmpeg when creating an APNG from a sequence of images? If so, can someone provide the proper syntax and/or show an example command? I have searched the ffmpeg documentation and cannot seem to find relevant syntax.

I can do the following, but it will not accept -delay nor -loop. I use Imagemagick to pipe in the images.

This works, but does not loop, and runs very fast.

magick lena.jpg mandril3.jpg monet2.jpg zelda1.jpg PNG:- | ffmpeg -i - x.apng

This gives errors about delay and/or loop:

magick lena.jpg mandril3.jpg monet2.jpg zelda1.jpg PNG:- | ffmpeg -i - -delay 1000 -loop -1 x.apng

I am also curious to know if it is possible to specify a sequence of images directly in ffmpeg as input without using ImageMagick.

Sorry, I am a relative novice with ffmpeg. I am using ffmpeg 4.2.1.


Solution

  • Looping

    You can set looping with the -plays output option. 0 is infinite, 1 is no loop, 2 will play twice, etc.

    -plays is an option specific (aka a private option) for the APNG muxer. You can see private options for a specific muxer with ffmpeg -h muxer=apng. See What are all codecs and formats supported by FFmpeg? for more examples.

    Another private option for APNG is -final_delay to force delay after the last frame. Accepts a value in seconds.

    Providing images to ffmpeg

    Image demuxer

    The most common method is to use the image demuxer.

    It accepts a numbered sequence such as image_001.png, image_002.png, etc:

    ffmpeg -framerate 3 -i image_%03d.png -plays 0 output.apng
    

    Or a glob (at least on Linux & macOS):

    ffmpeg -framerate 1 -pattern_type glob -i "*.png" output.apng
    

    Set delay/timing with the -framerate input option as shown in the examples above. This is a private option of the image demuxer.

    Pipe

    You can pipe the images to ffmpeg like you do in your question. Can be useful in combination with other tools to provide the order you prefer.

    For example, using sort is helpful your image series uses natural/version numbering such as 1.png, 2.png, ..., 10.png, etc. Otherwise ffmpeg would order them as 1.png, 10.png, 2.png.

    cat $(find . -name '*.png' -print | sort -V) | ffmpeg -framerate 1 -i - -plays 1 output.apng
    

    Concat demuxer

    Or use the concat demuxer if you want to provide a list of files. Each image can have its own duration.

    1. Create input.txt containing:

      file 'lena.jpg'
      duration 1
      file 'mandril3.jpg'
      duration 0.5
      file 'monet2.jpg'
      duration 3
      file 'zelda1.jpg'
      duration 2
      

      Duration value is in seconds.

    2. Concatenate:

      ffmpeg -f concat -i input.txt -plays 0 output.apng
      

    If you omit duration, and want an even delay/timing between images you can use the -r input option. This example will play at 1 frame per second.

    ffmpeg -r 1 -f concat -i input.txt -plays 0 output.apng
    

    Also see FFmpeg Wiki: Concatenate.