На днях занимался генерацией превьюшек для фильмов. Почти все современные ТВ умеют смотреть фильмы по сети через DLNA сервис, мой же, с пропатченной прошивкой, смотрит фильмы, которые расшарены через самбу(
Samba). Превьюшки телек генерит неумело и кадр выбирает как попало, к тому же хранит их у себя в памяти, которой не очень-то и много.
Итак, задача нагенерить jpeg-файлов. Особенность в том, что расширение jpeg-файла должно быть размером соответсвующего ему видеофайла, который поделили на 1000. Если размер больше 4Гб, то надо сначала вычесть 2
32 из размера, а потом делить. Думал, писать программку на C++, но подумалось,что скриптовые языки тоже не зря придумали. Результатом стали два скрипта на bash, которые можно видеть в конце.
Для геренации превьюшек существует небольшой опенсорс проект —
FFMpegThumbnailer. Интересен он тем, что там реализован алгоритм выбора удачного кадра. В отличие от тех сложных идей, с которыми приходилось встречаться ранее, вроде поиска лица, кожи и т.п., тут реализована очень простая идея. Считается гистограмма по сотне кадров и усредняется. Потом выбирается кадр, гистограмма которого наиболее близка к средней. Работает алгоритм на удивление хорошо.
Скрипт генерации одной превьюшки:
#!/bin/bash
# gen_th.sh
FILENAME=$1
# get file size in bytes
printf "$FILENAME\t"
FILESIZE=$(stat -c%s "$FILENAME" 2>/dev/null)
if [ $? -ne 0 ] ; then
echo "[FAIL]" # no file or access denied
exit 1
fi
# generate file extension, so Samsung TV could use thumbnail
if [ $FILESIZE -lt 4294967296 ] ; then
EXT=$(( $FILESIZE / 1000 ))
else
EXT=$(( ($FILESIZE - 4294967296) / 1000))
fi
NEWFN="${FILENAME%.*}.$EXT"
if [ -f "$NEWFN" ] ; then
echo "[SKIP]" # already exist
exit 3
else
ffmpegthumbnailer -s230 -cjpeg -i"$FILENAME" -o"$NEWFN" 2>/dev/null
if [ $? -eq 0 ] ; then
echo "[OK]"
exit 0
else
echo "[FAIL]"
exit 1
fi
fi
Генерация сразу для кучи файлов рекурсивно (используется предыдущий):
#!/bin/bash
# gen_all.sh
# Absolute path to this script. /home/user/bin/foo.sh
SCRIPT=$(readlink -f "$0")
# Absolute path this script is in. /home/user/bin
SCRIPTPATH=`dirname "$SCRIPT"`
FAILED=0
OK=0
SKIPPED=0
count=0
# set custom delimiter for the strings
IFS=$'\n'
# process each file
for NAME in $(find $1/ -type f -regex ".*\.\(avi\|mkv\|ts\)$")
do
"$SCRIPTPATH/gen_th.sh" "$NAME"
ecode=$? # keep exit code here because every command will change $?
if [ "${ecode}" -eq "1" ] ; then let "FAILED+=1"; fi
if [ "${ecode}" -eq "0" ] ; then let "OK+=1"; fi
if [ "${ecode}" -eq "3" ] ; then let "SKIPPED+=1"; fi
let "count+=1"
done
# display results
echo "Total files processed: $count"
echo "Skipped: $SKIPPED"
echo "Failed: $FAILED"
echo "Images generated: $OK"
Все исходные коды проекта доступны на
GitHub.