How to create a video from images with FFmpeg? [closed]
Asked Answered
F

9

362
ffmpeg -r 1/5 -start_number 2 -i img%03d.png -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4

This line worked fine but I want to create a video file from images in another folder. Image names in my folder are:

img001.jpg
img002.jpg
img003.jpg
...

How could I input images files from a different folder? Example: C:\mypics

I tried this command but ffmpeg generated a video with the first image (img001.jpg) only.

ffmpeg -r 1/5 -start_number 0 -i C:\myimages\img%03d.png -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4
Finley answered 25/7, 2014 at 17:18 Comment(1)
related- making video from single image stackoverflow.com/questions/25891342/…Utu
C
295

See the Create a video slideshow from images – FFmpeg

If your video does not show the frames correctly If you encounter problems, such as the first image is skipped or only shows for one frame, then use the fps video filter instead of -r for the output framerate

ffmpeg -r 1/5 -i img%03d.png -c:v libx264 -vf fps=25 -pix_fmt yuv420p out.mp4

Alternatively the format video filter can be added to the filter chain to replace -pix_fmt yuv420p like "fps=25,format=yuv420p". The advantage of this method is that you can control which filter goes first

ffmpeg -r 1/5 -i img%03d.png -c:v libx264 -vf "fps=25,format=yuv420p" out.mp4

I tested below parameters, it worked for me

"e:\ffmpeg\ffmpeg.exe" -r 1/5 -start_number 0 -i "E:\images\01\padlock%3d.png" -c:v libx264 -vf "fps=25,format=yuv420p" e:\out.mp4

below parameters also worked but it always skips the first image

"e:\ffmpeg\ffmpeg.exe" -r 1/5 -start_number 0 -i "E:\images\01\padlock%3d.png" -c:v libx264 -r 30 -pix_fmt yuv420p e:\out.mp4

making a video from images placed in different folders

First, add image paths to imagepaths.txt like below.

# this is a comment details https://trac.ffmpeg.org/wiki/Concatenate

file 'E:\images\png\images__%3d.jpg'
file 'E:\images\jpg\images__%3d.jpg'

Sample usage as follows;

"h:\ffmpeg\ffmpeg.exe" -y -r 1/5 -f concat -safe 0 -i "E:\images\imagepaths.txt" -c:v libx264 -vf "fps=25,format=yuv420p" "e:\out.mp4"

-safe 0 parameter prevents Unsafe file name error

Related links

FFmpeg making a video from images placed in different folders

FFMPEG An Intermediate Guide/image sequence

Concatenate – FFmpeg

Conto answered 26/7, 2014 at 1:25 Comment(7)
"If your video does not show the frames correctly If you encounter problems, such as the first image is skipped or only shows for one frame, then use the ​fps video filter instead" Sorry but could you please explain what you mean by "fps video filter" exactly?Gilberto
As far as I know –r parameter is variable frame rate this means that FFMPEG might drop or duplicate frames to achieve desired output frame rate. Using fps filter “-vf fps=value” force FFMPEG to produce constant frame rate. See Create a video slideshow from images – FFmpeg, and this What is the (technical) difference between -r and the fps filter?. So using -r parameter sometimes couse skipping first image..Conto
The first command on this list, ffmpeg -r 1/5 -i img%03d.png -c:v libx264 -vf fps=25 -pix_fmt yuv420p out.mp4, seemed to work but in the end resulted in a video that was unreadable by any player (on Ubuntu). VNC said, "moov atom not found". Trying to remedy this with qt-faststart produced the error "last atom in file was not a moov atom"Towers
I used this -i img%05d.png pattern but there are 133 images, just 10 of them created as video, why?Glycoprotein
When you search for "Create a video slideshow from images – FFmpeg", on ddg, this question/answer is the first link. Well done! (maybe, ddg).Concertino
The concat example requires durations to work (as per the documentation), which must be multiples of (1/25=)0.04s (they will be rounded otherwise). Without durations, frames get dropped.Chatelain
why do u have -r and fps ? what is the difference ?Pylle
C
427

-pattern_type glob

This great option makes it easier to select the images in many cases.

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

These are the test media I've used:

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: How to use GLUT/OpenGL to render to a file?

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

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

Answered at: https://superuser.com/questions/700419/how-to-convert-mp3-to-youtube-allowed-video-format/1472572#1472572

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 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: Resize to fit in a box and set background to black on "empty" part

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: VLC freezes for low 1 FPS video created from images with ffmpeg Therefore it repeats each frame 30 times to keep the desired 1 image per second effect.

Next steps

You will also want to:

  • cut up the part of the audio that you want before joining it: Cutting the videos based on start and end time using ffmpeg

    ffmpeg -i in.mp3 -ss 03:10 -to 03:30 -c copy out.mp3
    

    Alternatively, you can also cut it directly in the conversion command by adding the -ss just before the audio -i:

    ffmpeg -framerate 1 -pattern_type glob -i 'raw/*.png' -ss 0:36 -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p raw.mp4
    

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

Different duration for each image

https://video.stackexchange.com/questions/23530/use-ffmpeg-to-create-a-video-from-a-few-images gives a solution.

You create a file in.txt like:

file png/1.png
outpoint 5
file png/2.png
outpoint 2
file png/3.png
outpoint 7

and outpoint sets the duration of the previous image in seconds.

Then we just remove -framerate from the previous conversion commands:

ffmpeg -f concat -i in.txt -framerate 1 -i orig/audio.ogg -c:v libx264 -c:a copy -shortest -r 30 -pix_fmt yuv420p black.mp4

I also like that that approach with file names in a file is nicer than having to rename the input files to have the correct order, which makes it easier to quickly reorder images on a text editor (multiple -i did not work). Having two lines per input file makes that a bit more annoying, I didn't manage to combine the file and outpoint into a single line, but still, good to know.

This approach is also convenient if you are just going to convert a subset of your images. Then, to save time on the ImageMagick, you can reuse that in.txt file to loop over only the images you care about:

grep -E '^file ' in.txt | sed -E 's/^file //; s/\..*//' | while read f; do
  echo $f
  convert -thumbnail 1280x720 -background black -gravity center -extent 1280x720 "$(command ls -1 ../$f.* | grep -v .xcf | head -n1)" "out/$f.jpg"
done

Tested on

ffmpeg 3.4.4, vlc 3.0.3, Ubuntu 18.04.

Bibliography

Carolacarolan answered 27/5, 2016 at 8:9 Comment(8)
If you are using python and subprocess.call to start ffmpeg, you should not use the single quotes 'in the input and output file names. Otherwise it will not find the files.Herodias
This would be great for me, but my build from npm package ffmpeg-static does not implement glob. (Pattern type 'glob' was selected but globbing is not supported by this libavformat build)Halfbreed
-pix_fmt caused Trailing options were found on the commandline. errorSacrarium
@AnthonyKong I could not reproduce with ffmpeg -framerate 1 -pattern_type glob -i '*.png' -c:v libx264 -r 30 -pix_fmt yuv420p out.mp4 on Ubuntun 19.10 ffmpeg 4.1.4 just now, what's your version and exact command?Carolacarolan
I used -r 15 -f image2 -s 512x512 -i "sequencePath" -vcodec libx264 -crf 25 -pix_fmt yuv420p -y "1.mp4" to make video from sequences image from IM00001.jpg to 'IM00133.jpg' but just some of them are present in video like 15, how to change this to ignore removed duplicate or make all images as video with specific framerate, I don't want ffmpeg remove anything, I want all ?Glycoprotein
The glob pattern is not available on Windows builds.Pitarys
Nowadays Option pattern_type not found., so possibly outdated.Forester
@Forester still working on ffmpeg 4.4.2, Ubuntu 22.04. Which version are you at?Carolacarolan
C
295

See the Create a video slideshow from images – FFmpeg

If your video does not show the frames correctly If you encounter problems, such as the first image is skipped or only shows for one frame, then use the fps video filter instead of -r for the output framerate

ffmpeg -r 1/5 -i img%03d.png -c:v libx264 -vf fps=25 -pix_fmt yuv420p out.mp4

Alternatively the format video filter can be added to the filter chain to replace -pix_fmt yuv420p like "fps=25,format=yuv420p". The advantage of this method is that you can control which filter goes first

ffmpeg -r 1/5 -i img%03d.png -c:v libx264 -vf "fps=25,format=yuv420p" out.mp4

I tested below parameters, it worked for me

"e:\ffmpeg\ffmpeg.exe" -r 1/5 -start_number 0 -i "E:\images\01\padlock%3d.png" -c:v libx264 -vf "fps=25,format=yuv420p" e:\out.mp4

below parameters also worked but it always skips the first image

"e:\ffmpeg\ffmpeg.exe" -r 1/5 -start_number 0 -i "E:\images\01\padlock%3d.png" -c:v libx264 -r 30 -pix_fmt yuv420p e:\out.mp4

making a video from images placed in different folders

First, add image paths to imagepaths.txt like below.

# this is a comment details https://trac.ffmpeg.org/wiki/Concatenate

file 'E:\images\png\images__%3d.jpg'
file 'E:\images\jpg\images__%3d.jpg'

Sample usage as follows;

"h:\ffmpeg\ffmpeg.exe" -y -r 1/5 -f concat -safe 0 -i "E:\images\imagepaths.txt" -c:v libx264 -vf "fps=25,format=yuv420p" "e:\out.mp4"

-safe 0 parameter prevents Unsafe file name error

Related links

FFmpeg making a video from images placed in different folders

FFMPEG An Intermediate Guide/image sequence

Concatenate – FFmpeg

Conto answered 26/7, 2014 at 1:25 Comment(7)
"If your video does not show the frames correctly If you encounter problems, such as the first image is skipped or only shows for one frame, then use the ​fps video filter instead" Sorry but could you please explain what you mean by "fps video filter" exactly?Gilberto
As far as I know –r parameter is variable frame rate this means that FFMPEG might drop or duplicate frames to achieve desired output frame rate. Using fps filter “-vf fps=value” force FFMPEG to produce constant frame rate. See Create a video slideshow from images – FFmpeg, and this What is the (technical) difference between -r and the fps filter?. So using -r parameter sometimes couse skipping first image..Conto
The first command on this list, ffmpeg -r 1/5 -i img%03d.png -c:v libx264 -vf fps=25 -pix_fmt yuv420p out.mp4, seemed to work but in the end resulted in a video that was unreadable by any player (on Ubuntu). VNC said, "moov atom not found". Trying to remedy this with qt-faststart produced the error "last atom in file was not a moov atom"Towers
I used this -i img%05d.png pattern but there are 133 images, just 10 of them created as video, why?Glycoprotein
When you search for "Create a video slideshow from images – FFmpeg", on ddg, this question/answer is the first link. Well done! (maybe, ddg).Concertino
The concat example requires durations to work (as per the documentation), which must be multiples of (1/25=)0.04s (they will be rounded otherwise). Without durations, frames get dropped.Chatelain
why do u have -r and fps ? what is the difference ?Pylle
W
43

Simple Version from the Docs

Works particularly great for Google Earth Studio images:

ffmpeg -framerate 24 -i Project%03d.png Project.mp4
Whereunto answered 29/12, 2018 at 23:21 Comment(11)
Can't play this output: [h264 @ 0x7f148cc3cc40] hardware accelerator failed to decode pictureUlcerative
hi how can i execute that command i am just finding that can you please help me?Gyrostatics
@Gyrostatics From your Terminal or Console.Whereunto
got it man but project%3d.png did not pick my all images in a folder with name Project001.png, Project002.png and so on it only get 2 pictures what should i do to get all my pictures and convert it to videoGyrostatics
Are you using %3d or %03d?Whereunto
ffmpeg prompted me if I want to overwrite the input filesSacrarium
@AnthonyKong Did you name the output file the same as your input file? Post your code here so we know what you're trying to do.Whereunto
After I put " (quote) around the file name specification after -i, the prompt is no more.Sacrarium
@AnthonyKong Do you have a space in either your input or output filename(s)?Whereunto
@JoshuaPinter you should give "quote" to the -i parameter's value, e.g. ffmpeg -framerate 24 -i "Project%03d.png" Project.mp4Meuse
Black screen here if playing with UBU default video player that can play other mp4s just fine. It does, however import and play into my video editor software(kdenlive).Accent
H
41

cat *.png | ffmpeg -f image2pipe -i - output.mp4

from wiki

Hest answered 30/7, 2019 at 13:17 Comment(7)
My savior! Thank you for this.Unquote
what about windows cmd?Flagon
this is genius. short, simple and most important of all: working!Salicylate
I slowed it down later with this ffmpeg -i output.mp4 -filter:v "setpts=60.0*PTS" output_slowed.mp4Guerrilla
@Guerrilla You missed the second - after -iSpiritism
Results in Output file #0 does not contain any stream with ffmpeg 5.1.2 on Mac.Cumber
Results in a .mp4 file with a certain size but movie does not play, black screenAccent
E
4

As the glob command is not available on windows, because its a POSIX implementation, the workaround is to use sequence as a pattern. For this to work, one needs to rename their files with sequence numbers - like

gym01.jpg
gym02.jpg
...

Then we can use the command below on Windows - NOTE the gym%02d.jpg, where if your sequence contains more than 2 chars (eg, gym00001.jpg), change it accordingingly (gym%05d.jpg)

ffmpeg -framerate 1 -pattern_type sequence -i gym%02d.jpg -s:v 1920x1080 -c:v libx264 -pix_fmt yuv420p out.mp4
Elvyn answered 28/10, 2022 at 7:11 Comment(0)
P
2

Your files should be named depth_00001.png depth_00002.png etc which ensures the correct order

step 1) If they are called depth_1.png depth_2.png then you can batch rename them to the required naming with this command

for f in depth_[0-9]*; do mv "$f" "$(printf 'depth_%05d' "${f#depth_}" 2> /dev/null)"; done; for f in depth_[0-9]*; do mv "$f" "$f.png"; done;

step 2) Then run ffmpeg using standard options

ffmpeg -framerate 30 -i depth_%05d.png -pix_fmt yuv420p -c:v libx264 depth.mp4

step 3) If that fails (it did for me on Windows) then try this instead

cat depth_*.png | ffmpeg -f image2pipe -framerate 30 -i - -pix_fmt yuv420p -c:v libx264 depth.mp4

NOTE: step 2 failed when I used PNGs - but when I used image magick to convert the PNGs to JPGs step 2 worked

Here's the command I used to do the conversion

for image in *.png; do magick convert "$image" "${image%.*}.jpg"; done;

Also, I found this command useful to verify that the length of the output video was as expected

ffprobe -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 depth.mp4
Phototypy answered 3/9, 2021 at 2:42 Comment(0)
D
2

For me to create video with audio it worked, you need to specify:

the normal frames: -framerate 30

the audio -i audio/audio.ogg

and the library libx264

   system("ffmpeg -framerate 30 -i #{out_dir}/%03d.png -i audio/audio.ogg 
-c:a copy -shortest -c:v libx264 -pix_fmt yuv420p out/final
/#{out_dir.sub("out/", "")}.mp4")

if you want to create a loop, for example 3 times -stream_loop 2 because of 0,1,2

    system("ffmpeg -stream_loop 2 -framerate 30 -i 
#{out_dir}/%03d.png -i audio/audio.ogg -c:a copy -shortest -c:v 
libx264 -pix_fmt yuv420p -b:v 50M  out/final/#{out_dir.sub("out/", 
"")}.mp4")
Damned answered 1/1, 2022 at 22:38 Comment(0)
P
1

To create frames from video:

ffmpeg\ffmpeg -i %video% test\thumb%04d.jpg -hide_banner

Optional: remove frames you don't want in output video
(more accurate than trimming video with -ss & -t)

Then create video from image/frames eg.:

ffmpeg\ffmpeg -framerate 30 -start_number 56 -i test\thumb%04d.jpg -vf format=yuv420p test/output.mp4
Pitarys answered 16/2, 2021 at 5:7 Comment(0)
M
0

I found this helpful and tried it

ffmpeg -framerate 1 -pattern_type glob -i '*.jpg' -c:v libx264 -r 30 -pix_fmt yuv420p output.mp4

Source : https://shotstack.io/learn/use-ffmpeg-to-convert-images-to-video/

Meshed answered 24/9, 2022 at 15:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.