Вещание онлайн-видео с помощью nginx

776px-Nginx-battleship.svgЧто такое онлайн-видео?

Под термином онлайн-видео я понимаю длительное вещание какого-то живого видеосигнала (к примеру, из телестудии). Традиционные средства отдачи видео (flv- и mp4-стриминг) в данном случае не работают, просто потому что файла, содержащего весь видеопоток, не существует.

В этой статье речь будет идти не об организации видеохостинга, а об организации видеовещания в прямом эфире. Это две принципиально разные задачи, и обычно способы их решения существенно отличаются друг от друга.

RTMP-протокол

RTMP — Real Time Messaging Protocol (вики) — протокол, который обычно используется для раздачи живого видео- и аудиоконтента клиентам. Он удобен тем, что в AS3 есть его поддержка из коробки, требует не слишком много ресурсов на клиенте и поддерживает множество плюшек (например, трансляцию с переменными битрейтами и переключение клиентов на более высокое качество при наличии свободного канала).

NB: Помимо RTMP существует набор других протоколов вещания медиапотоков (RTSP, Apple HTTP Live Streaming и др.), но в этой статье они не рассматриваются.

Протокол RTMP — детище компании Adobe. Единственным официальным сервером, которым можно вещать RTMP-поток, является Adobe Flash Media Server. Его цена и производительность, к сожалению, оставляют желать лучшего, поэтому различными разработчиками были предприняты попытки создать более или менее совместимые альтернативные реализации протокола. К сожалению, у RTMP-протокола есть известные проблемы с лицензированием, к примеру, его официальная спецификация, если следовать ей строго, не позволяет написать работающий RTMP-сервер. Тем не менее, существует несколько реализаций:

  • Red5 — один из первых RTMP-серверов, написан на Java
  • Wowza — проприетарный RTMP-сервер, написан на Java. Помимо RTMP, поддерживает также RTSP, Apple HLS, и Smoothstreaming (Silverlight).
  • erlyvideo — свободный RTMP-сервер с отдельно распространяющимися проприетарными модулями, написан на Erlang. Проект пишется русскими программистами и активно развивается.

Java тормозит

В тестах, которые я проводил, Red5 и Wowza показали неприлично низкую производительность. При мегабитном видеопотоке Wowza при 1000 зрителей онлайн съедала уже около 300% процессорного времени (Intel Xeon E5607). Если требуется вещать хотя бы для 20000 человек онлайн, то нужно закупать 20 серверов? Это слишком дорого.

Что же делать?

Использовать неблокирующие операции. Тормоза в Wowza и Red5 следуют из-за далеко не самой оптимальной схемы обработки событий. Для реализации действительно быстрого стримингового сервера, нужно использовать эффективный метод обработки событий (для linux это epoll). Именно такую схему работы и реализовал Роман Арутюнян (блогgithub-профильrarutyunyan) в своём RTMP-сервере, реализованном как модуль к nginx.

nginx-rtmp-module

Достоинства:

  • Нереально шустрый. На том же физическом сервере, который я использовал для тестов Wowza, nginx выдержал 2500 мегабитных соединений на ядро, т.е. 10000 на весь сервер целиком.
  • Удобные конфиги :). После километровых XML-конфигов Wowza эти выглядят спасением.
  • Отзывчивость автора к фичреквестам.

Недостатки:

  • Проект молодой, наличествуют баги, которые, впрочем, оперативно исправляются.
  • Небольшая функциональность. Сервер вещает только в RTMP, перекодировка появилась буквально несколько дней назад, имеет статус экспериментальной и фактически является обёрткой над ffmpeg. UNIX-way во всей своей красе.
  • Нет многопоточности. Модуль может работать только в том случае, если nginx запускается с одним воркером. Для утилизации всех процессорных ядер нужно запускать несколько воркеров на разных IP-адресах и/или портах.

Многопоточность можно реализовать с помощью примерно такого костыля (Ubuntu):

    for ip in $(cat /etc/network/interfaces | grep address | awk '{print $2}') ; do
        touch /etc/nginx/nginx.$ip.conf
        cp /etc/nginx/nginx.conf.skel /etc/nginx/nginx.$ip.conf
        sed -i "s/%IPADDR%/${ip}/g" /etc/nginx/nginx.$ip.conf
        /usr/sbin/nginx -c /etc/nginx/nginx.$ip.conf
    done

При этом у вас должен быть написан скелет конфига с указанием %IPADDR% вместо IP-адреса. Например, такой:

worker_processes  1;

error_log   logs/error.%IPADDR%.log debug;

pid /var/run/nginx.%IPADDR%.pid;

worker_rlimit_nofile 65536;

events {
    worker_connections  16384;
}

rtmp {
        server {
                listen %IPADDR%:1935;
                chunk_size 4000;
                application live {
                        live on;
                        pull live stream %masterIP%;
                }
        }
}

http {
        server {
                listen %IPADDR%:8080;
                location /stat {
                        rtmp_stat all;
                        rtmp_stat_stylesheet stat.xsl;
                }
                location /stat.xsl {
                        root /srv/nginx/html;
                }
        }
}

Впрочем, автор обещает реализовать нормальную многопоточность в будущих релизах.

С помощью nginx-rtmp-module мне удалось полностью утилизировать 10-гигабитный канал. При этом основной проблемой стала вовсе не прожорливость самого nginx, а необходимость тюнинга сетевой карты и параметров ядра, чтобы software interrupts не съедали 100% CPU.

Ссылки по теме:

RTMP на Википедии
Wowza — официальный сайт
Erlyvideo — официальный сайт
Nginx-rtmp-module — проект на GitHub

Установка и настройка Wowza media server 2.2.4 и JW Player на Debian

wowza

Установка сервера

Топаем на оф сайт и качаем DEB версию. Пока качается ищем ключик (или покупаем…)

Установка самого сервера проста

sudo chmod +x WowzaMediaServer-2.2.4.deb.bin
sudo ./WowzaMediaServer-2.2.4.deb.bin

Т.к. требуется Java, ставим

apt-get install sun-java6-jre

Запускаем сервер

/etc/init.d/WowzaMediaServer start

 

Настройка сервера для вещания

Переходим в папку

cd /usr/local/WowzaMediaServer/content

Создаем папку для вещания, что типа плейлиста

mkdir simplevideostreaming

В папку content нужно будет класть ваше видео, либо сделать симлинк на content с вашим видео, и создать там папку simplevideostreaming.

 

Настройка плеера JW Player

Идем на оф сайт нажимаем Download JW Player, снимаем птички, ничего не заполняем, тыкаем Download Now. Плеер скачивается.

Распаковываем архив и кладем на сервер.

Пример для вещания

Кладем видео  video.flv в папку /usr/local/WowzaMediaServer/content

В папке которую мы распаковывали на сервер создаем тестовый html и вносим такие строки

<object id="player" style="display: block; margin-left: auto; margin-right: auto;" width="512" height="288" data="player.swf" type="application/x-shockwave-flash">
<param name="data" value="player.swf" />
<param name="name" value="player" />
<param name="allowfullscreen" value="true" />
<param name="allowscriptaccess" value="always" />
<param name="flashvars" value="streamer=rtmp://ВАШ_САЙТ:1935/simplevideostreaming&amp;file=video.flv&amp;image=preview.jpg&amp;provider=rtmp" />
<param name="src" value="player.swf" />
</object>

Подробнее:

streamer означает что видео будет потоковое, а не из файла

ВАШ_САЙТ — вписываем ваш URL  сайта где крутится сервер  Wowza

simplevideostreaming — это папка-плейлист который создавали в после установки сервера.

video.flv и preview.jpg — собственно видео и превью которое показывается до запуска видео.

Сохраняем и открываем, получаем такое…

jwplaeer-300x171

К плееру можно прикрутить переключение в HD, шарилку на Facebook и прочие плагины. Их можно найти тут. Если нужно бесплатно есть на трекерах.

 

P.S. Суть установки Wowza media server для меня была в перемотки длинных видео, т.к приходилось ждать пока все видео прогрузится. Здесь же промотка происходит как на YouTube с любого места.