to do

1. добавить вывод даты/времени в начале конвертирования каждого файла. бывает, что handbrake зависает и непонятно долго ли он уже мурыжит этот файл.

3. Сделать проверку/сравнение длительности потока исходного и конечного файла. Просто я столкнулся с тем, что в отсутствие кодеков, handbrake создает файл без видеопотока, но ошибок не сообщает.

ffprobe videofile.avi -v error -select_streams 0 -show_entries stream=duration

4. Сделать проверку и исправление исходного файла, в случае, когда не совпадает длительность потока.
5.Сделать автоматическое определение необходимого уровня качества, в зависимости от разрешения и частоты кадров потока. https://handbrake.fr/docs/en/latest/workflow/adjust-quality.html . Для ролика 1920*1080*60 мне кажется хорошим значение параметра -q=24. Битрейт в этом случае составляет 9-10 мегабит в секунду. При больших значниях - становятся заметны артефакты (на паузе на границах объектов, при воспроизведении - меньше). Короче - надо тестировать.

Для чего

Мне захотелось оптимизировать свой видеоархив при помощи кодека h265, который позволяет существенно сэкономить место на диске практически без потери качества видеоматериалов.

Применяемые средства

Для конвертации я буду использовать HandBrakeCLI под Ubuntu 16.04.
Устанавливать HandBrakeCLI лучше из репозитория разработчиков. Версия, которая есть в репозиториях Ubuntu 16.04 старая и некорректно обрабатывает звук (он просто пропадает после конвертации).
Также понадобится ffmpeg для определения кодека (чтобы повторно не конвертировать файлы уже сконвертированные в h265) и работы с данными EXIF.

sudo add-apt-repository ppa:stebbins/handbrake-releases
sudo apt-get update
sudo apt-get install handbrake-cli ffmpeg

Описание скрипта

Скрипт адаптирован к именам файлов и папок, содержащим пробелы.
Скрипт формирует список файлов в папке и вложенных папках по типу MIME - video.
Затем, у каждого файла проверяется текущий видеокодек и если он не HEVC (h265), то файл проверяется на наличие ошибок и если все все хорошо - конвертируется. Конвертированный файл кладется с именем оригинального файла на то же место, где лежал оригинальный файл.
После конвертации в файле меняется значение EXIF-аттрибута creation_date на значение извлеченное из оригинального файла.
В качестве бонуса подсчитывается количество сэкономленного места.
Для работы нужно задать параметры - папку с исходными файлами, папку куда будут положены исходные файлы после конвертации, а также количество потоков для HandBrakeCLI, чтобы система оставалась юзабельной во время конвертации.

#!/bin/bash

srcdir="/home/AUTOSYS/mike/Downloads/paan/"
oldfilesdir=`dirname "$srcdir"`/Unconverted_Video_`basename "$srcdir"`
filelist=`find $srcdir -type f -exec file -N -i -- {} + | sed -n 's!: video/[^:]*$!!p'`
logfile=$oldfilesdir/convertation_`date +"%d.%m.%y_%H-%M"`.log
threads=3
quality=30

mkdir $oldfilesdir
oldsize=0; newsize=0; filesleft=0; corruptedfiles=0
filesleft=`echo "$filelist" | wc -l`
echo $filesleft "video files detected" | tee -a $logfile
while read -r file
do
echo "FILE - $file" | tee -a $logfile
echo "ffprobe -show_format \"$file\" 2>&1 | grep Video: | grep hevc" | /bin/bash 1>/dev/null 2>/dev/null
if [ $? -eq 0 ]; then echo "This File is already in HEVC (h265)" | tee -a $logfile
else
        echo "Checking file for errors..." | tee -a $logfile
        echo "ffmpeg -i \"$file\" -v error -f null - 2>/dev/null 1>/dev/null" | /bin/bash 1>/dev/null 2>/dev/null
        if [ $? -ne 0 ]; then echo "File corrupted. Skipping..." | tee -a $logfile; (( corruptedfiles++ ))
        else
        filedir=`dirname "$file"`
        filesize=`du -k "$file" | cut -f1`
        filename=`basename "$file"`
        creationtime=`echo "ffprobe \"$file\" 2>&1 | grep -m 1 creation_time | sed -n -e 's/^.*creation_time\ *:\ *//p'" | /bin/bash`
        oldsize=$(( oldsize + filesize ))
        mkdir --parents "$oldfilesdir"/"$filedir"
        mv "$file" "$oldfilesdir"/"$filedir"
        echo "HandBrakeCLI -i \"$oldfilesdir\"/\"$file\" -o \"$filedir\"/\"$filename\" -e x265 -q $quality -E av_aac \
        --custom-anamorphic --keep-display-aspect -O -x threads=$threads 2> /dev/null" | /bin/bash
        handbrakereturn=$?
        if [ "$handbrakereturn" -eq 0 ]
                then echo "Convertation Done." | tee -a $logfile
                if [ "$creationtime" ]
                        then echo "Preserving Creation Time..." | tee -a $logfile
                        echo "ffmpeg -i \"$filedir\"/\"$filename\" -metadata:s:v:0 creation_time=\"$creationtime\" \
                        -metadata:s:a:0 creation_time=\"$creationtime\" -metadata creation_time=\"$creationtime\" \
                        -c copy \"$filedir\"/\"new_date_$filename\" 2> /dev/null" | /bin/bash
                        if [ $? -eq 0 ]; then echo "Done." | tee -a $logfile; else echo "Preservation of Creation Time metadata failed..." | tee -a $logfile; fi 
                        mv "$filedir"/"new_date_$filename" "$filedir"/"$filename"
                        else echo "Creation Time metadata not found" | tee -a $logfile
                fi
                else echo "Convertation ERROR. HandBrakeCLI Exit Code: $handbrakereturn" | tee -a $logfile
                mv "$oldfilesdir"/"$file" "$file"
        fi
        sync
        filesize=`du -k "$file" | cut -f1`
        newsize=$(( newsize + filesize ))
fi
fi
        (( filesleft-- ))
        echo $filesleft "files left to convert" | tee -a $logfile
done < <(echo "$filelist")
echo "Converted files old size - $oldsize Kb" | tee -a $logfile
echo "Converted files new size - $newsize Kb" | tee -a $logfile
echo "Saved Space - $(( $oldsize - $newsize )) Kb" | tee -a $logfile
echo "Corrupted files: $corruptedfiles" | tee -a $logfile

Вот вариант, еоторый кладет новые файлы на место старых:

#!/bin/bash

srcdir=/home/valusik/Изображения
#srcdir=/home/valusik/Изображения/test
filelist=`find $srcdir -type f -exec file -N -i -- {} + | sed -n 's!: video/[^:]*$!!p'`
logfile=$srcdir/convertation_`date +"%d.%m.%y_%H-%M"`.log
threads=3

#mkdir $oldfilesdir
oldsize=0; newsize=0; filesleft=0; corruptedfiles=0
filesleft=`echo "$filelist" | wc -l`
echo $filesleft "video files detected" | tee -a $logfile
while read -r file
do
echo "FILE - $file" | tee -a $logfile
echo "ffprobe -show_format \"$file\" 2>&1 | grep Video: | grep hevc" | /bin/bash 1>/dev/null 2>/dev/null
if [ $? -eq 0 ]; then echo "This File is already in HEVC (h265)" | tee -a $logfile
else
        echo "Checking file for errors..." | tee -a $logfile
        echo "ffmpeg -i \"$file\" -v error -f null - 2>/dev/null 1>/dev/null" | /bin/bash 1>/dev/null 2>/dev/null
        if [ $? -ne 0 ]; then echo "File corrupted. Skipping..." | tee -a $logfile; (( corruptedfiles++ ))
        else
        filedir=`dirname "$file"`
        filesize=`du -k "$file" | cut -f1`
        filename=`basename "$file"`
        creationtime=`echo "ffprobe \"$file\" 2>&1 | grep -m 1 creation_time | sed -n -e 's/^.*creation_time\ *:\ *//p'" | /bin/bash`
        oldsize=$(( oldsize + filesize ))
        echo "Creation time - \"$creationtime\"; Filesize - \"$filesize\""
        mv "$file" "$file".old
        echo "HandBrakeCLI -i \"$file\".old -o \"$file\" -e x265 -q 20 -E av_aac \
        --custom-anamorphic --keep-display-aspect -O -x threads=$threads 4> /dev/null" | /bin/bash
        handbrakereturn=$?
        if [ "$handbrakereturn" -eq 0 ]
                then echo "Convertation Done." | tee -a $logfile
                rm -f "$file".old
                if [ "$creationtime" ]
                        file_extension="${file##*.}"
                        new_date_file="$file"_new_date."$file_extension"
                        then echo "Preserving Creation Time..." | tee -a $logfile
                        preservation_time_cmd="ffmpeg -i \"$file\" -metadata:s:v:0 creation_time=\"$creationtime\" \
                        -metadata:s:a:0 creation_time=\"$creationtime\" -metadata creation_time=\"$creationtime\" \
                        -c copy \"$new_date_file\" 2> /dev/null"
                        echo $preservation_time_cmd | /bin/bash
                        if [ $? -eq 0 ]; then echo "Done." | tee -a $logfile; mv "$new_date_file" "$file"; else echo "Preservation of Creation Time metadata failed..." | tee -a $logfile; fi
                else echo "Creation Time metadata not found" | tee -a $logfile
                fi
        else
                echo "Convertation ERROR. HandBrakeCLI Exit Code: $handbrakereturn" | tee -a $logfile
                mv "$file".old "$file"
        fi
        sync
        filesize=`du -k "$file" | cut -f1`
        newsize=$(( newsize + filesize ))
fi
fi
        (( filesleft-- ))
        echo $filesleft "files left to convert" | tee -a $logfile
done < <(echo "$filelist")
echo "Converted files old size - $oldsize Kb" | tee -a $logfile
echo "Converted files new size - $newsize Kb" | tee -a $logfile
echo "Saved Space - $(( $oldsize - $newsize )) Kb" | tee -a $logfile
echo "Corrupted files: $corruptedfiles" | tee -a $logfile
Enter your comment. Wiki syntax is allowed:
 
  • linux_faq/bash_script_to_batch_convert_video_files_to_h265.txt
  • Last modified: 2019/11/15 13:00
  • by admin