#!/bin/bash
|
|
function displayHelp {
|
|
echo -e "Encode If Needed is a warper for FFmpeg to encode upon some conditions."
|
|
echo -e "USAGE: ein [OPTION] [INPUT]"
|
|
echo -e "DESCRIPTION:"
|
|
echo -e "By default, FFmpeg encode a file regardless of the fact that the"
|
|
echo -e "original and selected codec are the same. Although it may be be a"
|
|
echo -e "desired outcome, it can lead to unnecessary operations losing time"
|
|
echo -e "and quality."
|
|
echo -e "This script allow the user to specified a desired codec for audio"
|
|
echo -e "and video, only if either of those are not present an encoding will be"
|
|
echo -e "triggered."
|
|
echo -e "Example if the desired codecs are aac/h264 and the source file is wmav2"
|
|
echo -e "/h264 then the file will be encoded with aac and the h264 stream copied."
|
|
echo -e "Warning, by default no output is set, use the \"-d\" option or specify"
|
|
echo -e "the output file with \"-o\"."
|
|
echo -e "Errors generated by FFmpeg will be put in [INPUT].error.txt"
|
|
echo -e "[INPUT] can be one or multiple file(s) or directory(ies)."
|
|
echo -e "OPTION:"
|
|
echo -e "-a\tDesited audio codec like aac."
|
|
echo -e "-v\tDesited video codec like aac."
|
|
echo -e "-b\tArgument pass to FFmpeg if the audio codec specified by \"-a\""
|
|
echo -e "\tdon't match."
|
|
echo -e "-b\tArgument pass to FFmpeg if the video codec specified by \"-a\""
|
|
echo -e "\tdon't match."
|
|
echo -e "-d\tOptional output directory for the encoded file(s)."
|
|
echo -e "\tThe original filename will be used."
|
|
echo -e "\tMake sure the directory exist and that you have write access."
|
|
echo -e "-e\tUsed with \"-d\" to specified the container output file."
|
|
echo -e "\tBy default mkv will be used."
|
|
echo -e "-k\tOptional directory for original files kept \"as is\"."
|
|
echo -e "-f\tOptional directory for original files processed."
|
|
echo -e "-q\tReduce the verbosity."
|
|
echo -e "-h\tDisplay this help."
|
|
echo -e "EXAMPLE:"
|
|
echo -e "\t-a aac -b \"-c:a aac -b:a 48k\" \\"
|
|
echo -e "\t-v h264 -u \"-c:v libx264 -crf 23\" \\"
|
|
echo -e "\t-d /tmp/ \\"
|
|
echo -e "\t[FILE]"
|
|
echo -e "Will result in the encoding of the file(s) [FILE] if either their audio"
|
|
echo -e "codec is not \"aac\" or their video codec is not \"h264\". The result"
|
|
echo -e "encoded file(s) (if created) will have the same name as the original(s)"
|
|
echo -e "and be placed in the \"/tmp\" folder."
|
|
}
|
|
|
|
#"codec" will always matching thus allowing to specified only audio or video codec
|
|
audioCodecDesired="codec"
|
|
videoCodecDesired="codec"
|
|
audioParameter=""
|
|
videoParameter=""
|
|
outputDirectory=""
|
|
outputExtension="mkv"
|
|
goodAsIsDirectory=""
|
|
processedDirectory=""
|
|
optionalParameter=""
|
|
verbose=1
|
|
fileCount=0
|
|
errorCount=0
|
|
directoryCount=0
|
|
unencodedCount=0
|
|
|
|
no_args=1
|
|
while getopts a:v:b:u:d:e:o:k:f:qh option
|
|
do
|
|
case $option in
|
|
(a)
|
|
audioCodecDesired=$OPTARG;;
|
|
(v)
|
|
videoCodecDesired=$OPTARG;;
|
|
(b)
|
|
audioParameter=$OPTARG;;
|
|
(u)
|
|
videoParameter=$OPTARG;;
|
|
(d)
|
|
outputDirectory=$OPTARG;;
|
|
(e)
|
|
outputExtension=$OPTARG;;
|
|
(k)
|
|
goodAsIsDirectory=$OPTARG;;
|
|
(f)
|
|
processedDirectory=$OPTARG;;
|
|
(o)
|
|
optionalParameter=$OPTARG;;
|
|
(q)
|
|
verbose=0;;
|
|
(h)
|
|
(*)
|
|
displayHelp
|
|
exit;;
|
|
esac
|
|
no_args=0
|
|
done
|
|
shift $((OPTIND -1))
|
|
|
|
function processFile {
|
|
basename=$(basename "$@")
|
|
verbose $basename
|
|
errorFile="$basename.error.txt"
|
|
#Retrieve audio and video codec for the first stream of each
|
|
aCodec=$(ffprobe -select_streams a:0 -show_entries stream=codec_name -i "$@" -v error|head -n 2|tail -n 1)
|
|
vCodec=$(ffprobe -select_streams v:0 -show_entries stream=codec_name -i "$@" -v error|head -n 2|tail -n 1)
|
|
|
|
prefix="codec_name="
|
|
|
|
verboseAudio=$(echo -e "\t"$aCodec | sed -e "s/$prefix/Audio /")
|
|
verboseVideo=$(echo -e "\t"$vCodec | sed -e "s/$prefix/Video /")
|
|
|
|
encode=0
|
|
ffmpegCmd=""
|
|
if echo $aCodec|grep --quiet $audioCodecDesired; then
|
|
ffmpegCmd=$ffmpegCmd" -c:a copy"
|
|
verboseAudio=$verboseAudio" -> copy"
|
|
else
|
|
ffmpegCmd=$ffmpegCmd" "$audioParameter
|
|
encode=1
|
|
verboseAudio=$verboseAudio" -> "$audioCodecDesired
|
|
fi
|
|
if echo $vCodec|grep --quiet $videoCodecDesired; then
|
|
ffmpegCmd=$ffmpegCmd" -c:v copy"
|
|
verboseVideo=$verboseVideo" -> copy"
|
|
else
|
|
ffmpegCmd=$ffmpegCmd" "$videoParameter
|
|
encode=1
|
|
verboseVideo=$verboseVideo" -> "$videoCodecDesired
|
|
fi
|
|
|
|
verbose "$verboseAudio"
|
|
verbose "$verboseVideo"
|
|
|
|
if [[ $encode == 1 ]]; then
|
|
#Add optional arguments passed by user
|
|
if [ ! -z "$optionalParameter" ]; then
|
|
ffmpegCmd="$ffmpegCmd $optionalParameter"
|
|
fi
|
|
#Add directory "-d" if selected
|
|
if [ ! -z "$outputDirectory" ]; then
|
|
ffmpegCmd="$ffmpegCmd $outputDirectory/${basename%.*}.$outputExtension"
|
|
fi
|
|
|
|
verbose "\tffmpeg arguments:"$ffmpegCmd
|
|
|
|
FFREPORT=file="$errorFile":level=24
|
|
ffmpeg -hide_banner -i "$@" $(echo "$ffmpegCmd")
|
|
|
|
if [ -f "$errorFile" ]; then
|
|
errorCount=$((errorCount+1))
|
|
fi
|
|
|
|
# 2> "$basename".error.txt
|
|
if [ ! -z "$processedDirectory" ]; then
|
|
mv "$@" "$processedDirectory/" -v
|
|
if [ -f "$errorFile" ]; then
|
|
mv "$errorFile" "$processedDirectory/" -v
|
|
fi
|
|
fi
|
|
else
|
|
verbose "\tKeep original source."
|
|
unencodedCount=$((unencodedCount+1))
|
|
if [ ! -z "$goodAsIsDirectory" ]; then
|
|
mv "$@" "$goodAsIsDirectory/" -v
|
|
fi
|
|
fi
|
|
}
|
|
|
|
#Process user input that could be a file, a directory or anything really.
|
|
function processInput {
|
|
verbose "Input \"$@\""
|
|
if [ -d "$@" ]; then
|
|
directoryCount=$((directoryCount+1))
|
|
for inputInDir in "$@"/*; do
|
|
processInput "$inputInDir"
|
|
done
|
|
fi
|
|
if [ -f "$@" ]; then
|
|
fileCount=$((fileCount+1))
|
|
processFile "$@"
|
|
fi
|
|
}
|
|
|
|
function verbose {
|
|
if [[ $verbose == 1 ]]; then
|
|
echo -e "$@"
|
|
fi
|
|
}
|
|
|
|
if [[ $no_args == 1 ]]; then
|
|
displayHelp
|
|
else
|
|
verbose "Configuration:"
|
|
verbose "\tAudio codec desired="$audioCodecDesired
|
|
verbose "\tVideo codec desired="$videoCodecDesired
|
|
verbose "\tAudio parameter="$audioParameter
|
|
verbose "\tVideo parameter="$videoParameter
|
|
verbose "\tOptional parameter="$optionalParameter
|
|
verbose "\tDirectory encoded file="$outputDirectory
|
|
verbose "\tEncoded file extension="$outputExtension
|
|
verbose "\tDirectory processed file="$processedDirectory
|
|
verbose "\tDirectory unmodified file="$goodAsIsDirectory
|
|
verbose "Number of inputs "$#
|
|
|
|
if
|
|
([ $audioCodecDesired = "codec" ] && [ $videoCodecDesired = "codec" ]) ||
|
|
([ -z "$audioParameter" ] && [ -z "$videoParameter" ])
|
|
then
|
|
echo "At least one codec must be choosed."
|
|
exit
|
|
fi
|
|
|
|
for input in "$@"; do
|
|
processInput "$input"
|
|
done
|
|
|
|
#Display statistics
|
|
message="Processed "$fileCount" file"
|
|
if [ $fileCount -gt 1 ]; then
|
|
message=$message"s"
|
|
fi
|
|
if [ $directoryCount -gt 0 ]; then
|
|
message=$message" in $directoryCount director"
|
|
if [ $directoryCount -gt 1 ]; then
|
|
message=$message"ies."
|
|
else
|
|
message=$message"y."
|
|
fi
|
|
fi
|
|
encodedCount=$((fileCount-unencodedCount))
|
|
if [ $encodedCount -gt 0 ]; then
|
|
message=$message"\n"$encodedCount" encoded."
|
|
fi
|
|
if [ $unencodedCount -gt 0 ]; then
|
|
message=$message"\n"$unencodedCount" kept \"as is\"."
|
|
fi
|
|
if [ $errorCount -gt 0 ]; then
|
|
message=$message"\n"$errorCount" error"
|
|
if [ $fileCount -gt 1 ]; then
|
|
message=$message"s"
|
|
fi
|
|
message=$message" reported by FFmpeg."
|
|
fi
|
|
verbose $message
|
|
fi
|