Working with video
January 2011 5

Видеохостинг своими руками

Эта статья о некоторых технических аспектах реализации бесплатного сервиса для загрузки, хранения и просмотра видео. Будут рассмотрены вопросы настройки серверного программного обеспечения, даны примеры команд для конвертации видео и примеры кода на языке PHP.

С введением поддержки стандарта HTML5 во многих браузерах стало возможно встраивать видео-плеер при помощи тега video. Каждый браузер поддерживает определенный набор кодеков и контейнеров. Эта поддержка очень хорошо описана на странице http://diveintohtml5.org/video.html#what-works.

Одним из основных требований к системе являлась поддержка устройств Apple (iPhone, iPad, iPod). Из-за того, что эти устройства поддерживают онлайн-видео в единственном формате — MP4 и не имеют возможности использовать Flash-плеер, изначально было решено взять за основу универсальный MP4-контейнер (H.264 видео и AAC аудио). При кодировании используются бесплатные реализации этих кодеков libx264 и libfaac. Отсутствие поддержки этих форматов в других браузерах было решено компенсировать использованием Flash-плеера, который подключается автоматически в случае, если браузер пользователя не поддерживает тег video, либо поддержка невозможна из-за того, что браузер не поддерживает видео в формате MP4.

Архитектура


Архитектура системы достаточно проста и включает 2 типа серверов:
  • сервер конвертации (так же выполняющий роль сервера баз данных и веб-сервера);
  • файловый сервер, на который перемещаются конвертированные видео файлы.

image

Основные рабочие лошадки по доставке контента — файловые серверы. Идея в том, чтобы как можно скорее после конвертации переместить файл с основного сервера на файловый, чтобы избежать скачка нагрузки на сетевом интерфейсе в случае загрузки популярного видео. Для того, чтобы определить на каком сервере в данный момент находится конкретный видео-ролик, в БД имеется связывающая таблица videos_servers. На всех файловых серверах и сервере конвертации установлен модуль для трансляции потокового видео. Для перемещения файлов между серверами используется протокол NFS.

Очередь конвертации организуется при помощи сервера очередей beanstalkd (http://kr.github.com/beanstalkd/). Тесты показывают, что на шестиядерном сервере возможен запуск 30 воркеров. 30 пользователей смогут одновременно конвертировать видео без ущерба для общей производительности системы (время генерации страницы на стороне веб-сервера остаётся приемлемым). Тесты с большим числом воркеров не проводились, но имеется неплохой запас мощности и, в случае необходимости, количество воркеров может быть увеличено.

Серверное программное обеспечение


На сервере конвертации и на всех файловых серверах установлен Debian Lenny.

Программное обеспечение для обработки видео

Для конвертации видео в формат MP4 используется наиболее популярное в данный момент решение — ffmpeg (http://www.ffmpeg.org/). ffmpeg прекрасно справляется с конвертацией видео в самых разнообразных форматах и может использовать несколько ядер процессора в многоядерной системе. Для пост-обработки мы используем замечательную утилиту MP4Box из пакета gpac (http://gpac.sourceforge.net/). Пост-обработка необходима из-за того, что ffmpeg помещает “moov-атомы” (мета-информацию о видео) в конец файла, однако, чтобы пользователь имел возможность просматривать видео не дожидаясь его полной загрузки, эти атомы должны быть вначале файла. MP4Box перемещает их в начало и, кроме этого, приводит файл в соответствие со всеми стандартами, делает его пригодным для потоковой трансляции через соответствующий модуль.

$ ffmpeg -vpre videobam -y -i input.avi -s 320x240 -vcodec libx264 -acodec libfaac -threads 0 -ab 64k -b 400k -bt 500k -g 24 -r 24 temp.mp4
$ MP4Box -add temp.mp4 output.mp4

Следует заострить внимание на опции -g 24. Она определяет через сколько кадров будет сохранён каждый новый ключевой кадр (keyframe). Наличие ключевых кадров необходимо для того, чтобы пользователь мог прокручивать длинный ролик не дожидаясь его полной загрузки. Эта возможность реализуется при помощи модуля трансляции. Клиент (браузер или Flash-плеер) передаёт веб-серверу GET-параметр start, который обрабатывается модулем трансляции и означает количество секунд с которого нужно начинать проигрывание.

GET /output.mp4?start=856.733 HTTP/1.1

Кроме того, параметр -threads 0 существенно увеличит скорость конвертации указав программе на необходимость автоматически определить количество ядер процессора и использовать их в процессе работы. Важно указать необходимое количество кадров -r 24. У нас были проблемы с некоторыми роликами из-за неадекватно высокого количества кадров в секунде (в основном, это были скринкасты), для которых время конвертации было совершенно несоответствующим длительности ролика.

Для каждого видео делаются экранные снимки в определенных моментах времени, чтобы пользователь смог беглым взглядом оценить содержание ролика. Пример таких снимков можно увидеть внизу на странице http://videobam.com/tour. ffmpeg не в состоянии делать эти снимки быстро (он перематывает видео до нужного момента и лишь потом делает снимок). Для быстрого снятия снимков мы используем утилиту mplayer (http://www.mplayerhq.hu/), которая делает снимки практически моментально перемещаясь по файлу при помощи ключевых кадров.

$ mplayer -ss 00:00:04 -sstep 12 -frames 16 -vo jpeg:outdir=/tmp/pictures/ -nosound output.mp4

Следует отметить, что всё программное обеспечение собирается вручную из исходных кодов (клонируется из соответствующих систем контроля версий либо используются свежие сборки). Использовать самые новые версии из стабильных веток очень важно так как с момента исправления какого-либо бага до попадания этих исправлений в пакет выбранного вами дистрибутива Linux проходит достаточно много времени. В частности, мы столкнулись с проблемой заикающегося звука при конвертации некоторых QuickTime роликов в формат MP4. Проблема успешно решилась при помощи установки свежей версии библиотек libfaac и libfaad.

Серверные модули

Примечание: для сборки модуля h264 возможно потребуется применить патч http://pastie.org/1405286.

$ cd nginx-0.8.53
$ ./configure --add-module=../nginx_mod_h264_streaming-2.2.7/ --add-module=../ngx_http_secure_download/

Трансляция потокового видео обеспечивается модулем h264 для веб-сервера nginx (http://h264.code-shop.com/). Настройка этого модуля осуществляется очень просто:

/usr/local/nginx/conf/nginx.conf
location ~ \.mp4$ {
  mp4;
}

Перезапускаем сервер и пробуем загрузить ролик начиная с 10-ой секунды:

$ wget -O temp.mp4 “http://videobam.com/test.mp4?start=10.0”

Для защиты от копирования ссылок (хотлинкинга) мы используем модуль HTTP Secure Download (http://github.com/replay/ngx_http_secure_download). Он позволяет закодировать ссылку на видеофайл с использованием соли, установленной в настройках.

/usr/local/nginx/conf/nginx.conf
location ~* /videos {
  secure_download on;
  secure_download_path_mode file;
  secure_download_secret saltsaltsalt$remote_addr;

  if ($secure_download = "-1") {
      rewrite /expired.html break;
  }
  if ($secure_download = "-2") {
      rewrite /bad_hash.html break;
  }
  if ($secure_download = "-3") {
      return 500;
  }

  mp4;
  rewrite ^(.*)/[0-9a-zA-Z]*/[0-9a-zA-Z]*$ $1 break;
}

Ссылка на скачивание генерируется следующим образом:

public function secure_url($url)
{
  $ts = time() + 3600;
  $ts_in_hex = dechex($ts);
  $secret = 'saltsaltsalt' . $_SERVER['REMOTE_ADDR'];
  $hash = md5($url . '/' . $secret . '/' . $ts_in_hex);
  return  $url . '/' . $hash . '/' . $ts_in_hex;
}

NFS и autofs

Для работы с файловыми серверами на сервере конвертации установлен autofs. Он монтирует нужные файловые серверы по запросу. Все NFS-разделы монтируются в “мягком” режиме (soft mode), чтобы избежать зависания процесса копирования в случае, если файловый сервер вышел из строя.

/etc/auto.storage
0  :/var/www/shared/local_storage
1  -fstype=nfs,rw,async,soft,intr,timeo=20,rsize=64000,wsize=64000 f1.videobam.com:/var/storage
2  -fstype=nfs,rw,async,soft,intr,timeo=20,rsize=64000,wsize=64000 f2.videobam.com:/var/storage
3  -fstype=nfs,rw,async,soft,intr,timeo=20,rsize=64000,wsize=64000 f3.videobam.com:/var/storage
4  -fstype=nfs,rw,async,soft,intr,timeo=20,rsize=64000,wsize=64000 f4.videobam.com:/var/storage

Структура файлов и папок на всех серверах идентична, поэтому работа с файловыми серверами ведётся прозрачно при помощи подставления идентификатора сервера в шаблон пути. Важно помнить про ограничения файловой системы ext3 на количество файлов и папок в конкретной директории, все видео сохраняются в директории вида videos/a/ab/video.mp4, где “a” и “ab” — это первые буквы в названии видео.

Клиентская часть


Как уже было сказано ранее, мы используем VideoJS (http://videojs.com) для проигрывания и стилизации HTML5-видео. Кроме того, VideoJS выполняет “более умный” откат к Flash-плееру (в случае отсутствия поддерживаемого браузером видео-файла в списке источников). В качестве Flash-плеера используется flowplayer (http://flowplayer.org).

Тематические ссылки


Программное обеспечение:

beanstalkd kr.github.com/beanstalkd
VideoJS videojs.com
flowplayer flowplayer.org
ffmpeg www.ffmpeg.org
mplayer www.mplayerhq.hu
gpac (MP4Box) gpac.sourceforge.net
nginx 0.8.53 nginx.org/en
nginx h264 streaming module h264.code-shop.com
nginx http secure download github.com/replay/ngx_http_secure_download
nginx upload progress module github.com/masterzen/nginx-upload-progress-gimodule

Дополнительные материалы:

diveintohtml5.org/video.html
rob.opendot.cl/index.php/useful-stuff/ffmpeg-x264-encoding-guide
sites.google.com/site/linuxencoding/x264-ffmpeg-mapping
x264dev.multimedia.cx
rodrigopolo.com/ffmpeg/cheats.html
e-mats.org/2010/01/fixing-stuttering-audio-with-ffmpeg-and-quicktime
www.videohelp.com/tools/mp4box
+126
49.1k 529
Comments 108
Top of the day