ffmpeg: Create a video countdown – new post (2021) 2
The code below was used to generate the video countdown timers that are available in the following playlist using ffmpeg
. These counters show seconds and fractions of seconds only. They do not bother with formating for minutes nor hours, etc.
#!/bin/bash
# This code will create a countdown video.
# If no command line arguments are provided, it will default to creating a 3-second video, with two fractional digits at 100 frames per second.
# It will print the elapsed and remaining times using two decimals accuracy.
defaultSeconds=3;
# If command line argument 1 is empty, the default value will be used.
seconds="${1:-$defaultSeconds}";
# Calculating how many digits are used to compose the seconds variable.
# We will use this information for zero-padding to avoid having the text move a lot.
# We used the shell parameter expansion to get the length of the variable value.
integerDigits="${#var}";
defaultFractionalDigits=2;
# If command line paremeter 2 is empty, the default value will be used.
fractionalDigits="${2:-$defaultFractionalDigits}";
#Computing how many frames per second are needed to maintain the accuracy of time based on the fractional digits.
fps=$((10 ** $fractionalDigits));
countDownFont=600;
countUpFont=100;
#Using a fixed width and fixed height font, to avoid having the text move around.
font='./Led.ttf';
#We are using the n variable: the frame number starting from 0 rather than the t variable, which is the timestamp expressed in seconds. We will get better accuracy on the decimals.
ffmpeg -loop 1 -i ~/Pictures/Black-Background.png -c:v libx264 -r $fps -t $seconds -vf "fps=$fps,
drawtext=fontfile=$font:fontcolor=yellow:fontsize=$countDownFont:x=(main_w-text_w)/2:y=(main_h-text_h)/2:text='%{eif\:($seconds-(n/$fps))\:d\:$integerDigits}.%{eif\:(mod($fps - mod(n, $fps), $fps))\:d\:$fractionalDigits}',
drawtext=fontfile=$font:fontcolor=yellow:fontsize=$countUpFont:x=(main_w-text_w)/2:y=((main_h-text_h)/2)+$countDownFont:text='Elapsed\: %{eif\:(n/$fps)\:d\:$integerDigits}.%{eif\:(mod(n, $fps))\:d\:$fractionalDigits}'" "$seconds seconds countdown timer with $fractionalDigits fractional digits accuracy.mp4";
Notes
- We used a single black frame for the background that defined the video frame’s size as well.
- Using the fps variable, we defined the number of Frames per Second for the video.
- The seconds variable defined the number of seconds the duration of the video should be.
- The
fractionalDigits
variable defines how many decimal digits should be shown after the dot. - countDownFont and countUpFont define the fonts’ size in the upper row and the lower one, respectively.
- We used the
drawtext
directive twice to write to the frames. font
variable defines a fixed-width font to avoid having the text moving around.
Notes on the first drawtext
x=(main_w-text_w)/2
defines the X-coordinate of the location for the text on the frame, here we center the text horizontally on the frame.(main_h-text_h)/2
defines the Y-coordinate of the location for the text on the frame, here we center the text vertically on the frame.text='%{eif\:($seconds-(n/$fps))\:d\:$integerDigits}.%{eif\:(mod($fps - mod(n, $fps), $fps))\:d\:$fractionalDigits}'
We print the remaining seconds for the video to finish with specific decimal digit accuracy.
Notes on the second drawtext
x=(main_w-text_w)/2
defines the X-coordinate of the location for the text on the frame, here we center the text horizontally on the frame.y=((main_h-text_h)/2)+$countDownFont
defines the Y-coordinate of the location for the text on the frame, here shift the text from the vertical center of the frame enough to move it under the main text.text='Elapsed\: %{eif\:(n/$fps)\:d\:$integerDigits}.%{eif\:(mod(n, $fps))\:d\:$fractionalDigits}'
We print the elapsed seconds since the video started with specific decimal digit accuracy.