Skip to content

Instantly share code, notes, and snippets.

@dericed
Created April 28, 2015 03:33
Show Gist options
  • Save dericed/baa1b3291fb546e1d8fb to your computer and use it in GitHub Desktop.
Save dericed/baa1b3291fb546e1d8fb to your computer and use it in GitHub Desktop.
Bash script to use ffmpeg to pad an input with a color and silence at one or both ends.
#!/bin/bash
# suffix to use on the output file
suffix="_padded"
# color must be a value from http://ffmpeg.org/ffmpeg-utils.html#Color
color="black"
# seconds_at_start must be an integer
seconds_at_start=2
# seconds_at_end must be an integer
seconds_at_end=10
get_width(){
width=$(ffprobe "$1" -show_streams -select_streams v:0 2> /dev/null | grep ^width= | cut -d = -f 2)
}
get_height(){
height=$(ffprobe "$1" -show_streams -select_streams v:0 2> /dev/null | grep ^height= | cut -d = -f 2)
}
get_framerate(){
framerate=$(ffprobe "$1" -show_streams -select_streams v:0 2> /dev/null | grep ^r_frame_rate= | cut -d = -f 2)
if [ "$framerate" = "2997/100" ] ; then
framerate="30000/1001"
fi
}
get_channels(){
channels=$(ffprobe "$1" -show_streams -select_streams a:0 2> /dev/null | grep ^channels= | cut -d = -f 2)
}
get_sar(){
unset sar
sar=$(ffprobe "$1" -show_streams -select_streams v:0 2> /dev/null | grep ^sample_aspect_ratio= | cut -d = -f 2 | sed 's|:|/|g')
if [ "$sar" = "0/1" ] ; then
sar="1/1"
fi
}
get_samplerate(){
samplerate=$(ffprobe "$1" -select_streams a:0 -show_streams 2> /dev/null | grep ^sample_rate= | cut -d= -f2)
}
get_audiocodecname(){
audiocodecname=$(ffprobe "$1" -select_streams a:0 -show_streams 2> /dev/null | grep ^codec_name= | cut -d= -f2)
}
get_timecode(){
unset timecode
timecode=$(ffprobe "$1" -show_format 2> /dev/null | grep ^TAG:timecode | cut -d= -f2)
if [ "$timecode" = "" ] ; then
timecode="01:00:00;00"
fi
}
adjusttimecode() {
timecode="${1}"
h="${timecode:0:2}"
m="${timecode:3:2}"
s="${timecode:6:2}"
d="${timecode:8:1}"
f="${timecode:9:2}"
seconds=$(echo "${h}*3600+${m}*60+${s}" | bc)
adjustedseconds=$(echo "${seconds}-${seconds_at_start}" | bc)
h2="$((${adjustedseconds}/60/60))"
m2="$((${adjustedseconds}/60%60))"
s2="$((${adjustedseconds}%60))"
echo "${h2}:${m2}:${s2}${d}${f}"
}
if [ "$#" = 0 ] ; then
echo "this script is intended to simply accept an input video and then add some amount of padded to one or both ends, while adjusting the timecode to maintain timecode-to-frame associations of the input."
echo "Usage: $(basename ${0}) [ -o output_directory ] file1 [ file2 ... ]"
echo
echo "There's some other options but tweak the header of this script to work that."
exit
fi
# command-line options
OPTIND=1
while getopts ":o:x:" opt ; do
case "${opt}" in
o) output_dir="$OPTARG" ;;
x) audio_offset="$OPTARG" ;;
*) echo "bad option -$OPTARG" ; usage ;;
:) echo "Option -$OPTARG requires an argument" ; exit 1 ;;
esac
done
shift $(( ${OPTIND} - 1 ))
while [ "${*}" != "" ] ; do
# get context about the input
input_movie="${1}"
name=$(basename "$input_movie")
if [ ! -s "$input_movie" ] ; then
echo Hey "$input_movie" does not look like a real file.
exit
fi
if [ ! -d "$output_dir" ] ; then
output_dir=`dirname "$input_movie"`
fi
if [ ! "$audio_offset" ] ; then
audio_offset="0"
fi
get_timecode "${input_movie}"
timecodeout=$(adjusttimecode "$timecode")
echo "timecode is adjusted from $timecode to $timecodeout"
get_width "${input_movie}"
get_height "${input_movie}"
get_framerate "${input_movie}"
get_channels "${input_movie}"
get_sar "${input_movie}"
get_samplerate "${input_movie}"
get_audiocodecname "${input_movie}"
ffmpeg -f lavfi -i "color=color=${color}:s=${width}x${height}:r=${framerate}:sar=${sar}:d=${seconds_at_start}" \
-f lavfi -i "aevalsrc=0:s=${samplerate}:c=${channels}:d=${seconds_at_start}" \
-i "${input_movie}" \
-f lavfi -i "color=color=${color}:s=${width}x${height}:r=${framerate}:sar=${sar}:d=${seconds_at_end}" \
-f lavfi -i "aevalsrc=0:s=${samplerate}:c=${channels}:d=${seconds_at_end}" \
-filter_complex "[0:v:0][1:a:0][2:v:0][2:a:0][3:v:0][4:a:0]concat=n=3:v=1:a=1[v][a];\
[a]asetpts=PTS+${audio_offset}/TB[a1]" \
-map '[v]' -map '[a1]' -shortest -c:v v210 -r:v "${framerate}" -metadata:s:v:0 timecode="${timecodeout}" -metadata:s:v:0 encoder="Uncompressed 10-bit 4:2:2" -c:a "${audiocodecname}" -ac "${channels}" -ar "${samplerate}" -y "$output_dir/${name%.*}${suffix}.mov"
shift
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment