Но вчера один мой друг разместил у себя в блоге скрипт, который выполняет ту же задачу при помощи mplayer'а и ImageMagick.
Идея, с помощью которой реализуется данная задача, мне очень понравилась, но реализована она в этом скрипте, на мой взгляд, довольно криво. Вот недостатки, которые я заметил, натравив данный скрипт на несколько файлов:
- Некорректно работает со многими wmv и HDTVRip видеофайлами (создает серию скриншотов из одного и того же кадра).
- Иногда захватывает на 2 кадра больше, чем нужно.
- Не умеет обрабатывать сразу несколько файлов.
- Выводит кадры так, что в одной строке всегда находятся 4 кадра, и если задать вывод нечетного числа кадров, то в конечном изображении появляются дыры.
- Нет возможности создавать скриншоты размером с кадр в фильме (на некоторых трекерах предъявляется такое требование).
Синтаксис запуска скрипта таков:
framegrabber [-n stills] [-s size] files...
где n - количество захватываемых кадров (по умолчанию 20), s - ширина каждого кадра в пикселях (по умолчанию равна ширине кадра в фильме). При формировании конечного изображения количество кадров в строке (2, 3 или 4) выбирается в зависимости от параметра s.
После запуска framegrabber -n8 -s 300 video_file вы получите примерно такой результат:
А вот собственно и сам скрипт:
#!/bin/bash #*************************************************************************** #* Copyright (C) 2007, Konishchev Dmitry * #* http://konishchevdmitry.blogspot.com/ * #* * #* Special thanks to Sergey Volkhin * #* http://damnsmallblog.blogspot.com/ * #* * #* This program is free software; you can redistribute it and/or modify * #* it under the terms of the GNU General Public License as published by * #* the Free Software Foundation; either version 3 of the License, or * #* (at your option) any later version. * #* * #* This program is distributed in the hope that it will be useful, * #* but WITHOUT ANY WARRANTY; without even the implied warranty of * #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * #* GNU General Public License for more details. * #**************************************************************************/ usage=" framegrabber -h for help" usage_describe="\n Usage : framegrabber [-n stills] [-s size] files...\n \n Framegrabber is designed to extract stills from a video that is seekable and supported by Mplayer. Framegrabber then combine them in a mosaic image allowing preview of the movie. Number of frames to extract and size of the frames can be modified via options.\n \n Framegrabber depends on Mplayer and Imagemagick\n \n Options:\n -h : print this help message\n -n : number of stills to extract (default : 20)\n -s : size of each stills (default: same as video frame size)\n \n framegrabber -n 20 -s 100 my_video will create a mosaic of 20 stills of 100 pixels each." # Выводит страницу помощи print_help() { echo -e $usage_describe } # Удаляет временные файлы cleanup() { rm $temp_dir/*.jpg 2>/dev/null rmdir $temp_dir } # Получаем параметры, заданные пользователем --> while getopts ":n:s:h" option do case $option in n ) n=$OPTARG;; s ) s=$OPTARG;; h ) print_help; exit 0;; \? ) echo "Unknown option"; echo $usage; exit 1;; * ) echo "Unknown option"; echo $usage; exit 1;; esac done # Получаем параметры, заданные пользователем <-- # Значения по умолчанию --> ((!n)) && n=20 ((!s)) && s=0 # Значения по умолчанию <-- shift $(($OPTIND - 1)) # Проверяем, передан ли хотя бы один файл --> if [ "$1" == "" ] then echo $usage exit 1 fi # Проверяем, передан ли хотя бы один файл <-- # Генерируем скриншоты для каждого переданного файла --> while [ "$1" != "" ] do temp_dir=/tmp/framegrabber_tmp_$$ old_dir=`pwd` file_path="$1" frames_num=$n frame_size=$s file_name=${file_path##*/} mkdir $temp_dir || exit 1 cd "$temp_dir" || exit 1 echo "Processing file $file_path..." # Получаем абсолютный путь --> echo "$file_path" | grep '^/' > /dev/null if [ $? -eq 1 ] then ab_file_path="$old_dir"/"$file_path" else ab_file_path="$file_path" fi # Получаем абсолютный путь <-- # Получаем продолжительность видеофайла --> seconds=`mplayer -ao null -vo null -frames 1 -identify "$ab_file_path" 2>/dev/null | \ grep ID_LENGTH= | cut -d "=" -f 2` if [ "$seconds" == "" ] then echo "mplayer error! May be \"$file_path\" is not a video file?" cleanup cd "$old_dir" shift continue fi seconds=`awk -v var="$seconds" 'BEGIN { rounded = sprintf("%.0f", var); print rounded }'` # Получаем продолжительность видеофайла <-- # Количество секунд, через которое мы будем перепрыгивать для получения очередного скриншота --> step=`expr $frames_num + 1` step=`expr $seconds / $step` step=`awk -v var=$step 'BEGIN { rounded = sprintf("%.0f", var); print rounded }'` # Количество секунд, через которое мы будем перепрыгивать для получения очередного скриншота <-- # Генерируем необходимое количество скриншотов --> is_error=0 cur_sec=$step max_image_file_name=`expr 100 + $frames_num - 1` for image_file_name in `seq 100 $max_image_file_name` do mplayer -ao null -ss $cur_sec -vo jpeg -frames 30 "$ab_file_path" > /dev/null 2>&1 mv 00000007.jpg $image_file_name.jpg 2>/dev/null if [ $? -ne 0 ] then is_error=1 break fi rm 000000??.jpg cur_sec=`expr $cur_sec + $step` done if [ $is_error -ne 0 ] then echo "mplayer error! May be \"$file_path\" is not a video file?" cleanup cd "$old_dir" shift continue fi # Генерируем необходимое количество скриншотов <-- cd "$old_dir" # Подбираем оптимальное количество кадров в строке --> if [ `expr $frames_num % 4` -eq 0 ] then hor_frames_num=4 else if [ `expr $frames_num % 3` -eq 0 ] then hor_frames_num=3 else if [ `expr $frames_num % 2` -eq 0 ] then hor_frames_num=2 else hor_frames_num=4 fi fi fi # Подбираем оптимальное количество кадров в строке <-- # Упаковываем все захваченные кадры в один файл --> if [ $frame_size -ne 0 ] then resize_option="-resize $frame_size" else resize_option="" fi montage $resize_option -geometry +2+2 -tile $hor_frames_num -quality 100 $temp_dir/*.jpg "$file_name".jpg # Упаковываем все захваченные кадры в один файл <-- cleanup # Прыгаем на следующий в списке файл shift done # Генерируем скриншоты для каждого переданного файла <-- echo "Finished"
10 комментариев:
Приветствую. За скрипт спасибо. Есть одна проблема - скриншоты получаются плохого качества, и плохо передают качество исходного видео. Подозреваю, что проблема в битрейте кадров.
Хм... А что вы подразумеваете под плохим качеством? Если размер каждого скриншота, то его вы можете задать опцией -s. В остальном же полученные скриншоты полностью соответствуют кадрам видео. Почему вы связываете качество скриншотов с битрейтом видео, я, честно говоря, не понял, но на всякий случай нашел у себя видео с очень низким битрейтом - скриншоты получились в точности такие же как и кадры.
В любом видео есть кадры хорошие, есть не очень. Во-первых, брать нужно только i-кадры, но никак не b-кадры и не p-кадры. Во-вторых - было бы неплохо анализировать их качество (идея в том, чтобы брать скриншоты в статических сценах). Потому что в динамических сценах скриншоты не показательны.
Хм, скрипт как-то с ходу не заработал. Mplayer выдает значение ID_LENGTH=5304.01, оно заносится в переменную, но скрипт почему-то говорит "mplayer error! May be "Август.avi" is not a video file?" и всё... Хоть ты тресни :(
Извиняюсь, был не прав. Собрал mplayer и imagemagick без поддержки jpeg :( Как-то проморгал этот момент :(
Спасибо, полезный скрипт
А какой софт нужно поставить для того что бы он работал нормально?
Например у меня не хватает некой программы montage. Нельзяли сразу указать какие пакеты нужно установить?
Нужны пакеты imagemagick и mplayer.
Скрипт очень поможет, но...
Как убрать из имени получаемого файла расширение видеофайла?
Заранее спасибо.
Отправить комментарий