#!/bin/bash
##########
#
# process video files and create the podcast
#
# Mark Cain
# last modified: January 19, 2020
#
#
# What I would like to do next is process the speaker's name to populate the mp3 Tags and determine
# which intro bumper to use. I could pass the speakers name into the script as an arguement. I would
# need to increment the argument count.
#
###############
# set the following variable to the speaker's name
speaker_name="Peter hislastname";
# process the speaker's name to generate the lower_third_reference i.e. lowercase, underscore for spaces
lower_third_reference=$(echo $speaker_name | awk '{print tolower($0)}' | sed -e 's/ /_/');
# is the speaker "Peter hislastname" then populate bumper_reference with $lower_third_reference
if [ "$speaker_name" = "Peter hislastname" ]; then
bumper_reference=$lower_third_reference;
else
bumper_reference="generic";
fi
#
# Count the number of parameters passed into the script
# if the number of parameters is not within the range, halt the script and complain
#
if [[ $# -lt 4 ]] || [[ $# -gt 6 ]]
then
printf "Looks like I didn't get the right number of parameters\n"
printf " \n"
printf "If you are processing a single file (trimming a video clip), I need 4 parameters:\n"
printf " 1) File Number \n"
printf " 2) Starting time in minutes and seconds\n"
printf " 3) Ending time in minutes and seconds\n"
printf " 4) Series Title, Series Sequence Number, and Message Title\n"
printf " \n"
printf " like this:\n"
printf " \n"
printf " $0 1 12:14 22:45 \"Series Title - Part 2 - Message Title\"\n"
printf " \n"
printf " \n"
printf "If you are processing 2 files (joining or spanning 2 files), I need 5 parameters:\n"
printf " 1) First File Number \n"
printf " 2) Starting time in minutes and seconds\n"
printf " 3) Second File Number \n"
printf " 4) Ending time in minutes and seconds\n"
printf " 5) Series Title, Series Sequence Number, and Mesage Title\n"
printf " \n"
printf " like this:\n"
printf " \n"
printf " $0 1 12:14 2 22:45 \"Series Title - Part 2 - Message Title\"\n"
printf " \n"
printf " \n"
printf "If you are processing 3 files (joining or spanning 3 files), I need 6 parameters:\n"
printf " 1) First File Number \n"
printf " 2) Starting time in minutes and seconds\n"
printf " 3) Second File Number \n"
printf " 4) Third File Number \n"
printf " 5) Ending time in minutes and seconds\n"
printf " 6) Series Title, Series Sequence Number, and Mesage Title\n"
printf " \n"
printf " like this:\n"
printf " \n"
printf " $0 1 12:14 2 3 22:45 \"Series Title - Part 2 - Message Title\"\n"
printf " \n"
printf " \n"
exit
fi
##########################
#
# set a time variable to use for script duration calculations
STARTTIME=$(date +%s)
# Start processing the parameters passed into the script
# if there are 4 parameters set the variables as needed
if [ $# -eq 4 ]
then
# Assign the paraments to variables
videos=1
video1=$1
video1_start=$2
video1_end=$3
# Calcuate the starting point as expressed in seconds
minutes_start=$(echo $2 | cut -d: -f1)
seconds_start=$(echo $2 | cut -d: -f2)
start_in_seconds=$(echo "$minutes_start * 60 + $seconds_start" | bc -l)
# Calculate the ending point as expressed in seconds
minutes_end=$(echo $3 | cut -d: -f1)
seconds_end=$(echo $3 | cut -d: -f2)
ending_in_seconds=$(echo "$minutes_end * 60 + $seconds_end" | bc -l)
# calculate the duration of the clip in seconds
duration_in_seconds=$(echo "$ending_in_seconds - $start_in_seconds" | bc -l)
#parse the string that was passed via agruement to get the series, part, and title
# the way the folowing code works is that the 4th variable is piped into the cut command
# the cut command has the option to specifiy the delimiter as a hyphen "-" hence: -d-
# then we are look for the first field of the delimeter. hence: -f1
# then the result is piped through sed to remove any leading spaces
# then it is piped through sed again to remove any trailing spaces
# store the 1st field as the series
tag_series=$(echo $4 | cut -d- -f1 | sed -e 's/^ //' | sed -e 's/ $//')
# store the 2nd field as the part after removing leading space
tag_part=$(echo $4 | cut -d- -f2 | sed -e 's/^ //' | sed -e 's/ $//')
# Grab the number element of Part and store it as a track number
tag_track=$(echo ${tag_part: -1})
# store the 3rd field as the title after removing leading space
tag_title=$(echo $4 | cut -d- -f3 | sed -e 's/^ //' | sed -e 's/ $//')
# Build the filename. Cut the beginning and trailing spaces; then
# remove the spaces in the filename -- use underscores instead
filename=$(echo $4 | sed -e 's/^ //' | sed -e 's/ $//' | sed -e 's/ /_/g')
fi
# if there are 5 parameters set the variables as follows
if [ $# -eq 5 ]
then
# Assign the paraments to variables
videos=2
# format the name of the video file so that it is xxxxx.MTS where leading zeros
# proceed the actual number of the video and the extension is ".MTS"
video1=$(echo $1 | awk '{printf "%05d.MTS", $1}')
# format the start time of the video so that it is in HH:MM:SS.mmm
# The current file system in the camera is exfat which limits the file size to 4.2 Gigs which is
# roughly 26 minuts of 1080p video so there will never be a need to test for the hour segment.
# The hour segment can always default to 00. The following code supplies 00 for the hour
# segment, makes the minutes segment 2 digits with a leading zero if needed, makes the
# seconds segment 2 digits with a fragment of a second expressed in thousands
# Thus, 6:12.15 passed into the script will be reformated to 00:06:12.150
video1_start=$(echo $2 | awk -F: '{printf "00:%02d:%06.3f" , $1, $2}')
# format the name of the video file so that it is xxxxx.MTS where leading zeros
# proceed the actual number of the video and the extension is ".MTS"
video2=$(echo $3 | awk '{printf "%05d.MTS", $1}')
# format the end time of the video so that it is in HH:MM:SS.mmm
# The current file system in the camera is exfat which limits the file size to 4.2 Gigs which is
# roughly 26 minuts of 1080p video so there will never be a need to test for the hour segment.
# The hour segment can always default to 00. The following code supplies 00 for the hour
# segment, makes the minutes segment 2 digits with a leading zero if needed, makes the
# seconds segment 2 digits with a fragment of a second expressed in thousands
# Thus, 6:12.15 passed into the script will be reformated to 00:06:12.150
video2_end=$(echo $4 | awk -F: '{printf "00:%02d:%06.3f" , $1, $2}')
#parse the string that was passed via agruement to get the series, part, and title
# the way the folowing code works is that the 5th variable is piped into the cut command
# the cut command has the option to specifiy the delimiter as a hyphen "-" hence: -d-
# then we are look for the first field of the delimeter. hence: -f1
# then the result is piped through sed to remove any leading spaces
# then it is piped through sed again to remove any trailing spaces
# store the 1st field as the series
tag_series=$(echo $5 | cut -d- -f1 | sed -e 's/^ //' | sed -e 's/ $//')
# store the 2nd field as the part after removing leading space
tag_part=$(echo $5 | cut -d- -f2 | sed -e 's/^ //' | sed -e 's/ $//')
# Grab the number element of Part and store it as a track number
tag_track=$(echo ${tag_part: -1})
# store the 3rd field as the title after removing leading space
tag_title=$(echo $5 | cut -d- -f3 | sed -e 's/^ //' | sed -e 's/ $//')
# Build the filename. Cut the beginning and trailing spaces; then
# remove the spaces in the filename -- use underscores instead
filename=$(echo $5 | sed -e 's/^ //' | sed -e 's/ $//' | sed -e 's/ /_/g')
fi
# if there are 6 parameters set the variables as follows
if [ $# -eq 6 ]
then
# Assign the paraments to variables
videos=3
# format the name of the video file so that it is xxxxx.MTS where leading zeros
# proceed the actual number of the video and the extension is ".MTS"
video1=$(echo $1 | awk '{printf "%05d.MTS", $1}')
# format the start time of the video so that it is in HH:MM:SS.mmm
# The current file system in the camera is exfat which limits the file size to 4.2 Gigs which is
# roughly 26 minuts of 1080p video so there will never be a need to test for the hour segment.
# The hour segment can always default to 00. The following code supplies 00 for the hour
# segment, makes the minutes segment 2 digits with a leading zero if needed, makes the
# seconds segment 2 digits with a fragment of a second expressed in thousands
# Thus, 6:12.15 passed into the script will be reformated to 00:06:12.150
video1_start=$(echo $2 | awk -F: '{printf "00:%02d:%06.3f" , $1, $2}')
# format the name of the video file so that it is xxxxx.MTS where leading zeros
# proceed the actual number of the video and the extension is ".MTS"
video2=$(echo $3 | awk '{printf "%05d.MTS", $1}')
# format the name of the video file so that it is xxxxx.MTS where leading zeros
# proceed the actual number of the video and the extension is ".MTS"
video3=$(echo $4 | awk '{printf "%05d.MTS", $1}')
# format the end time of the video so that it is in HH:MM:SS.mmm
# The current file system in the camera is exfat which limits the file size to 4.2 Gigs which is
# roughly 26 minuts of 1080p video so there will never be a need to test for the hour segment.
# The hour segment can always default to 00. The following code supplies 00 for the hour
# segment, makes the minutes segment 2 digits with a leading zero if needed, makes the
# seconds segment 2 digits with a fragment of a second expressed in thousands
# Thus, 6:12.15 passed into the script will be reformated to 00:06:12.150
video3_end=$(echo $5 | awk -F: '{printf "00:%02d:%06.3f" , $1, $2}')
#parse the string that was passed via agruement to get the series, part, and title
# the way the folowing code works is that the 6th variable is piped into the cut command
# the cut command has the option to specifiy the delimiter as a hyphen "-" hence: -d-
# then we are look for the first field of the delimeter. hence: -f1
# then the result is piped through sed to remove any leading spaces
# then it is piped through sed again to remove any trailing spaces
# store the 1st field as the series
tag_series=$(echo $6 | cut -d- -f1 | sed -e 's/^ //' | sed -e 's/ $//')
# store the 2nd field as the part after removing leading space
tag_part=$(echo $6 | cut -d- -f2 | sed -e 's/^ //' | sed -e 's/ $//')
# Grab the number element of Part and store it as a track number
tag_track=$(echo ${tag_part: -1})
# store the 3rd field as the title after removing leading space
tag_title=$(echo $6 | cut -d- -f3 | sed -e 's/^ //' | sed -e 's/ $//')
# Build the filename. Cut the beginning and trailing spaces; then
# remove the spaces in the filename -- use underscores instead
filename=$(echo $6 | sed -e 's/^ //' | sed -e 's/ $//' | sed -e 's/ /_/g')
fi
######################################
#
# Here are the modules that will handle the work flow
#
#
function one_video () {
printf "We will be processing 1 video";
printf "Using $video1 from $video1_start to $video1_end ";
# check to see if there is an old file that needs to be deleted
remove_this $filename.mp4
# meaning of the options
# -ss is the starting point either in hh:mm:ss.ttt or simply in seconds
# -i is the input file
# -vcodec is the video codec and h264_nvenc exploits the NVIDIA GPU
# the flags, pixel format and video filter is best for Youtube videos
# -b:v is the bit rate for the video. 2M is 2 megs per second
# -t is the duration of the output file expressed in seconds
ffmpeg -hide_banner \
-ss 00:$video1_start \
-i 0000$video1.MTS \
-i ./constants/hcc_logo.svg \
-i ./constants/lower_thirds/name_animation_$lower_third_reference.mp4 \
-filter_complex "[1:v]scale=400:122[logo]; \
[0:a]dynaudnorm=m=45:p=1:b=1[a2]; \
[a2]volume=1.5[a3]; \
[a3]asplit[a][a4]; \
[0:v][logo]overlay=x=main_w-overlay_w-80:y=main_h-overlay_h-80[v-l]; \
[v-l][2:v]overlay=x=0:y=0:enable='between(t,0,12.5)'[v]" \
-vcodec h264_nvenc -preset fast \
-flags +cgop -pix_fmt yuv420p \
-b:v 2M -movflags +faststart \
-map "[v]" -map "[a]" -t $duration_in_seconds $filename.mp4 \
-map "[a4]" -t $duration_in_seconds -acodec libmp3lame bumperless_audio.mp3
}
two_videos() {
printf "We will be processing 2 videos\n\n";
printf "Starting with $video1 at $video1_start and cutting $video2 at $video2_end\n\n";
#
# lets clean up from the last job if the files are still hanging around
# test for the existence of the regular file trimmed1.MTS and delete if found
remove_this trimmed1.MTS
# test for the existence of the regular file trimmed2.MTS and delete if found
remove_this trimmed2.MTS
#########
#
# Output the first video from the start time (hh:mm:ss) to the end into a file names trimmed1.MTS
# -hide_banner suppresses the build info and copywrite text
# -loglevel fatal only shows fatal errors which are errors after which the prcess absolultely cannot contine
# the "ss" moves to that position. Using the -ss before the -i is faster than the -i before the -ss.
# the "i" indicates the input file
#
printf "Trimming the first video \n";
#
ffmpeg -hide_banner -loglevel 32 -ss $video1_start \
-i $video1 -codec copy trimmed1.MTS
#######
#
# Output the second video from the beginning to the end time (hh:mm:ss) into a file names trimmed2.MTS
# -hide_banner suppresses the build info and copywrite text
# -loglevel fatal only shows fatal errors which are errors after which the prcess absolultely cannot contine
# the "ss" moves to that position.
# the "i" indicates the input file
#
printf "Trimming the second video \n";
#
ffmpeg -hide_banner -loglevel 32 -i $video2 -ss 00:00:00.1 \
-to $video2_end -codec copy trimmed2.MTS
########
#
# Combine the 2 Videos into one file
# -hide_banner suppresses the build info and copywrite text
# -loglevel fatal only shows fatal errors which are errors after which the prcess absolultely cannot contine
#
# the "i" indicates the input file which in this case is the concatenated files
#
printf "Combining the two videos \n";
# check to see if there is an old file that needs to be deleted
remove_this $filename.mp4
ffmpeg -hide_banner -loglevel 32 \
-i trimmed1.MTS \
-i trimmed2.MTS \
-i ./constants/hcc_logo.svg \
-i ./constants/lower_thirds/name_animation_$lower_third_reference.mp4 \
-filter_complex "[0:v][0:a][1:v][1:a]concat=n=2:v=1:a=1[vv][a1]; \
[a1]dynaudnorm=m=45:p=1:b=1[a2]; \
[a2]volume=1.5[a3]; \
[a3]asplit[a][a4]; \
[2:v]scale=400:122[logo]; \
[vv][logo]overlay=x=main_w-overlay_w-80:y=main_h-overlay_h-80[v-l]; \
[v-l][3:v]overlay=x=0:y=0:enable='between(t,0,12.5)'[v]" \
-vcodec h264_nvenc -preset fast \
-flags +cgop -pix_fmt yuv420p \
-b:v 2M -movflags +faststart \
-map "[v]" -map "[a]" $filename.mp4 \
-map "[a4]" -acodec libmp3lame bumperless_audio.mp3
#finished with the files trimmed1.MTS and trimmed2.MTs; so delete them
remove_this trimmed1.MTS
remove_this trimmed2.MTS
}
three_videos() {
printf "We will be processing 3 videos";
printf "Starting with $video1 at $video1_start, adding all of $video2 and cutting $video3 at $video3_end";
# test for the existence of the regular file trimmed1.MTS and delete if found
remove_this trimmed1.MTS
# test for the existence of the regular file trimmed2.MTS and delete if found
remove_this trimmed2.MTS
# test for the existence of the regular file trimmed3.MTS and delete if found
remove_this trimmed3.MTS
#########
#
# Output the first video from the start time (hh:mm:ss) to the end into a file names trimmed1.MTS
# -hide_banner suppresses the build info and copywrite text
# -loglevel fatal only shows fatal errors which are errors after which the prcess absolultely cannot contine
# the "ss" moves to that position
# the "i" indicates the input file
#
ffmpeg -hide_banner -loglevel 32 \
-ss $video1_start -i $video1 -codec copy trimmed1.MTS
#########
#
# Output the second video in it's entirety into a file names trimmed2.MTS
# -hide_banner suppresses the build info and copywrite text
# -loglevel fatal only shows fatal errors which are errors after which the prcess absolultely cannot contine
# the "ss" moves to that position
# the "i" indicates the input file
#
ffmpeg -hide_banner -loglevel 32 \
-i $video2 -codec copy trimmed2.MTS
########
#
# Output the third video from the beginning to the end time (hh:mm:ss) into a file names trimmed3.MTS
# -hide_banner suppresses the build info and copywrite text
# -loglevel fatal only shows fatal errors which are errors after which the prcess absolultely cannot contine
# the "ss" moves to that position
# the "i" indicates the input file
#
ffmpeg -hide_banner -loglevel 32 \
-i $video3 -ss 00:00:00.1 -to $video3_end -codec copy trimmed3.MTS
########
#
# Combine the 3 Videos into one file
# -hide_banner suppresses the build info and copywrite text
# -loglevel fatal only shows fatal errors which are errors after which the prcess absolultely cannot contine
# the "ss" moves to that position
# the "i" indicates the input file
#
# check to see if there is an old file that needs to be deleted
remove_this $filename.mp4
ffmpeg -hide_banner -loglevel 32 \
-i trimmed1.MTS -i trimmed2.MTS -i trimmed3.MTS \
-i ./constants/hcc_logo.svg \
-i ./constants/lower_thirds/name_animation_$lower_third_reference.mp4 \
-filter_complex "[0:v][0:a][1:v][1:a][2:v][2:a]concat=n=3:v=1:a=1[vv][a1]; \
[a1]dynaudnorm=m=45:p=1:b=1[a2]; \
[a2]volume=1.5[a3]; \
[a3]asplit[a][a4]; \
[3:v]scale=400:122[logo]; \
[vv][logo]overlay=x=main_w-overlay_w-80:y=main_h-overlay_h-80[v-l]; \
[v-l][4:v]overlay=x=0:y=0:enable='between(t,0,12.5)'[v]" \
-vcodec h264_nvenc -preset slow \
-flags +cgop -pix_fmt yuv420p \
-b:v 2M -movflags +faststart \
-map "[v]" -map "[a]" $filename.mp4 \
-map "[a4]" -acodec libmp3lame bumperless_audio.mp3
#finished with the files trimmed1.MTS, trimmed2.MTS, and trimmed3.MTs; so delete them
remove_this trimmed1.MTS
remove_this trimmed2.MTS
remove_this trimmed3.MTS
}
# test for the existence of the regular file passed into the function and delete if found
remove_this() {
if [ -e $1 ] ; then
rm ./$1
fi
}
if [ $videos -eq 1 ]
then
one_video
fi
if [ $videos -eq 2 ]
then
two_videos
fi
if [ $videos -eq 3 ]
then
three_videos
fi
#######
# text an alert that the file is ready
#
echo "The video for Hope City is finished and ready to be uploaded to Youtube. " | ./twilio-sms XXX-XXX-XXXX
printf "\n\n"
printf "###############\n\n"
printf "# Step 1 of 2 - Joining the intro bumper, content, and outtro bumper and populating the ID3 tags"
printf "###############\n\n"
ffmpeg -hide_banner -loglevel 32 \
-i "concat:./constants/bumpers/bumper_intro_$bumper_reference.mp3|bumperless_audio.mp3|./constants/bumpers/bumper_outtro.mp3" \
-metadata title="$tag_title" \
-metadata album="$tag_series" \
-metadata Year="2020" \
-metadata author="$speaker_name" \
-metadata artist="$speaker_name" \
-metadata genre="Speech" \
-metadata track="$tag_track" \
-c copy wo_art.mp3
# finished with the file bumperless_audio.mp3; so delete it
remove_this bumperless_audio.mp3
printf "\n\n"
printf "###############\n\n"
printf "# Step 2 of 2 - Add the front cover artwork to the $filename.mp3 \n\n"
printf "###############\n\n"
ffmpeg -i wo_art.mp3 -i ./constants/album_covers/cover.png \
-c copy -map 0 -map 1 -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (front)" \
$filename.mp3
# finished with the file wo_art.mp3; so delete it
remove_this wo_art.mp3
printf "\n\n"
printf "###############\n\n"
ENDTIME=$(date +%s)
ELAPSED_TIME=$(($ENDTIME - $STARTTIME))
echo "Finished! Execution time was $((ELAPSED_TIME/60)) minutes and $((ELAPSED_TIME%60)) seconds."
printf "\n\n"
echo "The podcast for Hope City Church is finished and ready to upload to libsyn.com. Execution time was $((ELAPSED_TIME/60)) minutes and $((ELAPSED_TIME%60)) seconds." | ./twilio-sms XXX-XXX-XXXX