This is an old revision of the document!
Table of Contents
FFmpeg-based Interval Timer for Sport and Exercise
I am the one of the cycling captain of UEA Triathlon Club for the academic year of 2017-2018. I always find it hard to keep track of the set in a turbo session for some reason.
I used to use a Matlab-based countdown timer 1). However it always freezes after 558 seconds had elapsed - if you set a 10-minute countdown timer, it will freeze at 42 seconds. I can't be bothered to fix the Matlab code.
After digging through FFmpeg documentation 2) and the Internet, I figured out how to generate a text-based video.
Here I present the program listing, and an example output. The script works fine on Debian Stretch.
I have to say FFmpeg is one of my most abused software. Last time I used FFmpeg to upload arbitrary file to Youtube 3).
Program listing
#!/bin/bash # Copyright <2017> <Fufu Fang> # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # The content of the set # Format: # min:sec text turbo=( #Warm up '05:00 90 RPM Smooth pedalling' '02:00 95 RPM Smooth pedalling' '02:00 100 RPM Smooth pedalling' '02:00 105 RPM Smooth pedalling' '01:30 110 RPM Smooth pedalling' '00:30 120-130 RPM Maintain form' '02:00 90 RPM Relax and recover' '00:06 MAX RPM Rev out' '01:00 90 RPM Smooth pedalling' '00:06 MAX RPM Rev out' '01:00 90 RPM Smooth pedalling' '00:06 MAX RPM Rev out' '02:45 90 RPM Relax and recover' #Russian Steps '00:15 Max effort' '00:45 Recovery' '00:30 Max effort' '00:30 Recovery' '00:45 Max effort' '00:15 Recovery' '01:00 Max effort' '01:00 Recovery' '00:45 Max effort' '00:15 Recovery' '00:30 Max effort' '00:30 Recovery' '00:15 Max effort' '05:45 Recovery' '00:15 Max effort' '00:45 Recovery' '00:30 Max effort' '00:30 Recovery' '00:45 Max effort' '00:15 Recovery' '01:00 Max effort' '01:00 Recovery' '00:45 Max effort' '00:15 Recovery' '00:30 Max effort' '00:30 Recovery' '00:15 Max effort' '05:45 Recovery' '00:15 Max effort' '00:45 Recovery' '00:30 Max effort' '00:30 Recovery' '00:45 Max effort' '00:15 Recovery' '01:00 Max effort' '01:00 Recovery' '00:45 Max effort' '00:15 Recovery' '00:30 Max effort' '00:30 Recovery' '00:15 Max effort' '10:00 Cool Down' ) ################################################################################ resolution=1280x720 framerate=30 # The file number counter let counter=0 # The length of the set let setLen=${#turbo[@]}-1 function cleanup { rm -f seg-*.mp4 filelist.txt intro.txt } # Calling convention: duration, font_size function introduction { ffmpeg -f lavfi -i color=c=white:size=${resolution}:rate=${framerate} \ -vf "drawtext=textfile=intro.txt: fontsize=${2}: \ r=${framerate}: x=(w-tw)/2: y=h-h*0.9: fontcolor=black:" \ -t ${1} -preset ultrafast -tune stillimage -y -loglevel panic -stats \ seg-${counter}.mp4 echo "file seg-${counter}.mp4" >> filelist.txt let counter++ } # Calling convention: min, sec, text_now, text_next function videoSegment { let duration=${1}*60+${2} min=${1} sec=${2} textNow=${3} textNext=$(echo "Next -" ${4}) ffmpeg -f lavfi -i color=c=white:size=${resolution}:rate=${framerate} \ -vf "\ drawtext=text='${textNow}': fontsize=80: \ r=${framerate}: x=(w-tw)*0.5: y=h-h*0.80: fontcolor=Black:,\ \ drawtext=text='Duration: ${min} min ${sec} sec': fontsize=80: \ r=${framerate}: x=(w-tw)*0.5: y=h-h*0.60: fontcolor=Black:, \ drawtext=timecode='00\:00\:00\:00': fontsize=80: \ r=${framerate}: x=(w-tw)*0.5: y=h-h*0.40: fontcolor=Black:, \ \ drawtext=text='${textNext}': fontsize=50: \ r=${framerate}: x=(w-tw)*0.5: y=h-h*0.20: fontcolor=SlateGray:" \ \ -t ${duration} -preset ultrafast -tune stillimage -y -loglevel panic -stats \ seg-${counter}.mp4 echo "file seg-${counter}.mp4" >> filelist.txt let counter++ } function output { ffmpeg -f concat -i filelist.txt -c copy -y ${1} cleanup } # Calling convention: segment_id function turboSegment { thisLine=$(echo ${turbo[${1}]}) timing=$(echo $thisLine|cut -d ' ' -f 1) min=$(echo $timing|cut -d ':' -f 1) sec=$(echo $timing|cut -d ':' -f 2) textNow=$(echo $thisLine|cut -d ' ' -f 2-) let nextSeg=${1}+1 nextLine=$(echo ${turbo[${nextSeg}]}|tr ':' 'm') videoSegment $min $sec "${textNow}" "${nextLine}" } ################################################################################ cleanup # Create the introduction text variable printf "%s\n" "${turbo[@]}" > intro.txt # introduction 10 40 # read -p "Press any key to continue, or Ctrl+C to stop..." for i in $(seq 0 $setLen); do turboSegment ${i} done output UEA-Triathlon-$(date --rfc-3339=date).mp4