ffmpeg


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.

ffmpeg: Cut out a part of a video

Following is a snippet we used to remove a few seconds from a video using ffmpeg

ffmpeg -i 'input.mkv' -filter_complex \
  "[0:v]trim=end=553,setpts=N/FRAME_RATE/TB[v0]; \
   [0:a]atrim=end=553,asetpts=N/SR/TB[a0]; \
   [0:v]trim=start=559,setpts=N/FRAME_RATE/TB[v1]; \
   [0:a]atrim=start=559,asetpts=N/SR/TB[a1]; \
   [v0][a0][v1][a1]concat=n=2:v=1:a=1[v][a]" \
  -map "[v]" -map "[a]" 'output.mkv'

Specifically, we removed the seconds 09:13 (second 553) to 09:19 (second 559).