#!/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