Содержание
Автоматическая конвертация видео для сайта
По данной схеме возможно автоматически конвертировать видео файлы в воспроизводимые в браузере форматы ogv
, mp4
, webm
:
- создание базы данных видео файлов
- настройка скрипта
- настройка запуска по расписанию (cron)
Создание базы данных видео файлов
- video-scheme.sql
-- Таблица с исходными видео файлами CREATE TABLE `videos` ( `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(64) NOT NULL DEFAULT '', -- название `filename` VARCHAR(255) NOT NULL DEFAULT '', -- относительный путь к исходному файлу `thumbnail` VARCHAR(255) NOT NULL DEFAULT '', -- картинка предпросмотра (создается) `datetime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- дата PRIMARY KEY (`id`), UNIQUE KEY `idx_filename` (`filename`) ) ENGINE=INNODB; -- Таблица с перекодированными видео CREATE TABLE `convert_videos` ( `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `video_id` INT(11) UNSIGNED NOT NULL, -- внешний ключ на videos `format` ENUM('ogv','mp4','webm') NOT NULL, -- формат `filename` VARCHAR(255) NOT NULL, -- относительный путь к сконвертированному файлу PRIMARY KEY (`id`), UNIQUE KEY `idx_video_format` (`video_id`,`format`) ) ENGINE=INNODB; -- Таблица с логом перекодирования CREATE TABLE `convert_log` ( `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `datetime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `action` ENUM('init','ffmpeg','other') NOT NULL, `format` ENUM('-','ogv','mp4','webm','thumbnail') NOT NULL DEFAULT '-', `src` VARCHAR(255) NOT NULL DEFAULT '', `code` SMALLINT(5) NOT NULL DEFAULT '0', `message` VARCHAR(32) NOT NULL DEFAULT '', PRIMARY KEY (`id`) ) ENGINE=INNODB;
Bash-скрипт для конвертации
- video-converting.sh
#!/bin/bash srcDir='/path/to/video/src/' destDir='/path/to/webserver/root/' destOffset='data/video/' maxDaysLeft=30 videoFormats='mp4 ogv webm' # action - код логирования (в т.ч. для уровня) # message - текст # code - результат (0 - как правило, успех) function log() { addslashes "$1" action=$addslashes addslashes "$2" format=$addslashes addslashes "$3" src=$addslashes addslashes "$4" message=$addslashes addslashes "$5" code=$addslashes query="INSERT INTO convert_log (action, format, src, message, code) VALUES ('$action', '$format', '$src', '$message', '$code')" mysql -u$dbuser -p$dbpass -h$dbhost $dbname -e "$query" } function getVideoInfo() { videoId=$1 query="SELECT filename FROM videos WHERE id = $videoId" filename=`mysql -s -N -u$dbuser -p$dbpass -h$dbhost $dbname -e "$query"` md5 $filename } function convertVideo() { videoId=$1 format=$2 getVideoInfo $videoId if [ -f "$destDir$destOffset$md5.$format" ]; then log "other" "$format" "$filename" "File already exists" 1 return fi # различные параметры кодирования # -b - видеобитрэйт # - ab - аудиобитрэйт # - threads - количество потоков # - qscale - качество (1 - макс, 255 - мин) # -y - перезапись видео case "$format" in "ogv") echo y | ffmpeg -i "$srcDir$filename" -mbd rd -flags +ilme+ildct -trellis 2 -cmp 2 -subcmp 2 -g 300 -b 2500k -ab 192k -threads 8 -y "$destDir$destOffset$md5.$format" ;; "mp4") echo y | ffmpeg -i "$srcDir$filename" -mbd rd -flags +ilme+ildct -trellis 2 -cmp 2 -subcmp 2 -g 300 -b 2500k -ab 192k -threads 8 -vcodec libx264 -y "$destDir$destOffset~$md5.$format" qt-faststart "$destDir$destOffset~$md5.$format" "$destDir$destOffset$md5.$format" rm -f "$destDir$destOffset~$md5.$format" ;; *) echo y | ffmpeg -i "$srcDir$filename" -mbd rd -flags +ilme+ildct -trellis 2 -cmp 2 -subcmp 2 -g 300 -qscale 1 -ab 192k -threads 8 -y "$destDir$destOffset$md5.$format" ;; esac result=$? if [ "$result" != "0" ]; then rm "$destDir$destOffset$md5.$format" else query="INSERT INTO convert_videos (video_id, format, filename) VALUES ($videoId, '$format', '$destOffset$md5.$format')" mysql -s -N -u$dbuser -p$dbpass -h$dbhost $dbname -e "$query" fi log "ffmpeg" "$format" "$filename" "Make video" "$result" } function makeThumbnail() { # ffmpeg -i ../data/video-src/intro.avi 2>&1 | grep -o -P "(?<=Duration: ).*?(?=,)" # ffmpeg -i ../data/video-src/intro.avi -vf "thumbnail" -frames:v 1 thumb.png videoId=$1 getVideoInfo $videoId echo y | ffmpeg -i "$srcDir$filename" -qscale 1 -ss 00:00:5.000 -f image2 -vframes 1 -y "$destDir$destOffset$md5.jpg" result=$? if [ "$result" != "0" ]; then rm "$destDir$destOffset$md5.jpg" else query="UPDATE videos SET thumbnail = '$destOffset$md5.jpg' WHERE id = $videoId" mysql -s -N -u$dbuser -p$dbpass -h$dbhost $dbname -e "$query" fi log "ffmpeg" "thumbnail" "$filename" "Make thumbnail $filename" "$result" } # EXECUTION START cd $(dirname $(readlink -f $0)) source bash-lib/common.sh source bash-lib/db_config.sh amIAlone if [ $? = "1" ]; then echo 'Script is already running' exit 1 fi if [ ! -d "$srcDir" ]; then log "init" "-" "-" "Can not open source dir $srcDir" 1 exit 2 fi if [ ! -d "$destDir$destOffset" ]; then log "init" "-" "-" "Can not open dest dir $destDir$destOffset" 1 exit 2 fi # Thumbnails query="SELECT id FROM videos WHERE thumbnail = '' AND datetime >= ADDDATE(NOW(), INTERVAL -$maxDaysLeft DAY) LIMIT 10 " videoIds=`mysql -s -N -u$dbuser -p$dbpass -h$dbhost $dbname -e "$query"` if [ -n "videoIds" ]; then for videoId in $videoIds; do makeThumbnail "$videoId" done fi # получаем для каждого формата имя файла, который еще не был сконвертирован for format in $videoFormats; do query="SELECT id FROM videos WHERE id NOT IN ( SELECT videos.id FROM videos JOIN convert_videos ON (videos.id = convert_videos.video_id) WHERE format = '$format' ) AND datetime >= ADDDATE(NOW(), INTERVAL -$maxDaysLeft DAY) LIMIT 10 " videoIds=`mysql -s -N -u$dbuser -p$dbpass -h$dbhost $dbname -e "$query"` if [ -n "videoIds" ]; then for videoId in $videoIds; do convertVideo "$videoId" "$format" done fi done
- bash-lib/common.sh
function addslashes() { addslashes=`echo "$1" | sed "s/'/\\\\'/g"` } function md5() { md5=`echo -n "$1" | /usr/bin/md5sum | cut -f1 -d" "` } # проверка на наличие уже запущенной копии function amIAlone() { lock_file=`pwd`"/.tv_lock" do_exit() { RETURN_VALUE=$? rm -f "$lock_file" exit $RETURN_VALUE } lockfile -r 0 "$lock_file" || return 1 trap do_exit EXIT return 0 }
- bash-lib/common.sh
dbname='data_base_name' dbuser='db_user' dbpass='db_password' dbhost='db_host'
Настройка скрипта
bash-lib/common.sh
- параметры подключения к БД.
video-converting.sh
:
Параметр | Описание |
---|---|
srcDir | абсолютный путь к исходным файлам с видео |
destDir | абсолютный путь к конечным файлам с видео |
destOffset | относительный путь - будет записан в БД и выводиться на сайте |
maxDaysLeft | количество дней, в течение которых данный файл будет обрабатываться |
videoFormats | конечные видео-форматы |
Запуск по расписанию
Данный скрипт возможно повесить на cron:
*/2 * * * * /path/to/script/video-converting.sh > /dev/null 2>&1
Не следует беспокоиться об одновременном запуске нескольких копий - в скрипте есть проверка.
Полезные опции ffmpeg
Проверка на ошибки / повреждения видеофайла:
ffmpeg -v error -i example.mov -f null -