I was working on a weather project to make animated maps of the jet stream. Getting and plotting wind data is a much longer article (coming soon), but once I had all the images plotted, I wanted to combine them all into a time-lapse video showing how the jet stream moves.
Like most projects, it's simple once you find the right recipe. If your images are named outdir/filename00.png, outdir/filename01.png, outdir/filename02.png and so on, you can turn them into an MPEG4 video with ffmpeg:
ffmpeg -i outdir/filename%2d.png -filter:v "setpts=6.0*PTS" -pix_fmt yuv420p jetstream.mp4
%02d, for non-programmers, just means a 2-digit decimal integer
with leading zeros, If the filenames just use 1, 2, 3, ... 10, 11 without
leading zeros, use %2d instead; if they have three digits, use %03d or
%3d, and so on.
Update: If your first photo isn't numbered 00, you can set a -start_number — but it must come before the -i and filename template. For instance:
ffmpeg -start_number 17 --i outdir/filename%2d.png -filter:v "setpts=6.0*PTS" -pix_fmt yuv420p jetstream.mp4
"setpts=6.0*PTS" controls the speed of the playback,
by adding or removing frames.
PTS stands for "Presentation TimeStamps",
which apparently is a measure of how far along a frame is in the file;
setpts=6.0*PTS means for each frame, figure out how far
it would have been in the file (PTS) and multiply that by 6. So if
a frame would normally have been at timestamp 10 seconds, now it will be at
60 seconds, and the video will be six times longer and six times slower.
And yes, you can also use values less than one to speed a video up.
You can also change a video's playback speed by
frame rate, either with the -r option, e.g.
or with the fps filter,
The default frame rate is 25.
You can examine values like the frame rate, number of frames and duration of a video file with:
ffprobe -select_streams v -show_streams filename
or with the mediainfo program (not part of ffmpeg).
-pix_fmt yuv420p turned out to be the tricky part.
The recipes I found online didn't include that part, but without it,
Firefox claims "Video can't be played because the file is corrupt",
even though most other browsers can play it just fine.
If you open Firefox's web console and reload, it offers the additional
"Details: mozilla::SupportChecker::AddMediaFormatChecker(const mozilla::TrackInfo&)::<lambda()>: Decoder may not have the capability to handle the requested video format with YUV444 chroma subsampling.":
-pix_fmt yuv420p cured the problem and made the
video compatible with Firefox, though at first I had problems with
ffmpeg complaining "height not divisible by 2 (1980x1113)" (even though
the height of the images was in fact divisible by 2).
I'm not sure what was wrong; later ffmpeg stopped giving me that error
message and converted the video. It may depend on where in the ffmpeg
command you put the pix_fmt flag or what other flags are
present. ffmpeg arguments are a mystery to me.
Of course, if you're only making something to be uploaded to youtube,
the Firefox limitation probably doesn't matter and you may not need
-pix_fmt yuv420p argument.
Making an animated GIF is easier. You can use ImageMagick's convert:
convert -delay 30 -loop 0 *.png jetstream.gifThe GIF will be a lot larger, though. For my initial test of thirty 1000 x 500 images, the MP4 was 760K while the GIF was 4.2M.
[ 09:59 May 11, 2018 More linux | permalink to this entry | ]