Демон конвертации видео в FLV

    Решил поделиться недавно написанным кодом демона для видеохостинга.
    Принцип демона прост. Демон смотрит в папку, куда загружаются видеофалы, и при появлении там новых, копирует в другую папку, запускает в фоне процесс конвертации, создает превьюшку, и копирует полученное видео в папку пользователя.

    Скрипт написан на bash, поэтому в режиме демона его надо запускать командой nohup ну или screen. Недостатком является отсутствие контроля нагрузки. Если загрузка файлов активная, то реальна перегрузка сервера. У нас пока этот вопрос не критичен, но тем кому такое решение не подойдет, проще всего использовать команду flock для создания очереди процессов.

    Самые важные параметры работы демона, можно указать через командную строку. Получить список команд вы можете, запустив скрипт с параметром -h.

    Обратите внимание на параметр -u. С его помощью можно указать местоположение папок пользователей, куда будет копироваться конвертированное видео. Структура папок задана жестко, и что бы её изменить, придется править скрипт. Но по умолчанию структура директорий такова: <USER_ID>/video
    То есть, в папочку video будут складываться конвертированные в формат FLV ролики.

    И еще такой момент. С помощью параметров -s и -t можно указать директорию источник и промежуточную директорию для конвертации, соответственно. Важно знать, что файл в директорию, указанную в параметре -s (по умолчанию /var/videoinput), должен загружаться с именем <USER_ID>_<FILE_ID>.<avi|mpg|3gp|...>, где <USER_ID> это ID пользователя (то есть название его папки), а <FILE_ID> — ID файла, например ID записи в БД.
    Превью будет скопирована туда же куда и файл видео, с таким же именем, но расширением png. Превью берется с 16-й секунды. В принципе, по хорошему, надо определять длину ролика (он то может быть и короче 16 сек), но это оставляю вам в качестве самостоятельной работы ;)

    Из кода ясно, но все таки опишу необходимый софт для работы скрипта:
    mencoder — собственно конвертация
    mplayer — для вырезания превью
    convert — ImageMagik утилита для ресайза превьюшки
    flvtool2 — для записи мета-информации в FLV

    #!/bin/bash

    # folder_monitor.sh
    # This is a daemon shell script for monitoring video input directory.
    #

    #определяем значения параметров по умолчанию
    SRC_DIR=/var/videoinput
    TRG_DIR=/var/videooutput
    PARAMS='-ovc lavc -lavcopts vcodec=flv:keyint=50:vbitrate=300:mbd=2:mv0:trell:v4mv:cbp:last_pred=3 -vf scale=480:360 -of lavf -oac mp3lame -lameopts abr:br=64 -srate 22050'
    OUTPUT_FORMAT='flv'
    USER_FOLDER="/usr/local/jboss/server/default/resources/files/user_folders"
    THUMBNAIL_WIDTH=175
    THUMBNAIL_HEIGHT=110

    # получаем параметры
    while getopts ":s:t:hp:u:H:W:" optname
    do
    case $optname in
    "u")
    USER_FOLDER="$OPTARG"
    ;;
    "p")
    PARAMS="$OPTARG"
    ;;
    "s")
    SRC_DIR="$OPTARG"
    ;;
    "W")
    THUMBNAIL_WIDTH="$OPTARG"
    ;;
    "H")
    THUMBNAIL_HEIGHT="$OPTARG"
    ;;
    "t")
    TRG_DIR="$OPTARG"
    ;;
    "h")
    echo "-h - help"
    echo "-W - width of thumbnail"
    echo "-H - height of thumbnail"
    echo "-p - command line params for mencoder"
    echo "-u - path to user folders"
    echo "-s - source dir"
    echo "-t - target dir"
    exit 0;
    ;;
    *)
    echo "Unknown parameter or option error with option - $OPTARG"
    exit 1;
    ;;
    esac
    done

    while :
    do
    echo "Looking dir ${SRC_DIR}...\n"
    #получаем входящие файлы видео
    FILES=$(find $SRC_DIR -type f -exec basename '{}' \;)

    #проходим по ним
    for FILE in $FILES
    do
    #парсим имя файла, получая имя папки и конечного файла
    USER_ID=$(echo $FILE | sed 's/[^0-9]/ /g' | awk '{print $1}')
    VIDEO_ID=$(echo $FILE | sed 's/[^0-9]/ /g' | awk '{print $2}')

    #запускаем в фоне команды
    (echo "Converting $FILE..."
    #забрали файл в промежуточную папку
    mv ${SRC_DIR}/${FILE} ${TRG_DIR}/${FILE}
    #вырезали превью
    mplayer -ss 16 -frames 1 -vo png -nosound ${TRG_DIR}/${FILE}
    THUMBNAIL="${USER_FOLDER}/${USER_ID}/video/${VIDEO_ID}.png"
    #переместили превью
    mv 00000001.png $THUMBNAIL
    #уменьшили до нужного размера
    convert $THUMBNAIL -resize ${THUMBNAIL_WIDTH} -gravity center -crop ${THUMBNAIL_WIDTH}x${THUMBNAIL_HEIGHT}+0+0 -quality 75 $THUMBNAIL
    #кодируем видео
    mencoder ${TRG_DIR}/${FILE} -o "${TRG_DIR}/${FILE}.${OUTPUT_FORMAT}" ${PARAMS}
    #записали метаинформацию для плеера
    flvtool2 -UP "${TRG_DIR}/${FILE}.${OUTPUT_FORMAT}"
    #удаляем исходный файл
    rm ${TRG_DIR}/${FILE}
    #и копируем сконвертированный файл в папку пользователя
    mv "${TRG_DIR}/${FILE}.${OUTPUT_FORMAT}" "${USER_FOLDER}/${USER_ID}/video/${VIDEO_ID}.${OUTPUT_FORMAT}"
    ) &
    done

    sleep 10s
    done


    С Наступающим Новым Годом!

    UPD. Продолжение статьи

    Комментарии 31

      0
      Я помню как-то писал похожий демон, только папки не сканировал, после загрузки файла пхп через сокеты передавал параметры демону и он конвентировал видео…

      А можно вообще поизврощаться, запустить конвертацию из пхп…
      echo 'Файл загружен.';
      flush();
      exec('mencoder ...');
        +1
        Хорошая статья для будущих начинаний. Добавил в букмарки!
          0
          я как-то тоже писал только на пхп. замучился с параметрами для менкодера для достижения меньшего размера и лучшего качества аж жуть…
            +1
            проверять директорию каждые 10 секунд — неправильно.
            почитайте о famd.
              +1
              Тоже занимаюсь «онлайн» конвертацией видео, но только не в flv, а в quicktime(h264) с помощью ffmpeg.
              Был написан небольшой скриптик на php и повешен в крон. Раз в 10 минут он «смотрит в базу» и если там есть новый файл — конвертирует его. Чтобы избежать одновременного запуска нескольких копий этого скриптика сделал проверку:
                      exec("ps aux | grep ffmpeg",$pslist);
                      //echo '<pre>';print_r($pslist);
                      for($i=0; $i < count($pslist); $i++)
                      {
                          $pslist[$i] = ereg_replace(" +"," ",$pslist[$i]);
                          $item = explode(" ",$pslist[$i]);
                          if(stristr($item[10],"ffmpeg")) { echo "ffmpeg running...".$item[10]; exit; }
                      }

              * This source code was highlighted with Source Code Highlighter.


              Параметры для ffmpeg можно посмотреть здесь: habrahabr.ru/blogs/mplayer/39224/ (#UPD3)
              Превью берется с 3 секунды.
                –1
                Спасибо за идею!
                При вызове этой команды бывает что она себя «индуцирует», тоесть ффмпеги не запущены а есть строка
                apache 74746 0.0 0.0 1520 724 ?? RL 2:27AM 0:00.00 grep ffmpeg
                поэтому чтобы обнаружить такую строку
                  0
                  блин, отправилось раньше
                  строка такая
                  user 74080 95.1 0.6 32732 21788 ?? R 2:09AM 0:20.81 /usr/bin/ffmpeg
                  я делаю так
                  foreach ($pslist as $r) {
                  $v=preg_split('|\s+|',$r);
                  //print_r($v);
                  if ($v[10]=='/usr/bin/ffmpeg') die();
                  }
                  0
                  выбирал между fmpeg и mencoder. Судо по ресечу, ffmpeg намного меньше форматов поддерживает
                  ну и проекту mplayer все таки больше доверия
                    +2
                    Поддерживаю. mencoder не только средство кодирования, но еще и средство распаковки\запаковки контейнеров, наложения фильтров и т.д. Да и нассчет доверия… 28к+ ревизий в svn это вам не наколенный курсач студента :)
                    0
                    и еще, расскажу такую поучительную историю. Однажды возникла задача обработки каких-то директорий, и что-то там с ними деланья. Подробностей не помню, но суть была в напряженной работе с файловой системой. После работы, попивая пиво с нашим одмином, я рассказал ему суть задачи. Ну обсудили алгоритм, вобщем обычный треп двух IT-шников. И тут он мне говорит: «Рома, я тебя своими руками придушу, если ты это все реализуешь на php». Я и не думал это делать на php, но спросил, «почему?» Он ответил: «Каждому языку свое применение»
                    И я с ним согласен.
                      0
                      > «Каждому языку свое применение»
                      Согласен, но то, что ты описывал — это в рамках пхп.
                        0
                        что именно? конвертация видео или работа с файловой системой?
                    +2
                    Спасибо.

                    И с новым годом, черт побери!
                      +1
                      Лучше будет, если заюзать inotify.

                      С Новым годом!
                        +1
                        а что помешало сделать полноценный демон с секциями start stop restart… короче по всем правилам?
                          +1
                          todo)))
                          честно говоря как то не задумался, но спасибо за замечание!
                          уточню только что то о чем вы говорите не демон а управляющий скрипт
                          +1
                          ну да, а из него уже можно делать отслеживание pid, прибивать nohup/screen, вобщем все тоже самое что вылезает в гугле на запрос «screen rtorrent as service»
                            0
                            У меня аналогичное, только смотрит через inotify и кодирует через ffmpeg, сразу вопрос на засыпку, накладываю логотип на видео, из-за чего приходится извращаться по принципу…

                            шаг 1 парсим вывод ffmpeg -i и вычисляем пропорции которые требуются для вписывания в 320x240

                            шаг 2
                            ffmpeg -i вход -b 640K -f flv -s размер -ar 22050 -y выход

                            шаг 3
                            ffmpeg -i вход -b 384K -f flv -ar 22050 -vhook '/usr/lib/vhook/imlib2.so -x «сдвиг -90px» -y 2 -i 1.png' -y выход

                            Есть возможность за один проход в отресайзить и наложить логотип в mecoder или чемнить еще?

                              0
                              на самом деле еще не хватает прохода для flvtool2, который сделает мета теги. это полезно, в частности, для произвольного позиционирования при воспроизведении.
                              0
                              Грабли: flvtool2 — подходит только для маленьких видеороликов, т.к. грузит весь файл в память, только затем начинает работать над ним.
                                0
                                Противоядие?
                                  +1
                                  см. коммент ниже ) промахнулся
                                    0
                                    спасибо. честно, ради того и запостил код что бы указали на слабые места)))
                                    С Новым годом!
                                      0
                                      Думаю, стоит сделать апдейт топика, ато все еще могут наступить на грабли
                              0
                                0
                                спасибо, полезная вещь, только думал о таком, чтобы по фтп постить файлы и видео в блог, а не каждую отдельно.
                                  +1
                                  Я сейчас применил это для жены. У неё плеер тока mpeg4 формат поддерживает. Вот сделал ей 2 папочки. В одну копируешь по сети любой формат, из другой забираешь нужный)))
                                    0
                                    Следить за папкой — хорошо конечно. Но как во время запуска удостовериться в том, что файл уже можно начинать кодить и что он на данный момент не находится в процессе заливки/копирования?

                                    Я буквально неделю назад писал кодирующего демона на руби и решил этот вопрос для себя следующим образом: видео заливается в одну папку, а сам демон смотрит в другую. Внешняя программа неспешно заливает видео в нужную папку, а потом кладет еще один пустой файлик с таким же именем туда, куда смотрит демон. Появление пустого файла демоном рассматривается как команда начинать.
                                      0
                                      команда mv выполняется в локальных ФС мгновенно. То есть файл заливается по HTTP в временную директорию, а потом мувится в нужную папку. Ну если что, можно перед кодированием делать sleep 1s
                                      0
                                      Коллеги, нужен совет! Есть видео, которое кодируется в Final Cut и на выходе мы получаем mov (h.624). ЕСть портал с плеером, способным играть flv (h.264).

                                      Вопрос, насколько гиморно заставить сервер понимать имеющийся контейнер?

                                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                      Самое читаемое