ffmpeg settings for converting still images to video for archival

If you want highest quality and minimal file size, you should use a compression-efficient codec. However, you first have to think about whether you want to do a (mathematically) lossless, visually lossless, or lossy encode:

  • Lossless encodes will of course result in higher file sizes, but they offer the benefit of preserving the original data. You can then extract individual frames from the video without any quality loss. Here, codecs such as HuffYUV or FFV1 could be used. These are often used for archival purposes, where the original material needs to be preserved, and generation loss is to be avoided. libx264 (H.264), libx265 (HEVC) and libvpx-vp9 can also be used in lossless mode:

    ffmpeg -i <input> -c:v huffyuv output.avi
    ffmpeg -i <input> -c:v ffv1 output.avi
    ffmpeg -i <input> -c:v libx264 -crf 0 output.mp4
    ffmpeg -i <input> -c:v libx265 -x265-params lossless=1 output.mp4
    ffmpeg -i <input> -c:v libvpx-vp9 -lossless 1 output.webm
    
  • Visually lossless encodes throw away some data but preserve quality in such a way that humans are likely not to notice any difference between the original and the encoded video. So-called "intermediate" codecs such as ProRes (see here) are often used for this purpose. You can also do visually lossless encodes with libx265 or libx264 by specifying a low enough CRF value (explanation of CRF here), e.g. between 10 and 18 for x264.

    ffmpeg -i <input> -c:v prores -profile:v 3 output.mov
    ffmpeg -i <input> -c:v libx264 -crf 10 -preset ultraslow output.mp4
    ...
    
  • Lossy codecs, there are plenty. If you can sacrifice quality, you can reduce the file size drastically. VP9 and HEVC are more efficient than H.264 in terms of how much space they require, but they may take longer to encode. Forget about Theora and VP8. With VP9, HEVC and H.264 (at least with the encoders available in ffmpeg) you can set a CRF parameter that gives you the quality you want. You need to visually check your output to make sure that the amount of loss is not too severe for your purpose. For libx264, CRF values between 18 and 23 look "good".

    ffmpeg -i <input> -c:v libx264 -crf 23 -preset ultraslow output.mp4
    ffmpeg -i <input> -c:v libvpx-vp9 -crf 10 -b:v 0 output.webm
    ...
    

Generally, if you are aiming for archiving content, you should not just specify a target bitrate. Instead, you want to use a constant quality mode, where the encoder is free to use as many bits as it needs to retain the quality of the image (within certain bounds). Especially with the H.264 or HEVC encoders libx264 and libx265, using -b:v for a single-pass encode is not recommended, as it might lead to huge quality variations over time. (I wrote an article on different rate control modes here.) To summarize, if you're archiving, simply go for a constant CRF value.

It's also very important that you do not resize the video, since that either introduces blurring (when upscaling), or throws away data (when downscaling). Simply leave out the -s:v option unless your images are much too big for video.

Finally, when performing visually lossless or lossy encodes, you can trade off speed against compression efficiency. In other words, if you wait longer, you can make the file size smaller. Here, the preset options come into play: If you choose a preset like ultraslow, the encoding process is going to take a long time, but the resulting file – assuming a given CRF – will be smaller, even though it has the same quality. VP9 has different options to control the speed, see here.

One more thing: With libx264, you can use the -tune stillimage option to optimize the encode for images. Also, choosing the lowest frame rate needed will help save file size, of course.

Some documentation:

  • Encoding guide for FFV1
  • Encoding guide for H.264
  • Encoding guide for H.265
  • Encoding guide for VP9