Simple time lapse with ffmpeg
04 Dec 2022 - tsp
Last update 04 Dec 2022
4 mins
So the idea is simple: Capturing images at fixed intervals from an attached
camera or some webcam reachable via the network. One might for example
use an ESP32 cam in ones WiFi and periodically fetch images from this
camera onto oneβs server to generate a multi-year time lapse. Or one might
want to illustrate how algorithms behave over time and simply generate state
images at various steps in time. Then one often wants to stitch the images
to form a video in the end. A really good tool for this is ffmpeg.
Assembling frames with ffmpeg
Using globber
Globber provides the easiest way to supply a filename pattern. It just performs
the typical resolution of wildcards as also done by ones shell:
- Selecting the globber pattern type using
-pattern_type glob
- Passing the filename pattern using
-i
. In case one wants to join
all images ending in .jpg
one could for example supply -i "*.jpg"
. In
this case the quotes are important to prevent expansion of the parameter by
the shell itself
Then one uses the typical parameters like
-r
to specify the framerate like -r 10
for 10 frames per second
in the output video
-s 640x480
to supply the desired output size (in this example 640 times 480 pixels)
- specifying the video codec:
-vcodec libx264
This would lead to the following example command line:
ffmpeg -pattern_type glob -r 10 -i "*.jpg" -s 640x480 -vcodec libx264 out.mp4
Using a counter
Unfortunately on some platforms (like Windows) globber is not available as
pattern type. Then one has to switch to the sequence
pattern type and
enumerate images with monotonically increasing numbers - for example calling
them image0001.jpg
, image0002.jpg
, etc. When using sequences ffmpeg
will stop after the first image thatβs not found any more.
The idea is to:
- Selecting the sequence pattern type using
-pattern_type sequence
- Supplying the first number used
-start-number 00000001
- Specifying the filename pattern using a placeholder. The placeholder
can be either
%d
for a non zero padded number or something like %08d
that would specify a decimal number zero padded to 8 digits.
Then one uses the typical parameters like
-r
to specify the framerate like -r 10
for 10 frames per second
in the output video
-s 640x480
to supply the desired output size (in this example 640 times 480 pixels)
- specifying the video codec:
-vcodec libx264
This would lead to the following example command line:
ffmpeg -pattern_type sequence -start_number 00000001 -r 10 -i image%08d.png -s 640x480 -vcodec libx264 out.mp4
Capturing frames
So now that one knows how to assemble frames - how does one capture them? This
of course depends on the source of the images.
Capturing from ESP32 camera or other HTTP devices
For a HTTP based webcam like the streams exposed for example by ESP32-CAM (note: affiliate
link, this pages author profits from qualified purchases) one can simply use
tools like fetch
or wget
that are usually preinstalled to fetch frames
at intervals configured in crontab
.
The idea is to use a small script fetchframe.sh
that builds the filename
pattern and executes the fetch. For example:
#!/bin/sh
fdate=`date +"%Y-%m-%d-%H-%M-%S"`
fname="/home/exampleuser/timelapseimages/${fdate}.jpg"
fetch -q -o ${fname} http://example.com/capture?_cb=1665873105911
This script can then be called from a crontab entry (edit either the system wide
crontab at /etc/crontab
or better the users crontab using crontab -e
)
For the users crontab an entry that should capture every minute would look like
the following:
* * * * * /home/exampleuser/timelapseimages/fetchframe.sh
To fetch only every five minutes:
*/5 * * * * /home/exampleuser/timelapseimages/fetchframe.sh
In case one wants to fetch an image every day at noon for example one can of course
also fix the time to 12 o clock every day:
0 12 * * * /home/exampleuser/timelapseimages/fetchframe.sh
When one then wants to assemble all frames one can simply use the above pattern.
Of course itβs also possible to automate the process again using a shell script
or something similar
Capturing from a webcam
Itβs also possible to capture images directly from an attached video4linux
device using tools like ffmpeg by simply limiting the number of video frames to
one.
#!/bin/sh
fdate=`date +"%Y-%m-%d-%H-%M-%S"`
fname="/home/exampleuser/timelapseimages/${fdate}.jpg"
ffmpeg -f video4linux2 -i /dev/video0 -vframes 1 -video_size 640x480 ${fname}
This article is tagged: