I need to convert a set of still images (static cameras pointed at a road) to a video.

I have considered video codecs such as Theora, H.264, VP8, VP9, HEVC, Snow.

The video should have a minimum size with the maximum image quality. Now, from all available command-line arguments, I'm using framerate (fps), b:v (bitrate) and s (width*height). Also, for H.264 and HEVC there are -crf and -preset.

What other command-line arguments can be useful to achieve what I'm after? In ffmpeg dozens of command-line arguments and parsing each can take a long time.

  • This question is a little bit too broad to be answerable. Are your images frames of a video that should be merged, or is it more of a slideshow? What is the end use here – streaming or storage/archival? Do you care about compression artifacts or should the result be (almost) visually lossless? Do you care about (legacy) device or browser compatibility? What have you tried and where did you find it lacking? – slhck May 23 '17 at 13:49
  • Images - photos from static street cameras (the cameras are aimed at the road) End use - archival. If necessary, I will extract the photos back. Requirements for quality - the ability to understand the number of the car. I achieved acceptable results using the arguments described in the question, but there is a hope that it is possible to improve the quality/size ratio by applying unknown arguments to me. Compatibility doesn`t matter – Maxim Fedorov May 23 '17 at 13:56
  • I added some more stuff to the answer, hope that helps. – slhck May 23 '17 at 14:26

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:

  • from animated gif, with hevc -crf 10, I still got good quality and 60% of original gif size. This is very good condensed specific info, thx vm! – Aquarius Power Feb 8 '19 at 22:38
  • Very complete answer, thanks. For a video with a still image and a music, do you know why I get such an enormous difference in file size between the lossless HEVC (~ 70 MB) and FFV1 (~ 10 GB) video codecs? The issued commands: ffmpeg -loop 1 -i input.jpg -i input.wav -c:v hevc -crf 0 -c:a flac -shortest output.mkv for lossless HEVC and ffmpeg -loop 1 -i input.jpg -i input.wav -c:v ffv1 -c:a flac -shortest output.mkv for FFV1. It looks like either the parameters you provided for lossless HEVC are incorrect (in the sense not really lossless) or FFV1 is a terrible codec. – Maggyero Mar 1 '20 at 4:05
  • 1
    @Maggyero The lossless setting for libx265 is correct. The difference is most likely caused by the fact that HEVC can use inter-frame coding to simply predict the following frames from the first one, whereas FFV1 will code each frame separately. With a still image, that means a lot of unnecessary duplication in the case of FFV1. It does not mean that FFV1 is a terrible codec — it just has a different use case (for archival purposes, storage of individual frames is much preferred over predicted frames). – slhck Mar 1 '20 at 13:03
  • I see thanks. Another user says that -crf 0 is not really lossless and that you should use -x265-params lossless=1 instead. The file size then increases by ~ 10 MB (so it is ~ 80 MB in total). What is your opinion on this? It is a shame that we cannot use FFV1 in inter-frame mode, or maybe there is an option? And does HEVC have an option for intra-frame mode only? – Maggyero Mar 1 '20 at 15:52
  • @Maggyero The question/answer mostly has all the info in the comments. True lossless means bypassing rate-control completely, whereas CRF 0 works on a later stage in the encoding process. Visually it will be the same result, but without --lossless it will probably not be bit-exact. As for I-frame only H.265, see keyint=1 mentioned in the other answer. – slhck Mar 2 '20 at 6:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.