Итак, задача нагенерить jpeg-файлов. Особенность в том, что расширение jpeg-файла должно быть размером соответсвующего ему видеофайла, который поделили на 1000. Если размер больше 4Гб, то надо сначала вычесть 232 из размера, а потом делить. Думал, писать программку на 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.