Онлайн вещание через Nginx-RTMP: несколько готовых рецептов

    Недавно я наткнулся на топик "Сервер онлайн-вещаний на базе nginx" о замечательном модуле Романа Арутюняна (@rarutyunyan) для nginx: nginx-rtmp-module. Модуль очень прост в настройке и позволяет на основе nginx создать сервер публикации видеозаписей и живого вещания.

    Про сам модуль можно прочитать на его странице на GitHub, я же хочу привести несколько простых примеров использования. Надеюсь, топик поможет новичкам в видеоделах (таким как я).


    Коротко об RTMP


    RTMP (Real Time Messaging Protocol) — проприетарный протокол вещания от Adobe. В качестве транспорта по умолчанию используется TCP (порт 1935). Также можно инкапсулировать RTMP в HTTP (RTMPT). Клиент RTMP — это в первую очередь Adobe Flash Player.
    Кодек видео — H.264, кодек аудио AAC, nellymoser или MP3, контейнеры MP4 или FLV.

    Публикация видеозаписи


    Иначе говоря, видео по запросу (VOD). Просто добавьте в nginx.conf в секцию rtmp { server {… }}.
    application vod {
         play /var/videos;
      }
    


    (Прим.: конечно, секцию не обязательно называть vod)
    Теперь можно положить в папку /var/videos видеофайл в правильном формате и «скормить» плееру источник, например rtmp://server/vod/file.flv. Насколько я понял, MP4 нативно поддерживает перемотку видео, а FLV придется индексировать отдельно.

    Все приведенные далее примеры будут уже про «живую» трансляцию с помощью ffmpeg под Windows. Впрочем, эта информация будет полезна и для пользователей Linux.

    Онлайн-трансляция


    Мы можем отправить поток видео и аудио на сервер используя все тот же протокол RTMP для публикации. А наши клиенты смогут трансляцию смотреть. Для этого на сервере надо добавить секцию:

    application live {
         allow publish 1.2.3.4;
         allow publish 192.168.0.0/24;
         deny publish all;
         allow play all;
         live on;
      }
    


    Рекомендую сразу закрыть доступ на публикацию всем, кроме доверенных IP, как показано в примере.

    На машине, с которой мы будем вещать, для начала надо получить список устройств DirectShow. Пуск — Выполнить — cmd, переходим в папку ffmpeg/bin и запускаем:
    ffmpeg -list_devices true -f dshow -i dummy


    Если в названии вашего источника есть русские буквы, то они могут отобразиться кракозябрами. ТруЪ админы заюзают iconv, а простые парни вроде меня раскодируют бяку на сайте Лебедева. FFmpeg'у нужно скормить читабельную надпись.

    Теперь, зная имя видео и аудио источника, можно захватить его при помощи ffmpeg и отправить на сервер.

    Веб-камера


    Как минимум нужно указать источник видео, кодек и сервер:
    ffmpeg -f dshow -i video="Webcam C170" -c:v libx264 -an -f flv "rtmp://1.2.3.4/live/test.flv  live=1"


    Вместо «Webcam C170» нужно подставить название вашей камеры из списка.
    Ключ -an говорит о том, что мы не передаем аудио поток. Если аудио поток нужен, то строка запуска будет выглядеть примерно так:
    ffmpeg -f dshow -i video="Webcam C170" -f dshow -i audio="Микрофон ..." -c:v libx264 -c:a libfaac -ar 44100 -ac 2 -f flv "rtmp://1.2.3.4/live/test.flv  live=1"

    Здесь мы использует кодек libfaac, частота дискретизации 44100, 2 канала (стерео). Можно вместо AAC использовать MP3 (кодек libmp3lame).

    image

    Аналоговая камера


    Если у вашей камеры аналоговый выход, то ее можно подключить к компьютеру с помощью устройства захвата. Я использую дешевую PAL камеру и USB плату захвата с Dealextreme.

    ffmpeg -r pal -s pal -f dshow -i video="USB2.0 ATV" -c:v libx264 -an -f flv "rtmp://1.2.3.4/live/test.flv live=1"


    image

    Захват экрана


    Тут есть два варианта: установить FFSplit или использовать screen-capture-recorder с FFmpeg.
    FFSplit использовать проще, т.к. у него есть удобный GUI, но он не работает под XP/2003.

    Если вы решили выбрать второй способ, то строка запуска FFmpeg будет выглядеть примерно так:
    ffmpeg -f dshow -i video="screen-capture-recorder" -c:v libx264 -an -r 2 -f flv "rtmp://1.2.3.4/live/test.flv live=1"

    Аудио-поток можно захватить с virtual-audio-capturer.

    image
    Пример захвата экрана в приложении

    Ретрансляция


    Естественно, вы можете ретранслировать видео или аудио файл (или поток) FFmpeg на сервер. В примере ниже мы передаем MJPEG видео с удаленной камеры:
    ffmpeg -f mjpeg -i video="http://iiyudana.miemasu.net/nphMotionJpeg?Resolution=320x240&Quality=Standard" -c:v libx264 -f flv "rtmp://1.2.3.4/live/test.flv live=1"

    Но для таких целей более разумно использовать опцию push на самом RTMP-сервере, чтобы исключить промежуточное звено и вытягивать поток на самом сервере.

    image
    Какая-то веб-камера в Японии

    Тюнинг, решение проблем



    -preset имя У H.264 есть несколько наборов настроек соотношения компрессия/скорость: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow. Поэтому если вы хотите повысить производительность, стоит использовать:
    -preset ultrafast 

    -crf число непосредственно влияет на битрейт и качество. Принимает значения от 0 до 51 — чем больше, тем ниже качество картинки. По умолчанию 23, 18 — losless качество. Битрейт примерно удваивается при уменьшении CRF на 6.

    -r число задает входной и выходной FPS. Для источников, с которых вы захватываете картинку, можно установить вместо -r -re, чтобы использовать «родной» FPS.

    -rtbufsize число размер буфера реального времени. Если у вас постоянно появляются сообщения о переполнении буфера и отбрасывании кадров, вы можете поставить большой буфер (например, 100000k), однако это может увеличить задержку передачи.

    -pix_fmt задает цветовую модель. Если у вас вместо картинки показывается черный квадрат, а звук работает, попробуйте поставить yuv420p или yuv422p.

    -s ширинаxвысота входной и выходной размер картинки.

    -g число насколько я понял, это максимальное число кадров между ключевыми. Если у вас FPS очень маленький, то можно поставить это значение поменьше, чтобы уменьшить задержку начала трансляции.

    -keyint_min число минимальное число кадров между ключевыми.

    -vf «crop=w:h:x:y» обрезать видео

    -tune zerolatency «волшебная» опция уменьшения задержки трансляции. Что она конкретно делает я так и не нашел (-:

    -analyzeduration 0 отключает анализ длительности, что помогает снизить задержку трансляции

    Помимо рассмотренных выше параметров аудио вам может понадобиться -acodec copy в том случае, если ваш аудио поток не требует дополнительной перекодировки в MP3/AAC.

    Пример: вещаем с веб-камеры с низкой задержкой без звука, рисуем в верхней части картинки текущее время

    ffmpeg -r 25 -rtbufsize 1000000k -analyzeduration 0 -s vga -copyts -f dshow -i video="Webcam C170" -vf "drawtext=fontfile=verdana.ttf:fontcolor=yellow@0.8:fontsize=48:box=1:boxcolor=blue@0.8:text=%{localtime}" -s 320x240 -c:v libx264 -g 10 -keyint_min 1 -preset UltraFast -tune zerolatency -crf 25 -an -r 3 -f flv "rtmp://1.2.3.4:1935/live/b.flv live=1"


    Плеер на сайте


    Тут все просто. Поставьте на свой сайт один из популярных плееров, например Flowplayer или JW Player.

    Пример подключения JW Player вы можете посмотреть на странице демо трансляции.

    Что дальше?


    С помощью модуля rtmp можно создать не только видеотрансляцию, но и видеочат, интернет-радио, простую платформу для вебинаров. Дерзайте!

    Я рассмотрел лишь базовую функциональность nginx-rtmp-module и ffmpeg. Возможности у них гораздо шире, поэтому обратите внимание на документацию:
    Блог nginx-rtmp-module
    Wiki nginx-rtmp-module
    Документация FFmpeg
    Streaming Guide
    x264 Encoding Guide
    Filtering Guide

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

      0
      Сразу скажу, что ffmpeg — не единственное решение. Но, например, с VLC у меня так ничего и не получилось: поддержка RTMP там пока экспериментальная.
        0
        И плюсом есть какие-то проблемы с HLS у модуля, по крайней мере live и просмотр hls на ipad у меня не пошло почему то.
        Еще бы авторам модуля неплохо было-бы добавить запись не только в flv, но и в mp4/x264/aac
          +1
          С HLS полный порядок. Недавно я реализовал нативную поддержку HLS, теперь библиотеки ffmpeg не нужны для сборки с HLS.
            0
            Угу попробую еще, у меня когда просто плейлист в Тегеран video стоит циклилось по кругу кусок начала трансляции. Может я что то не понял, конечно. Кстати просьба добавить куда нить в статус номер версии модуля
          +2
          nginx-rtmp не поддерживает RTMPT, что очень печально, т.к. часть клиентов (особенно в организациях) ходят в интернет через прокси, которая об RTMP ничего не знает.
            0
            Как быть с мобильными клиентами, которые не поддерживают flash?
              +1
              Android и iPhone могут проигрывать HLS, который nginx-rtmp умеет вещать. Правда, сам я не пробовал, т.к. у меня допотопный смартфон.
              0
              А какие есть решения для записи с камеры через веб-страницу (flash, html5)?
                0
                Старые версии JWPlayer это умели, в исходниках на гитхабе он идет комплектом в примерах.
                +1
                У нас трансляция ведется с обычного компьютера, и адрес там динамический. Поэтому написал такой скрипт:
                #!/bin/bash
                PUBLISER_IP=$(echo $SSH_CLIENT | grep -o "^\S*")
                cp /usr/local/nginx/conf/nginx.conf.bone /usr/local/nginx/conf/nginx.conf
                sed -i "s/%PUBLISHER_IP%/$PUBLISER_IP/g" /usr/local/nginx/conf/nginx.conf
                killall nginx-rtmp
                /usr/local/nginx/sbin/nginx-rtmp
                


                Соответственно в конфиге-заготовке nginx.conf.bone в директиве allow publish %PUBLISHER_IP%; подменяется текст на адрес, с которого был залогинен клиент по SSH. Затем на всякий случай сносим nginx-rtmp со старым конфигом, и запускаем его заново.

                Сам скрипт запускается по SSH, который в свою очередь авторизуется по ключу, чтобы девочкам не нужно было ничего водить. Они просто запускают ярлычок на рабочем столе, и все.

                Кстати, победить нормальное вещание веб-камеры через ffmpeg так и не удалось, поэтому я тупо настроил Wirecast. Хоть он и избыточен для задачи, но у него есть возможность обращаться к командам из вне (кажется он подключается как COM).
                Так как я быдлокодер, то смог победить только подключение по JS.
                var wirecast = new ActiveXObject("Wirecast.Application"); 
                if (wirecast) {
                	var doc = wirecast.DocumentByName ("MyDocument", 2)
                	var layer = doc.LayerByIndex(1)
                	layer.ActiveShotID = doc.ShotIDByName('MainCamera', 2)
                	layer.Go()
                	
                	doc.Broadcast('start');
                } 
                
                


                Само собой этот скрипт работает только из-под IE, и для того, чтобы не нужно было ничего тыкать в браузере дополнительно, необходимо html-файл добавлять в доверенные сайты, а для последних позволять запуск ActiveX без спроса. MyDocument — название ранее сохраненного в Wirecast пресета, а MainCamera название шота, который будет транслироваться.
                Вообще можно настроить таким образом автоматическую смену камер, и прочие плюшки Wirecast, API позволяет многое.
                  0
                  А как насчет ARM-донглов? есть поддержка? Будут проблемы?
                    0
                    Что именно вы имеете в виду? Работает ли nginx на arm?
                    0
                    Можно ли использовать предложенную вами USB плату захвата как микшерский пульт? Поясню: собираемся сделать конференцию в 4х залах, хотелось бы транслирвоать в сеть не 4 потока, а миксованные записи самых интересных выступлений. Но прерывания канала не должно быть. Как выход нашли только видеопульт за сумму свыше 100 тыс. рублей, подача с него видеосигнала на плату захвата. А в вашей плате я заметил сразу 4 входа, нет возможности протестировать? Может она будет решением и для нашего случая
                      0
                      Та плата имеет только 1 канал захвата видео. Но в можете купить 4 платы, так как они стоят просто копейки, а видео миксовать через Wirecast, например. Главное, чтобы компьютер справлялся с 4 потоками.
                        0
                        Ну если 4 канала одновременно записывать не надо, а только переключаться, то такая штука подойдет.
                        Мы делали через нее трансляцию конференции, когда у нас дорогая плата захвата отказалась работать.
                        Но под Windows 7 x64 на ней почему-то работает только канал №2 — дрова кривые.
                        vasiliy, какую ОС вы хотите использовать?
                          0
                          ОС могу использовать ту, под которой эта штука заведется. Каналы действительно записывать не надо, просто нужно переключиться на определенную камеру в определенный момент времени и подать картинку в поток. Так как вход для аудио здесь один, то думаю это решить каким нибудь ручным переключателем.
                            0
                            Товарищ автор, а не на х64 оно у вас завелось с переключением по каналам? Прямо с ffmpeg? Поведайте, пожалуйста!
                            У нас сейчас остро стоит вопрос с этими девайсинами: никак не выходит подружить их с компьютером и, тем более, с ffmpeg.
                        0
                        Что делает параметр live=1?
                          0
                          Я так понимаю, что он нужен при онлайн-вещании.
                            0
                            У меня и без него с вебкамеры и с сетевой вещало, я поэтому и спрашиваю. Есть документ, описывающий все параметры?
                              0
                              ffmpeg вроде librtmp юзает, поэтому опции эти можно посмотреть в man librtmp.
                              Возможно, эта опция ничего и не меняет в нашем случае, можно не заморачиваться.
                                0
                                О, похоже то, что нужно.

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

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