FFmpeg: Make a video track from an image separately (x264)

In this article we will talk about how to convert .png, .jpg images to .mp4, .mkv videos. We will not create a slideshow and add an audio track to it. For now, we’ll just figure out how to make a video track from a single image. What options for this can be used and what is their speed and result.

Video track encoding from an image

Here are the parameters of the image that I will use. It is large both in filesize and proportions:

An image for experiments:

Source image: jpeg, yuvj444p, 1440x1902 (in amount of pixels it is bigger than 1080p), filesize = 1.7 M

yuv444p, yuvj444p (3 bytes per pixel, 12 bytes per 4 pixels)

This pixel format may not work in some applications, browsers, online video services (like youtube, facebook). For example, it is not playable in my Firefox 66.0.5.

Since our image is in yuvj444p pixel format ffmpeg without additional settings will encode it to yuvj444p pixel format of a video. This pixel format is not always supported by applications, but it is modern and provides better image quality.

Make a video track with duration of 10 seconds, 30 fps, h264 with slow preset (good compression and pretty fast encoding speed):

ffmpeg -framerate 1/10 -i image.jpg -c:v libx264 -preset slow -r 30 out.mp4 

Here is the result:

Results: yuvj444p, 854 kb/s, 30 fps, 10 sec of the video duration, 1.1M filesize and 20 seconds spent on the encoding process (-threads 6 by default) 

-framerate 1/10 is input framerate (Frames per second)

-r 30 is output framerate (Frames per second)

Video track duration <— use this to control duration in all the article examples

Without any ‘time’ or ‘loop’ option ffmpeg wants to encode only 1 frame of a video (convert .jpg image to 1 frame of .mp4 video). But -framerate 1/10 option stretches this process for 10 seconds. Keyframes will also be placed:

-framerate 1/10 <- this number figuratively means 'seconds'

yuv420p (6 bytes per 4 pixels), works everywhere (all media players, most browsers), less filesize

Another pixel format that works everywhere is yuv420p, it works perfectly in my Firefox 66.0.5:

ffmpeg -framerate 1/10 -i image.jpg -c:v libx264 -preset slow -r 30 -pix_fmt yuv420p out.mp4 
Results: yuv420p, 782 kb/s, 961K, 18 seconds of encoding (-threads 6 by default), playback hardware support (NVIDIA, VDPAU) on my GPU

Another way is to use ffmpeg’s video filter options, it is the same:

ffmpeg -framerate 1/10 -i image.jpg -c:v libx264 -preset slow -vf "fps=30,format=yuv420p" out.mp4  
Results: yuv420p, 782 kb/s, 961K, 20 sec of encoding (-threads 6 by default)

Speed up encoding process. Set fps to 1 and customize keyframes interval

It is possible to speed up encoding process. If a video must consists of one single image we can set output framerate (-r option) to 1. This speeds up the process, but also has a side effect (video steps in media players are broken). This problem can be solved by setting keyframe interval by ourselves.

In the following example we will get a video track in 2 seconds of encoding (video track duration is 10 seconds), 1 keyframe per 5 frames of the video track, so every 5 seconds, output framerate (fps) is 1 (-r 1):

ffmpeg -framerate 1/10 -i image.jpg -c:v libx264 -x264-params keyint=5:scenecut=0 -preset slow -r 1 -pix_fmt yuv420p out.mp4 
Results: 633 kb/s, 776K, 2 seconds of encoding (-threads 6 by default)

Keyframe rate affects video size. For longer videos, a slightly longer interval can be used.

Get 60 seconds of the video track, one keyframe every 10 seconds, fps is 1:

ffmpeg -framerate 1/60 -i image.jpg -c:v libx264 -x264-params keyint=10:scenecut=0 -preset slow -r 1 -pix_fmt yuv420p out.mp4
Results: 786 kb/s, 5.7 M, 12 seconds of encoding (-threads 6 by default)

Another method: Set video track duration directly (without -framerate option)

There is -loop 1 option which infinitely loops our image. We can stop encoding process by setting the duration option (-tseconds‘):

ffmpeg -loop 1 -i image.jpg -t 10 -c:v libx264 -preset slow -r 30 -pix_fmt yuv420p out.mp4 
Results: 782 kb/s, 961K, 28 seconds of encoding (-threads 6 by default)