117

Is it possible to use ffmpeg to create a video from a set of sequences, where the number does not start from zero?

For example, I have some images [test_100.jpg, test_101.jpg, test_102.jpg, ..., test_200.jpg], and I want to convert them to a video. I tried the following command, but it did not work (it seems the number should start from zero):

ffmpeg -i test_%d.jpg -vcodec mpeg4 test.avi

Any advice?

13 Answers13

106

There is no need to rename files if using the -start_number switch like so:

ffmpeg -start_number n -i test_%d.jpg -vcodec mpeg4 test.avi

where n is the start of the sequence of stills.

Note, this will work as long as the sequence is unbroken once it starts. If there are gaps and you want all of the stills included, then renumbering may be necessary to fill the gaps.

There are some other switches you might find useful.

I use the following one-liner to get a slower frame rate and to compress the images and have a smaller resulting video:

ffmpeg.exe -f image2 -framerate 25 -pattern_type sequence -start_number 1234 -r 3 -i Imgp%04d.jpg -s 720x480 test.avi

The -r 3 option sets the framerate of the resulting video to 3 frames per second so that I can see each still for a short period of time. The -s option rescales the pictures to the desired resolution to manage the size of the resulting video.

(In the Windows shell, replace -i Imgp%04d.jpg with -i "Imgp%%04d.jpg". Credit for this to Mike Fitzpatrick https://superuser.com/a/344178/153054)

Assad Ebrahim
  • 2,110
  • 2
  • 23
  • 30
42

you can use this below code snippet:

 cat *.jpg | ffmpeg -f image2pipe -r 1 -vcodec mjpeg -i - -vcodec libx264 out.mp4
34

From ffmpeg's docs:

Using a glob pattern

ffmpeg also supports bash-style globbing (* represents any number of any characters).

This is useful if your images are sequential but not necessarily in a numerically sequential order as in the previous examples.

ffmpeg -r 1 -pattern_type glob -i 'test_*.jpg' -c:v libx264 out.mp4

So, as long as your files are sorted, using the -pattern_type glob switch should work for you.

Note that the quotes around the pattern are important in the case a glob is used.

19

You can find an example script in the ffmpeg documentation:

3.2 How do I encode single pictures into movies?

If you have large number of pictures to rename, you can use the following command to ease the burden. The command, using the bourne shell syntax, symbolically links all files in the current directory that match *jpg to the /tmp' directory in the sequence of img001.jpg', `img002.jpg' and so on.

x=1; for i in *jpg; do counter=$(printf %03d $x); ln "$i" /tmp/img"$counter".jpg; x=$(($x+1)); done

Then run:

ffmpeg -f image2 -i /tmp/img%03d.jpg /tmp/a.mpg
gaizka
  • 291
12

-pattern_type glob concrete examples with audio

This option was mentioned at: https://superuser.com/a/782520/128124 but here are a few concrete examples of its usage, including of adding audio to the output video.

Slideshow video with one image per second

ffmpeg -framerate 1 -pattern_type glob -i '*.png' \
  -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4

Add some music to it, cutoff when the presumably longer audio when the images end:

ffmpeg -framerate 1 -pattern_type glob -i '*.png' -i audio.ogg \
  -c:a copy -shortest -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4

Here are two demos on YouTube:

Be a hippie and use the Theora patent-unencumbered video format in an OGG container:

ffmpeg -framerate 1 -pattern_type glob -i '*.png' -i audio.ogg \
  -c:a copy -shortest -c:v libtheora -r 30 -pix_fmt yuv420p out.ogv

Your images should of course be sorted alphabetically, typically as:

0001-first-thing.jpg
0002-second-thing.jpg
0003-and-third.jpg

and so on.

I would also first ensure that all images to be used have the same aspect ratio, possibly by cropping them with imagemagick or nomacs beforehand, so that ffmpeg will not have to make hard decisions. In particular, the width has to be divisible by 2, otherwise conversion fails with: "width not divisible by 2".

Full realistic slideshow case study setup step by step

There's a bit more to creating slideshows than running a single ffmpeg command, so here goes a more interesting detailed example inspired by this timeline.

Get the input media:

mkdir -p orig
cd orig
wget -O 1.png https://upload.wikimedia.org/wikipedia/commons/2/22/Australopithecus_afarensis.png
wget -O 2.jpg https://upload.wikimedia.org/wikipedia/commons/6/61/Homo_habilis-2.JPG
wget -O 3.jpg https://upload.wikimedia.org/wikipedia/commons/c/cb/Homo_erectus_new.JPG
wget -O 4.png https://upload.wikimedia.org/wikipedia/commons/1/1f/Homo_heidelbergensis_-_forensic_facial_reconstruction-crop.png
wget -O 5.jpg https://upload.wikimedia.org/wikipedia/commons/thumb/5/5a/Sabaa_Nissan_Militiaman.jpg/450px-Sabaa_Nissan_Militiaman.jpg
wget -O audio.ogg https://upload.wikimedia.org/wikipedia/commons/7/74/Alnitaque_%26_Moon_Shot_-_EURO_%28Extended_Mix%29.ogg
cd ..

Convert all to PNG for consistency.

https://unix.stackexchange.com/questions/29869/converting-multiple-image-files-from-jpeg-to-pdf-format

Hardlink the ones that are already PNG.

mkdir -p png mogrify -format png -path png orig/.jpg ln -P orig/.png png

Now we have a quick look at all image sizes to decide on the final aspect ratio:

identify png/*

which outputs:

png/1.png PNG 557x495 557x495+0+0 8-bit sRGB 653KB 0.000u 0:00.000
png/2.png PNG 664x800 664x800+0+0 8-bit sRGB 853KB 0.000u 0:00.000
png/3.png PNG 544x680 544x680+0+0 8-bit sRGB 442KB 0.000u 0:00.000
png/4.png PNG 207x238 207x238+0+0 8-bit sRGB 76.8KB 0.000u 0:00.000
png/5.png PNG 450x600 450x600+0+0 8-bit sRGB 627KB 0.000u 0:00.000

so the classic 480p (640x480 == 4/3) aspect ratio seems appropriate.

Do one conversion with minimal resizing to make widths even (TODO automate for any width, here I just manually looked at identify output and reduced width and height by one):

mkdir -p raw
convert png/1.png -resize 556x494 raw/1.png
ln -P png/2.png png/3.png png/4.png png/5.png raw
ffmpeg -framerate 1 -pattern_type glob -i 'raw/*.png' -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p raw.mp4

This produces terrible output, because as seen from:

ffprobe raw.mp4

ffmpeg just takes the size of the first image, 556x494, and then converts all others to that exact size, breaking their aspect ratio.

Now let's convert the images to the target 480p aspect ratio automatically by cropping as per https://stackoverflow.com/questions/21262466/imagemagick-how-to-minimally-crop-an-image-to-a-certain-aspect-ratio

mkdir -p auto
mogrify -path auto -geometry 640x480^ -gravity center -crop 640x480+0+0 png/*.png
ffmpeg -framerate 1 -pattern_type glob -i 'auto/*.png' -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p auto.mp4

So now, the aspect ratio is good, but inevitably some cropping had to be done, which kind of cut up interesting parts of the images.

The other option is to pad with black background to have the same aspect ratio as shown at: https://stackoverflow.com/questions/18514083/resize-to-fit-in-a-box-and-set-background-to-black-on-empty-part/18514327

mkdir -p black
mogrify -path black -thumbnail 640x480 -background black -gravity center -extent 640x480 png/*.png
ffmpeg -framerate 1 -pattern_type glob -i 'black/*.png' -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p black.mp4

Generally speaking though, you will ideally be able to select images with the same or similar aspect ratios to avoid those problems in the first place.

About the CLI options

Note however that despite the name, -glob this is not as general as shell Glob patters, e.g.: -i '*' fails: https://trac.ffmpeg.org/ticket/3620 (apparently because filetype is deduced from extension).

-r 30 makes the -framerate 1 video 30 FPS to overcome bugs in players like VLC for low framerates: https://stackoverflow.com/questions/19267443/playback-issues-in-vlc-with-low-fps-video-from-images-using-ffmpeg/41797724#41797724 Therefore it repeats each frame 30 times to keep the desired 1 image per second effect.

Next steps

You will also want to:

TODO: learn to cut and concatenate multiple audio files into the video without intermediate files, I'm pretty sure it's possible:

Normal speed video with one image per frame at 30 FPS

ffmpeg -framerate 30 -pattern_type glob -i '*.png' \
  -c:v libx264 -pix_fmt yuv420p out.mp4

Here's what it looks like:

GIF generated with: https://askubuntu.com/questions/648603/how-to-create-an-animated-gif-from-mp4-video-via-command-line/837574#837574

Add some audio to it:

ffmpeg -framerate 30 -pattern_type glob -i '*.png' \
  -i audio.ogg -c:a copy -shortest -c:v libx264 -pix_fmt yuv420p out.mp4

Result: https://www.youtube.com/watch?v=HG7c7lldhM4

Convert one music file to a video with a fixed image for YouTube upload

Answered at: How to convert MP3 to YouTube-allowed video format?

Obtain some synthetic test input images

These are the test images I've been using in this answer:

wget -O opengl-rotating-triangle.zip https://github.com/cirosantilli/media/blob/master/opengl-rotating-triangle.zip?raw=true
unzip opengl-rotating-triangle.zip
cd opengl-rotating-triangle
wget -O audio.ogg https://upload.wikimedia.org/wikipedia/commons/7/74/Alnitaque_%26_Moon_Shot_-_EURO_%28Extended_Mix%29.ogg

Images generated with: https://stackoverflow.com/questions/3191978/how-to-use-glut-opengl-to-render-to-a-file/14324292#14324292

It is cool to observe how much the video compresses the image sequence way better than ZIP as it is able to compress across frames with specialized algorithms:

  • opengl-rotating-triangle.mp4: 340K
  • opengl-rotating-triangle.zip: 7.3M

About the CLI options

Note however that despite the name, -glob this is not as general as shell Glob patters, e.g.: -i '*' fails: https://trac.ffmpeg.org/ticket/3620 (apparently because filetype is deduced from extension).

-r 30 makes the -framerate 1 video 30 FPS to overcome bugs in players like VLC for low framerates: https://stackoverflow.com/questions/19267443/playback-issues-in-vlc-with-low-fps-video-from-images-using-ffmpeg/41797724#41797724 Therefore it repeats each frame 30 times to keep the desired 1 image per second effect.

Next steps

You will also want to:

TODO: learn to cut and concatenate multiple audio files into the video from the command line:

Tested on

ffmpeg 3.4.4, vlc 3.0.3, Ubuntu 18.04.

Bibliography

11

As far as I know, you cannot start the sequence in random numbers (I don't remember if you should start it at 0 or 1), plus, it cannot have gaps, if it does, ffmpeg will assume the sequence is over and stop adding more images.

Also, as stated in the comments to my answer, remember you need to specify the width of your index. Like:

image%03d.jpg

And if you use a %03d index type, you need to pad your filenames with 0, like :

image001.jpg image002.jpg image003.jpg

etc.

5

I agree with Francisco, but as a workaround you could just write a quick script to move or create symbolic links to the files with the sequence numbers that ffmpeg needs. The script could then call ffmpeg and then remove the links or move the files back to their original locations.

Jason B
  • 151
3

I know this is an old question but I came across it in Google while looking for the same answer. None of the answers here satisfied me completely so I did more searching and reading and this is a command that I came up with for my own problem.

cat {0032..1501}*.png | ffmpeg -f image2pipe -framerate 5 -i - -s 720x480 test2.avi

The reason why i'd use a command like this is...

  1. Cat and -f image2pipe give you finer control over what images you use. For example it allows you to use bash features like bracket expansion and other commands like grep to fine-tune your results should you choose.
  2. Fewer switches to remember.
  3. I recommend NOT using -r, and just use -framerate instead. In my experience -r tends to drop frames more often.
  4. Less complex, no unnecessary switches in use and it will work as-is. You may add more complexity (for example, specifying encoder) and fine tune to suit your needs.
2

look up

x=1; for i in *jpg; do counter=$(printf %03d $x); ln "$i"
/tmp/img"$counter".jpg; x=$(($x+1)); done
0

You can do this with convert -morph:

convert *.jpg -delay 10 -morph 10 %05d.jpg

If you want to use ffmpeg, I used

ffmpeg -pattern_type glob -i '*.jpg' -vf "setpts=10*PTS" movie.mp4

where the 10*PTS tells ffmpeg to slow it down 10 times. You can also have fractions there to speed it up.

Martin Thoma
  • 3,604
  • 10
  • 36
  • 65
0

From the documentation, it seems you can simply use *

For example, for creating a video from filenames matching the glob pattern foo-*.jpeg:

ffmpeg -f image2 -pattern_type glob -framerate 12 -i 'foo-*.jpeg' -s WxH foo.avi

As a note, to improve affect the quality, the rate/fps might be important (eg, first specifying very low/high frame rate and then pass from a second filter that will make the slow motion video to normal?)

ntg
  • 230
0

In my case, it was a little trickier because of the numbers in the files. Here's how my images look like:

$ ls | head -5
2014_aq_unprocessed 001.jpg
2014_aq_unprocessed 002.jpg
2014_aq_unprocessed 003.jpg
2014_aq_unprocessed 004.jpg
2014_aq_unprocessed 005.jpg

and here's the command I used:

ffmpeg -i 2014_aq_unprocessed\ %3d.jpg  -vcodec mpeg4 test.avi
0

I used the flv encoder since my video was going in a flash player (Jwplayer)

ffmpeg -i %d.jpg -vcodec flv test.flv