Ffmpeg wrapper for batch conversion

Hi,
I was fiddling around with ffmpeg video conversion because my storage capacity for movies it nearly full.
So I’ve put together a bash script that will find every file in the current directory and every subdirectory (except some subtitles for examle) and then pass them to ffmpeg with some default values - nothing too fancy. Output movie file is stored in a new directory _converted with an optional ffmpeg log file.
Use -h argument for help.

Perhaps someone will find it useful as well.

The script - click here
#!/bin/bash

dir=$(pwd)

# default storage locations
out_dir="_converted"
out_log="${out_dir}/_log"

# error output storage
err_file="_00000_ERROR_conversion.log"
rm -f "${dir}/${err_file}"

# default values
height=480                  # maximal pixel height of converted video
crf=24                      # video quality
aa='-map 0:a? -c:a copy'    # audio mapping
ss='-map 0:s? -c:s copy'    # subtitles mapping
log=1                       # default true

# print help
usage() {
    echo "Usage: $0 [-hf:t:P:q:sal]
	-h ........... \"this help\"
	-f <val> ..... \"from time - format hh:mm:ss\"
	-t <val> ..... \"to time - format hh:mm:ss (make sure f<t)\"
	-P <val> ..... \"pixel height (default ${height}p)\"
	-q <val> ..... \"video quality as crf (default ${crf}; 0=lossless, 51=worst)\"
	-s ........... \"no subtitles\"
	-a ........... \"no audio\"
	-l ........... \"no conversion logging\"
	" 1>&2; exit "$1"; }

# parse command line arguments
while getopts "hf:t:P:q:sal" arg; do
	case "${arg}" in
		h)
			usage 0
			;;
		f)
			f="-ss ${OPTARG}"
			;;
		t)
			t="-to ${OPTARG}"
			;;
		P)
			height="${OPTARG}"
			;;
		q)
		    crf="${OPTARG}"
		    ;;
		s)
			ss=''
			;;
		a)
			aa=''
			;;
		l)
		    log=0
		    ;;
		*)
		    usage 1
		    ;;
	esac
done


# find all files and get rid of all already converted and some non-video files
# then for each file make the conversion
find "${dir}" -type f                                                   |\
grep -Evie "^.*(${out_dir}).*$"                                         |\
grep -Evie '^.*\.(txt|srt|sub|log|i?nfo|rar|zip|7z)$'                   |\
sort -Vf                                                                |\
while read file; do

    # create storage directories
	mkdir -p "${file%/*}/${out_dir}"
    [[ log -eq 1 ]] && mkdir -p "${file%/*}/${out_log}"

    # get file name for further processing
    printf "${file}"
    filename=${file##*/}

    # log storage file from the ffmpeg output
    if [[ log -eq 1 ]]; then
        log_file="${file%/*}/${out_log}/${filename%.*}_${height}p.log"
    else
        log_file="/dev/null"
    fi

    # conversion time measurement
    TIME_START=$(date +%s%N)

    # the conversion itself
    ffmpeg  -y -i "${file}"                                                                     \
            ${f}                                                                                \
            ${t}                                                                                \
            -map 0:v? -c:v libx265 -crf ${crf} -vf scale="trunc(oh*a/2)*2:min(${height}\,ih)"   \
            ${aa}                                                                               \
            ${ss}                                                                               \
            "${file%/*}/${out_dir}/${filename%.*}_${height}p.mkv"                               \
            2> "${log_file}" < /dev/null

    # store which files return with an error code
	if [ $? -ne 0 ]; then
        echo "${file}" >> "${dir}/${err_file}"
	fi

    # conversion time measurement
	TIME_STOP=$(date +%s%N)
	printf "\t\tdone: %.2f s\n" "$(echo "(${TIME_STOP}-${TIME_START})/1000000000" | bc -l | sed -e "s/,/\./g")"
done

# print all files that had a problem with the conversion
if [[ -f "${err_file}" ]]; then
    echo -e "\n\nconversion errors:"
    cat "${err_file}"
fi
2 Likes