NGINX + nginx-rtmp-module — трансляция видео с веб-сервера

Thank you for reading this post, don't forget to subscribe!

Веща­ние видео будет осу­ществ­лять­ся с помо­щью моду­ля для nginx — nginx-rtmp-module.

Для это­го необ­хо­ди­мо собрать веб-сер­вер nginx из исход­ни­ков, вклю­чив выше­на­зван­ный модуль.

RTMP - про­то­кол пере­да­чи пото­ко­во­го видео, напри­мер с видео­ре­ги­стра­то­ра или напря­мую с каме­ры. Рас­шиф­ро­вы­ва­ет­ся как Real Time Messaging Protocol. Раз­ра­бо­тан ком­па­ни­ей Adobe.

RTMP актив­но исполь­зу­ет­ся для транс­ля­ции видео в каче­стве веб-кон­тен­та (на сай­те). Это воз­мож­но бла­го­да­ря, напри­мер, веб-сер­ве­ру NGINX в связ­ке с моду­лем nginx-rtmp-module — захва­ты­ва­ем меди­а­кон­тент по RTSP с исполь­зо­ва­ни­ем коде­ка ffmpeg и кон­вер­ти­ру­ем его в пото­ко­вое видео.

В каче­стве кли­ен­тов (пле­е­ров), при­ни­ма­ю­щих поток, мож­но использовать:

  • Adobe Flash Player.
  • JW Player.
  • Uppod.

Ино­гда, оши­боч­но пола­га­ют, что поток мож­но при­ни­мать с помо­щью извест­ной про­грам­мы VLC. На самом деле, это не так — дан­ный пле­ер не уме­ет рабо­тать с RTMP напря­мую. Одна­ко, мож­но захва­ты­вать видео при помо­щи ути­ли­ты rtmpdump и пере­да­вать его на VLC.

По умол­ча­нию, про­то­кол рабо­та­ет на пор­ту 1935, транс­порт осу­ществ­ля­ет­ся с исполь­зо­ва­ни­ем TCP.

Еще немно­го об RTMP на Википедии

Сборка NGINX + nginx-rtmp-module

Для удоб­ства рабо­ты с nginx, сна­ча­ла мы уста­но­вим его из паке­тов, хотя бы, что­бы созда­лись скрип­ты автозапуска.

Установка nginx и пакетов для сборки

Настра­и­ва­ем репозиторий:

vi /etc/yum.repos.d/nginx.repo

[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1

yum install nginx pcre-devel openssl-devel

Сборка из исходников

Смот­рим вер­сию уста­нов­лен­но­го пакета:

nginx -v

Теперь пере­хо­дим по ссыл­ке https://nginx.org/download и копи­ру­ем ссыл­ку на уста­нов­лен­ную вер­сию nginx (архив tar.gz). В моем слу­чае, это была вер­сия 1.10.0.
* обра­ти­те вни­ма­ние, что в дан­ном спис­ке вер­сии идут не по поряд­ку — ори­ен­ти­руй­тесь по дате (сред­няя колонка).

Ска­чи­ва­ем исходник:

wget http://nginx.org/download/nginx-1.10.0.tar.gz

Ска­чи­ва­ем модуль:

wget https://github.com/arut/nginx-rtmp-module/archive/master.tar.gz

Рас­па­ко­вы­ва­ем исход­ник nginx и модуль:

tar xzf nginx-1.10.0.tar.gz
tar xzf master.tar.gz

И пере­хо­дим в рас­па­ко­ван­ный ката­лог nginx:

cd nginx-1.10.0

Смот­рим, с каки­ми опци­я­ми собран уже уста­нов­лен­ный nginx:

nginx -V

Копи­ру­ем текст, кото­рый идет после configure arguments:

Теперь кон­фи­гу­ри­ру­ем nginx со ско­пи­ро­ван­ны­ми опци­я­ми + --add-module=../nginx-rtmp-module-master. Полу­чить­ся что-то на вроде:

./configure --with-cc-opt='-g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_v2_module --with-http_sub_module --with-http_xslt_module --with-stream --with-stream_ssl_module --with-mail --with-mail_ssl_module --with-threads --add-module=../nginx-rtmp-module-master

Соби­ра­ем исходник:
make

И выпол­ня­ем установку:
make install

Запус­ка­ем веб-сервер:
systemctl start nginx

Настройка захвата видео

Если исполь­зу­ет­ся бранд­мау­эр, не забы­ва­ем доба­вить в раз­ре­ше­ния tcp порт 1935.

Установка утилит

Ubuntu:

apt-get install ffmpeg rtmpdump

CentOS:

Уста­нав­ли­ва­ем рас­ши­рен­ный репо­зи­то­рий паке­тов EPEL:

yum install epel-release

Тянем допол­ни­тель­ный репозиторий:

rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm

Теперь мож­но уста­нав­ли­вать пакеты:

yum install ffmpeg rtmpdump

Настройка NGINX

Откры­ва­ем на редак­ти­ро­ва­ние сле­ду­ю­щий файл:

vi /etc/nginx/nginx.conf

И допи­сы­ва­ем следующее:

[codesyntax lang="php" blockstate="collapsed"]

[/codesyntax]

* важ­но, что­бы дан­ный блок шел не внут­ри, а отдель­но от основ­но­го http.

Пере­за­гру­жа­ем сервис:

systemcl restart nginx

На дан­ном эта­пе мы настро­и­ли про­стей­ший rtmp-сер­вер, кото­рый смо­жет при­ни­мать запро­сы на пере­да­чу видео.

Что­бы про­ве­рить его рабо­ту, вос­поль­зу­ем­ся ранее уста­нов­лен­ной ути­ли­той ffmpeg:

ffmpeg -i rtsp://admin:admin@192.168.0.12:554/Streaming/Channels/1/ -c copy -f flv rtmp://127.0.0.1/cam1/stream

* где admin:admin — логин и пароль на под­клю­че­ние к веб-каме­ре; 192.168.0.12 — IP-адрес каме­ры; cam1 — имя application, кото­рое мы зада­ли в кон­фи­гу­ра­ци­он­ном фай­ле nginx; stream — про­из­воль­ное назва­ние для потока.

В под­твер­жде­ние пра­виль­но­го выпол­не­ния коман­ды, мы уви­дим что-то наподобие:

frame= 1381 fps= 26 q=-1.0 size=   27586kB time=00:00:55.27 bitrate=4088.6kbits/
frame= 1394 fps= 26 q=-1.0 size=   27822kB time=00:00:55.79 bitrate=4085.1kbits/
frame= 1407 fps= 26 q=-1.0 size=   28131kB time=00:00:56.31 bitrate=4092.5kbits/
frame= 1420 fps= 26 q=-1.0 size=   28371kB time=00:00:56.83 bitrate=4089.6kbits/
frame= 1433 fps= 26 q=-1.0 size=   28609kB time=00:00:57.35 bitrate=4086.5kbits/
frame= 1446 fps= 26 q=-1.0 size=   28852kB time=00:00:57.87 bitrate=4084.1kbits/

Теперь мож­но запу­стить при­ло­же­ние вос­про­из­ве­де­ния видео, напри­мер, VLC пле­ер и под­клю­чить­ся к веб-сер­ве­ру (Медиа - Открыть URL):

 

Вво­дим URLrtmp://192.168.0.100/cam1/stream

* где 192.168.0.100 — IP-адрес сер­ве­ра nginx; cam1 — наш application; stream — наше про­из­воль­ное назва­ние для потока.

Если мы уви­дим видео с каме­ры, зна­чит все настро­е­но верно.

Теперь пре­ры­ва­ем рабо­ту ffmpeg и откры­ва­ем кон­фиг nginx:

vi /etc/nginx/nginx.conf

И добав­ля­ем следующее:

[codesyntax lang="php" blockstate="collapsed"]

[/codesyntax]

Пере­за­пус­ка­ем nginx:
systemctl restart nginx

И сно­ва, но уже не запус­кая вруч­ную ffmpeg, про­ве­ря­ем нали­чие видео­по­то­ка при помо­щи VLC.

Несколько камер

Откры­ва­ем nginx.conf:

vi /etc/nginx/nginx.conf

Настра­и­ва­ем авто­ма­ти­че­ское опре­де­ле­ние воркеров:

worker_processes auto;

* опти­маль­ное чис­ло одно­вре­мен­ных пото­ков, поз­во­лит nginx рабо­тать быстрее.

В корень кон­фи­га добавляем:

rtmp_auto_push on;

* вклю­ча­ет локаль­ные ретранс­ля­ции для исполь­зо­ва­ния несколь­ких воркеров.

Теперь пере­хо­дим к настрой­кам rtmp и при­во­дим наш кон­фиг к сле­ду­ю­ще­му виду:

[codesyntax lang="php" blockstate="collapsed"]

[/codesyntax]

его мож­но так­же настро­ить так:

[codesyntax lang="php" blockstate="collapsed"]

[/codesyntax]

Или так:

[codesyntax lang="php" blockstate="collapsed"]

[/codesyntax]

И пере­за­пус­ка­ем nginx:

systemctl restart nginx


Запись

Для хра­не­ния видео на сер­вер, есть так­же несколь­ко вари­на­тов настройки.

1-й вари­ант: исполь­зо­ва­ние несколь­ких application. В каж­дом из них своя пап­ка для хра­не­ния видео:

[codesyntax lang="php" blockstate="collapsed"]

[/codesyntax]

Созда­ем папки:

mkdir /tmp/record1 /tmp/record2

Зада­ем пра­ва (вла­дель­ца):

chown nginx:nginx /tmp/record*

2-й вари­ант: один application с раз­ны­ми име­на­ми для потоков:

[codesyntax lang="php" blockstate="collapsed"]

[/codesyntax]

Необ­хо­ди­мо так­же создать пап­ку и задать владельца:

mkdir /tmp/record
chown nginx:nginx /tmp/record

и не забы­ва­ем пере­за­гру­зить nginx:

systemctl restart nginx

Полезные опции для записи

record_suffix -%Y-%m-%d-%H-%M-%S.flv;
record_max_size 5120K;
record_interval 3m;

record_suffix — добав­ля­ет окон­ча­ние к каж­до­му создан­но­му файлу.
record_max_size — огра­ни­чи­ва­ет раз­мер каж­до­го фай­ла опре­де­лен­ным объ­е­мом (в дан­ном при­ме­ре, 5 Мб). При лими­те, будет создан новый файл.
record_interval — огра­ни­чи­ва­ет файл видео­фраг­мен­том в несколь­ко минут (в нашем при­ме­ре, 3).

HLS

Преж­де, чем начать, убе­ди­тесь, что бранд­мау­эр отклю­чен или про­пус­ка­ет http-запро­сы. Selinux на момент про­ве­де­ния тестов, луч­ше отключить.

Про­то­кол HLS поз­во­ля­ем транс­ли­ро­вать пото­ко­вое видео поверх HTTP. Это поз­во­лит сэко­но­мить ресур­сы сер­ве­ра при мно­же­ствен­ном обра­ще­нии и создать более крос­сплат­фор­мен­ную инфраструктуру.

Для его вклю­че­ния, при­во­дим наш nginx.conf к сле­ду­ю­ще­му виду:

[codesyntax lang="php" blockstate="collapsed"]

[/codesyntax]

Пере­за­пуск:

systemctl restart nginx

Ждем 4-5 секунд и смот­рим содер­жи­мое папок в /tmp:

ls /tmp/cam1
ls /tmp/cam2

Внут­ри каж­дой из них мы долж­ны уви­деть файл с рас­ши­ре­ни­ем m3u8 — это плей­лист с видео­на­рез­ка­ми. Если фай­лы есть, зна­чит HLS заработал.

Оста­лось научить наш NGINX отда­вать дан­ные фай­лы. Для это­го в сек­ции http добавим:

[codesyntax lang="php" blockstate="collapsed"]

[/codesyntax]

И сно­ва:

systemctl restart nginx

В том же VLC для про­вер­ки вво­дим сле­ду­ю­щий URL:

http://192.168.0.100/cam1/stream.m3u8

MPEG-DASH

Как аль­тер­на­ти­ва HLS, исполь­зу­ет­ся для видео­транс­ля­ции поверх HTTP. Его основ­ные пре­иму­ще­ства — под­держ­ка со сто­ро­ны боль­шо­го коли­че­ства бра­у­зе­ров и рабо­та на javascript-плеере.

И так, его настрой­ка силь­но напо­ми­на­ет настрой­ку HLS. В кон­фи­ге NGINX:

[codesyntax lang="php" blockstate="collapsed"]

[/codesyntax]

* обра­ти­те вни­ма­ние, здесь мы реши­ли настро­ить все в одном application с раз­ны­ми пото­ка­ми для каж­дой каме­ры. И не пото­му, что так нуж­но для MPEG-DASH — ско­рее для демон­стра­ции воз­мож­но­сти раз­лич­ных спо­со­бов конфигурации.
** так­же мож­но заме­нить, что мы доба­ви­ли опции кон­вер­та­ции пото­ка при пере­во­де его в RTMP — это важ­но для MPEG-DASH.

Пере­за­пус­ка­ем nginx:

systemctl restart nginx

Про­ве­ря­ем появ­ле­ние фай­лов с рас­ши­ре­ни­ем .mpd.

ls /tmp/cams

Если они есть, пере­хо­дим в /tmp

cd /tmp

И выпол­ня­ем сле­ду­ю­щую команду:

git clone https://github.com/arut/dash.js.git

* мы ска­ча­ли js-пле­ер для про­смот­ра dash-видео.
** по хоро­ше­му, в про­дук­тив­ной сре­де сле­ду­ет создать отдель­ный вир­ту­аль­ный домен и хра­нить все фай­лы в спе­ци­аль­ной выде­лен­ной дирек­то­рии, а не в ката­ло­ге /tmp. Для теста это не принципиально.

И созда­ем новую вет­ку live:

cd dash.js
git checkout live

Про­ве­рим рабо­ту пле­е­ра. Откры­ва­ем бра­у­зер и вво­дим сле­ду­ю­щий URL:

http://192.168.0.100/dash.js/baseline.html

* где 192.168.0.100 — IP-адрес наше­го видео-сервера.

И нажи­ма­ем play — нач­нет­ся показ демон­стра­тив­но­го видео.

Теперь откро­ем файл baseline.html внут­ри пап­ки dash.js:

vi /tmp/dash.js/baseline.html

Най­дем строчку:

url = "http://dash.edgesuite.net/envivio/dashpr/clear/Manifest.mpd",

И заме­ним ее на:

url = "http://192.168.0.100/cams/stream1.mpd",

* где cams — наш application; stream1 — имя пото­ка с пер­вой камеры.

И сно­ва откры­ва­ем бра­у­зер и вводим:

http://192.168.0.100/dash.js/baseline.html

Полезные директивы

respawn_timeout 15s;
chunk_size 8192;

respawn_timeout — вре­мя ожи­да­ния перед повтор­ным запус­ком дочер­не­го про­цес­са. По умол­ча­нию, 5 секунд.
chunk_size — мак­си­маль­ный раз­мер пор­ции для муль­ти­плек­си­ро­ва­ния пото­ка. По умол­ча­нию, 4096.

Пол­ный пере­чень дирек­тив опуб­ли­ко­ван по ссылке:

https://github.com/arut/nginx-rtmp-module/wiki/Directives