Низкая задержка при вещании стала обязательным условием любых тендеров и конкурсов на построение головных станций и сетей доставки контента (CDN). Операторы требуют от поставщиков вещательного оборудования низкую задержку повсеместно: для трансляции новостей, концертов, интервью, ток-шоу, киберспортивных соревнований и азартных игр. В этом обзоре мы разберем, какие протоколы для вещания с низкой задержкой предлагает рынок.
Виталий Сутурихин
Виталий Сутурихин
Низкая задержка при вещании стала обязательным условием любых тендеров и конкурсов на построение головных станций и сетей доставки контента (CDN). Операторы требуют от поставщиков вещательного оборудования низкую задержку повсеместно: для трансляции новостей, концертов, интервью, ток-шоу, киберспортивных соревнований и азартных игр. В этом обзоре мы разберем, какие протоколы для вещания с низкой задержкой предлагает рынок.
Что такое задержка в вещании
Это разница во времени между тем, когда конкретный видеокадр был захвачен устройством (камерой, плей-аут-сервером, кодером), и тем, когда он был проигран на экране у конечного пользователя.
Низкая задержка не должна снижать качество передачи сигнала, а это значит, что требуется минимальная буферизация при кодировании и мультиплексировании с сохранением плавной и четкой картинки на экране любого устройства. Еще одно обязательное условие — гарантированная доставка: все потерянные пакеты должны быть восстановлены, а передача в открытых сетях не должна вызывать проблем.
Компании переводят в облако все больше сервисов, чтобы сэкономить на арендуемых площадях, электроэнергии и покупке оборудования. Это повышает требования к низкой задержке с длительным временем пересылки сообщения туда и обратно (Round Trip Time — RTT). Это особенно актуально при передаче потоков с высоким битрейтом во время трансляции HD- и UHD-видео, например если облачный сервер расположен в США, а потребитель контента находится в Европе.
Протокол UDP
Первой технологией, которая активно применялась в современном телевещании и с которой связывают термин «низкая задержка», было вещание мультикаст-трафика с MPEG Transport Stream содержимым по UDP. Обычно подобный формат выбирали в закрытых ненагруженных сетях, где вероятность потери пакетов сводилась к минимуму. К примеру, вещание с кодера на модулятор на головной станции — зачастую в рамках одной серверной стойки — либо IPTV-вещание по выделенной линии с усилителями и повторителями. Подобная технология используется повсеместно и показывает отличные показатели задержки. Российские компании достигали задержки на кодирование, передачу данных и декодирование с использованием сети Ethernet не более 80 мс при 25 кадрах/с.
Скриншот 1. Измерение задержки при вещании в UDP в лаборатории.
На скриншоте 1 сверху показан сигнал с карты захвата SDI, снизу — сигнал, прошедший стадии кодирования, мультиплексирования, вещания, приема и декодирования. Как видно, второй сигнал приходит позже на одну единицу измерения (в данном случае — 1 кадр, который равен 40 мс, так как фреймрейт 25 кадров/с). Подобное решение применялось при трансляции Кубка конфедераций—2017 и чемпионата мира по футболу—2018, только ко всей архитектурной цепочке добавлялись модулятор, распределенная DVB-C-сеть и телевизор в качестве конечного устройства. Общая задержка составила 220–240 мс.
А если сигнал проходит через внешнюю сеть? Там его ждут различные испытания: помехи, шейпинг (ограничение пропускной способности, — прим. ред.), нагруженный трафиком канал, ошибки оборудования, поврежденные кабели, проблемы программного уровня. В таком случае требуется не только низкая задержка, но и переотправка потерянных пакетов.
В случае с UDP с этим неплохо справляется технология Forward Error Correction (FEC) с избыточностью (дополнительным проверочным трафиком или оверхедом). При этом неизбежно увеличиваются требования к пропускной способности сети и, следовательно, задержка и объем избыточности в зависимости от ожидаемого процента потерянных пакетов. Процент восстановленных благодаря FEC пакетов всегда лимитирован, а при передаче по открытым сетям он может существенно изменяться. Таким образом, чтобы надежно передавать большие объемы данных на большие расстояния, приходится добавлять к ним десятки процентов избыточного трафика.
Протокол TCP
Рассмотрим технологии, которые базируются на протоколе TCP. Если контрольная сумма полученного пакета не соответствует ожидаемому значению, выставленному в заголовке TCP-пакета, то этот пакет отправляется повторно. А если на стороне клиента и сервера не поддерживается спецификация Selective Acknowledgment (SACK), то происходит переотправка всей цепочки TCP-пакетов с потерянного и до последнего полученного на сниженной скорости.
Ранее, когда было нужно обеспечить низкую задержку при вещании в прямом эфире, протокола TCP избегали, поскольку в его случае задержка вырастала из-за проверки на ошибки, пересылки пакетов, трехстороннего рукопожатия, «медленного старта» и предотвращения переполнения канала (TCP Slow Start и Congestion Avoidance Phase). При этом задержка до начала передачи даже при широком канале может достигать пятикратной круговой задержки (RTT), а увеличение пропускной способности влияет на задержку крайне незначительно.
Также приложения, которые вещают по TCP, не получают полную обратную связь по состоянию соединения (таймауты, размеры окна для перевещания), поскольку передача идет единым сплошным потоком, и прежде чем выдать ошибку, приложение может зависнуть на неопределенное время. А протоколы верхнего уровня не имеют возможности тюнинга ТСP для минимизации проблем вещания.
При этом существуют протоколы, которые эффективно работают поверх UDP даже в открытых сетях и на длительные расстояния. Давайте рассмотрим и сравним различные реализации протоколов. Из форматов передачи данных, которые базируются на TCP, выберем RTMP, HLS и CMAF, а из базирующихся на UDP — WebRTC и SRT.
Протокол RTMP
Являлся проприетарным протоколом Macromedia (ныне принадлежит Adobe) и был очень популярен, когда приложения на базе Flash пользовались успехом. Имеет несколько разновидностей с поддержкой шифрования TLS/SSL и даже вариаций на базе UDP — RTFMP (Real Time Media Flow Protocol, использовался для соединений точка-точка). RTMP разбивает поток на фрагменты, размер которых может динамически меняться. Внутри канала пакеты, которые относятся к аудио и видео, могут чередоваться и мультиплексироваться.
RTMP формирует несколько виртуальных каналов, по которым передаются аудио, видео, метаданные и др. Большинство CDN уже не поддерживают RTMP как протокол для раздачи трафика конечным клиентам. Однако у Nginx (веб-сервер и почтовый прокси-сервер, — прим. ред.) есть собственный модуль с поддержкой простого RTMP-протокола, который работает поверх TCP и по умолчанию использует порт 1935. Nginx может выступать в качестве RTMP-сервера и раздавать контент, который он получает от RTMP-стримеров. Кроме того, RTMP по-прежнему пользуется популярностью для доставки трафика до CDN, а в дальнейшем трафик передается по другим протоколам.
Сегодня технология Flash устарела: браузеры либо сокращают ее поддержку, либо полностью блокируют. RTMP не поддерживает HTML5 и не работает в браузерах (воспроизведение возможно с помощью плагина Adobe Flash). Для обхода брандмауэров используют RTMPT (инкапсуляцию в HTTP-запросы и использование стандартных портов 80/443 вместо порта 1935), но это значительно влияет на задержку и избыточность (по разным оценкам, RTT и общая задержка увеличиваются на 30%). RTMP по-прежнему популярен, например, для вещания на YouTube или в соцсетях (RTMPS для Facebook).
Ключевые минусы RTMP: отсутствие поддержки кодеков AV1, HEVC, VP9 и ограничение двумя аудиодорожками. Также протокол не содержит временных меток в заголовках пакетов, а лишь метки, рассчитанные исходя из фреймрейта, поэтому декодер не знает, когда именно декодировать этот поток. Это обязывает принимающий компонент ровно выдавать сэмплы на декодирование, поэтому приходится увеличивать буфер на величину джиттера пакетов.
Другой проблемой является пересылка потерянных пакетов TCP, которая описана выше. Подтверждения получения не уходят сразу к отправителю, чтобы поддерживать низкий уровень обратного трафика. Только после получения цепочки пакетов отправляется позитивное или негативное подтверждение вещающей стороне.
По разным оценкам, задержка при вещании с помощью RTMP составляет минимум две секунды при полном тракте кодирования (кодер → сервер → клиент).
Протокол CMAF
Разработан экспертной группой по движущимся изображениям по заказу Apple и Microsoft для адаптивного вещания (с адаптивным битрейтом, который меняется исходя из изменения пропускной способности всего сетевого тракта) поверх HTTP. Обычно HTTP Live Streaming (HLS) от Apple использовал MPEG Transport Stream, а MPEG DASH от Microsoft — фрагментированный MP4. Спецификация CMAF увидела свет в июле 2017 года. В CMAF фрагментированные MP4-сегменты (ISOBMFF) передаются по HTTP с двумя разными плейлистами для одного контента для соответствующего плеера: iOS (HLS) или Android/Windows (MPEG DASH).
По умолчанию CMAF (как HLS и MPEG DASH) не предназначен для вещания с низкой задержкой. Но внимание и интерес к низкой задержке постоянно растет, так что некоторые производители предлагают расширение стандарта, например Low Latency CMAF. Это расширение предполагает, что и вещательная, и приемная стороны поддерживают два метода:
1. Chunk Encoding — разделение сегментов на подсегменты (маленькие фрагменты с MOOF+MDAT-MP4-боксами, которые в итоге составляют целый сегмент, пригодный для проигрывания) и их пересылка до того, как весь сегмент собран воедино;
2. Chunked Transfer Encoding — использование HTTP 1.1 для отправки подсегментов на CDN: отправляется только один HTTP-запрос методом POST для всего сегмента в 4 секунды (25 кадров/с), а в дальнейшем внутри этой сессии могут быть отправлены 100 маленьких фрагментов (в каждом по одному кадру). Плеер также может пытаться скачивать не полностью готовые сегменты, CDN, в свою очередь, при помощи Chunked Transfer Encoding отдает уже готовую часть и далее держит соединение до добавления новых фрагментов в скачиваемом сегменте. Передача сегмента плееру завершится, как только весь сегмент будет сформирован на стороне CDN.
Чтобы переключаться между профилями, необходима буферизация (минимум 2 секунды). Учитывая это, а также потенциальные проблемы в доставке, разработчики стандарта заявляют о потенциальной задержке менее трех секунд. При этом сохраняются такие возможности, как масштабирование через CDN с тысячами одновременных клиентов, шифрование (вместе с поддержкой Common Encryption), поддержка HEVC и WebVTT (субтитров), гарантированная доставка и совместимость с разными плеерами (Apple/Microsoft). Из минусов можно выделить обязательную поддержку LL CMAF на стороне плеера (поддержка фрагментированных сегментов и продвинутая работа с внутренними буферами). При этом в случае несовместимости плеер по-прежнему может работать с контентом в рамках спецификации CMAF со стандартной задержкой, типичной для HLS или DASH.
Протокол Low Latency HLS
Компания Apple опубликовала его спецификацию в июне 2019 года. Она состоит из следующих составляющих:
1. Генерация частичных сегментов (fragmented MP4 или TS) с минимальной длительностью вплоть до 200 мс, которые доступны еще до формирования полного сегмента (чанка), состоящего из таких частей (x part). Устаревшие частичные сегменты регулярно удаляются из плейлиста.
2. Серверная сторона может использовать режим HTTP/2 Server Push, чтобы отправлять обновленный плейлист вместе с новым сегментом (или фрагментом). Однако в последней правке спецификации в январе 2020 года эту рекомендацию исключили.
3. Обновленные плейлисты отправляются после их появления/обновления, а не после непосредственного запроса.
4. Вместо полного плейлиста отправляется разница в плейлистах (сохраняется изначальный плейлист, и далее отправляется только добавочная разница/дельта — x skip — при ее появлении вместо отправки полного плейлиста).
5. Сервер объявляет о предстоящей доступности новых частичных сегментов (preload hint).
6. Информация о плейлистах загружается параллельно в соседних профилях (rendition report) для более быстрого переключения.
Ожидаемая задержка при полной поддержке этой спецификации CDN и плеером — менее трех секунд. HLS очень широко используется для вещания в открытых сетях благодаря отличной масштабируемости, поддержке шифрования и адаптивного битрейта, кросс-платформенности и обладает обратной совместимостью, что полезно, если плеер не поддерживает LL HLS.
Протокол WebRTC
Разработан компанией Google в 2011 году. Используется в сервисах Google Hangouts, Slack, BigClueButton и YouTube Live. Представляет собой набор стандартов, протоколов и JavaScript-интерфейсов, который реализует сквозное шифрованное благодаря DTLS-SRTP в рамках peer-to-peer-соединения. При этом технология не использует сторонние плагины или ПО, проходя через брандмауэры без потери качества и задержки (например, при видеоконференциях в браузерах). При вещании видео обычно применяется реализация WebRTC поверх UDP.
Протокол работает следующим образом: хост отправляет запрос на соединение к пиру, с которым хочет соединиться. Пока соединение между пирами не установлено, они общаются между собой через третье лицо — сигнальный сервер. Далее каждый из пиров обращается к так называемому STUN-серверу с вопросом «кто я?» (как ко мне попасть извне?).
При этом существуют публичные STUN-сервера Google (например, stun.l.google.com:19302). STUN-сервер отдает список IP-адресов и портов, по которому можно достучаться до текущего хоста. Из этого списка формируются ICE-кандидаты. Вторая сторона делает то же самое. Происходит обмен ICE-кандидатами через сигнальный сервер, и уже на этом этапе устанавливается peer-to-peer-соединение, то есть формируется одноранговая сеть.
Если прямое соединение установить невозможно, то в качестве релей/прокси-сервера выступает так называемый TURN-сервер, который также заносится в список ICE-кандидатов.
За мультиплексирование, отправку, контроль перегрузок и надежную доставку отвечают SCTP- (данные приложения) и SRTP-протоколы (аудио- и видеоданные). Для обмена «рукопожатиями» и дальнейшего шифрования трафика применяется DTLS.
В качестве кодеков используются Opus и VP8. Максимальное разрешение — 720p, фреймрейт — 30 кадров/с, битрейт — 2 Мбит/с.
Минусом WebRTC в плане безопасности считается определение реального IP-адреса даже за NAT и при использовании сети Tor или прокси-сервера. Протокол не предназначен для большого количества одновременных пиров для просмотра в силу архитектуры соединений (тяжело масштабируется), а также практически не поддерживается CDN на текущий момент. Наконец, WebRTC уступает своим коллегам по качеству кодирования и максимальному объему передаваемых данных.
WebRTC недоступен в браузере Safari и частично недоступен в Microsoft Edge и UC Browser. Задержка, заявляемая Google, составляет меньше секунды. При этом данный протокол может использоваться не только для видеоконференций, но и для передачи файлов.
Протокол SRT
Создан компанией Haivision в 2012 году. Работает на базе UDT (UDP-based Data Transfer Protocol) и технологии восстановления пакетов ARQ. Поддерживает шифрование AES-128 бит и AES-256 бит. Помимо режима listener (сервер), поддерживает режимы caller (клиент) и rendezvous (когда обе стороны инициируют соединение), которые позволяют устанавливать соединения через брандмауэры и NAT. Процесс «рукопожатия» в SRT работает в рамках существующих политик безопасности, поэтому разрешаются внешние соединения без открытия постоянных внешних портов в брандмауэре.
SRT содержит временные метки внутри каждого пакета, что позволяет проигрывать ровно с той скоростью, с которой поток закодирован без необходимости большой буферизации, выравнивая джиттер (постоянно меняющуюся скорость прихода пакетов) и входящий битрейт. В отличие от TCP, где при потере одного пакета может пересылаться вся цепочка пакетов, начиная с потерянного, SRT идентифицирует конкретный пакет по его номеру и пересылает только его.
Это положительно влияет на задержку и избыточность. Пересылка пакета происходит с более высоким приоритетом, чем стандартное вещание. В отличие от стандартного UDT, в SRT полностью переписана архитектура переотправки пакетов, чтобы реагировать сразу же, как только пакет потерян. Такая технология является вариацией selective repeat/reject ARQ.
Стоит отметить, что конкретный потерянный пакет можно переслать только фиксированное количество раз. Пропуск пакета отправителем происходит, когда время на пакете составляет более 125% от общей задержки. SRT поддерживает FEC, и пользователь сам определяет, какую из этих двух технологий применять либо использовать обе, чтобы балансировать между самой низкой задержкой или самой высокой надежностью доставки.
Передача данных в SRT может быть двунаправленной: обе точки могут посылать данные одновременно, а также могут выступать как слушателем (listener), так и стороной, инициирующей соединение (caller). Может использоваться режим «рандеву» (rendezvous), когда обе стороны пытаются установить соединение. Протокол имеет механизм внутреннего уплотнения, который позволяет мультиплексировать несколько потоков одной сессии в одно соединение, используя один UDP-порт. Также SRT подходит для быстрой передачи файлов, которая впервые была представлена в UDT.
В SRT существует механизм контроля сетевой перегрузки (congestion control): каждые 10 мс отправитель получает последние данные об RTT и его изменениях, доступном размере буфера, скорости получения пакетов и примерный размер текущего линка. Есть ограничения на минимальную дельту между двумя пакетами, посылаемыми подряд. Если их невозможно доставить вовремя, они удаляются из очереди.
Разработчики утверждают, что минимальная задержка, которую можно достигнуть при использовании SRT, — 120 мс с минимальным буфером при передаче на маленькие расстояния в закрытых сетях. Общая задержка, рекомендуемая для стабильного вещания, равна 3–4 RTT. Кроме того, SRT лучше справляется с доставкой на большие расстояния (несколько тысяч километров) и с высоким битрейтом (от 10 Мбит/с и выше), чем его конкурент RTMP.
Скриншот 2. Измерение задержки при вещании в SRT в лаборатории.
На скриншоте 2 показана измеренная в лаборатории задержка при вещании SRT в 3 фрейма при 25 кадрах/с. То есть 40 мс × 3 = 120 мс. Отсюда можно сделать вывод, что задержка на уровне 0,1 секунды, которая может достигаться при вещании в UDP, доступна и при вещании в SRT. Способность к масштабированию в SRT не на таком уровне, как в HLS или DASH/CMAF, однако SRT активно поддерживается разными CDN и перевещателями (рестримерами), а также обеспечивает вещание напрямую конечным клиентам через медиасервер в режиме слушателя (listener).
В 2017 году компания Haivision открыла исходный код SRT-библиотек и создала SRT Alliance, который насчитывает уже более 350 членов.
Резюме
Сегодня все открытое и хорошо документированное ПО довольно быстро приобретает популярность. Можно предположить, что такие форматы, как WebRTC и SRT, ждет перспективное будущее в своих областях применения. По минимальной величине задержки эти протоколы уже опережают адаптивное вещание поверх HTTP, при этом сохраняют надежность доставки, обладают низкой избыточностью и поддерживают шифрование (AES в SRT и DTLS/SRTP в WebRTC). Также в последнее время набирает популярность «младший брат» SRT (по возрасту, но не по функциям и возможностям) — протокол RIST, но это уже тема для отдельного обзора. RTMP же активно вытесняется с рынка молодыми конкурентами, а из-за отсутствия нативной поддержки в браузерах его вряд ли ждет широкое применение.
Источник: telesputnik.ru
Сервер онлайн-вещаний на базе nginx
2012-12-12 в 6:28, admin , рубрики: flash, nginx, nginx-rtmp-module, вещание, метки: flash, nginx, nginx-rtmp-module, вещание
Введение
Привет всем! Несколько месяцев назад на Хабре была опубликована статья «Вещание онлайн-видео с помощью nginx» , в которой Aecktann рассказал о своем опыте внедрения разрабатываемого мной модуля к nginx для вещания видео — nginx-rtmp-module. С тех пор продукт активно развивался и в этой статье я более подробно расскажу о нем.
Вещатель нужен для передачи видео-потока клиенту. Речь идет либо о живом потоке, либо о вещании записанного видео (VOD, Video-on-demand). Существует большое количество технологий вещания видео. Среди них можно выделить традиционные протоколы, такие как RTMP или MPEG-TS, а также появившиеся в последнее время технологии адаптивного вещания поверх HTTP.
К последним относятся HLS (Apple), HDS (Adobe), Smooth Streaming (Microsoft), MPEG-DASH. При выборе технологии основным фактором является ее поддержка на клиентской стороне. Именно поэтому вещание в формате RTMP на текущий момент является одним из самых распространенных. Протокол HLS поддерживается устройствами компании Apple, а также некоторыми версиями Android.
Сборка и настройка nginx-rtmp
Для добавления модуля nginx-rtmp к nginx нужно указать его в опции —add-module при конфигурации nginx, как и любой другой модуль.
./configure —add-module=/path/to/nginx-rtmp-module
После сборки и инсталляции нужно добавить секцию rtmp<> в файл конфигурации nginx.conf. Добавлять ее надо в корень конфига. Например:
rtmp < server < listen 1935; application myapp < live on; >> >
Для многих случаев этой простой конфигурации будет достаточно. В ней задается RTMP-приложение с именем myapp. В это приложение мы позже будем публиковать потоки и проигрывать их из него. У каждого потока также будет свое уникальное имя.
Стоит отметить один важный нюанс, касающийся приведенной выше конфигурации. Она верна для того случая, когда число воркеров nginx равно единице (как правило, задается в начале nginx.conf).
worker_processes 1;
Чтобы иметь возможность использовать live вещания с бОльшим числом воркеров, нужно указать директиву rtmp_auto_push on (см. раздел «Воркеры и локальная ретрансляция»).
Публикация и проигрывание живого потока
Для публикации и проигрывания видео можно использовать Flash-проигрыватели (JWPlayer, FlowPlayer, Strobe и т.д.). Однако, для вещания серверных потоков и для тестирования часто используют ffmpeg (и ffplay). Начнем вещание тестового файла test.mp4 следующей командой:
ffmpeg -re -i /var/videos/test.mp4 -c copy -f flv rtmp://localhost/myapp/mystream
Тут надо учесть, что RTMP поддерживает ограниченый набор кодеков, впрочем, такие популярные кодеки, как H264 и AAC, входят в их число. Если кодеки в тестовом файле не совместимы с RTMP, потребуется перекодировка:
ffmpeg -re -i /var/videos/test.mp4 -c:v libx264 -c:a libfaac -ar 44100 -ac 2 -f flv rtmp://localhost/myapp/mystream
Вещать можно как поток из файла, так и из другого источника. Например, если предположить, что по адресу video.example.com/livechannel.ts вещается некий live MPEG-TS поток, то его также можно завернуть в rtmp:
ffmpeg -i http://video.example.com/livechannel.ts -c copy -f flv rtmp://localhost/myapp/mystream
Пример вещания с локальной веб-камеры:
ffmpeg -f video4linux2 -i /dev/video0 -c:v libx264 -an -f flv rtmp://localhost/myapp/mystream
Проиграть поток можно при помощи ffplay следующей командой:
ffplay rtmp://localhost/myapp/mystream
И, наконец, простой пример использования JWPlayer для проигрывания потока из браузера (полностью приведен в директории /test/www модуля):
jwplayer(«container»).setup( < modes: [ < type: «flash», src: «/jwplayer/player.swf», config: < bufferlength: 1, file: «mystream», streamer: «rtmp://localhost/myapp», provider: «rtmp», >> ] >);
Видео по запросу
Модуль поддерживает вещание видео-файлов в форматах mp4 и flv. Пример настройки:
application vod < play /var/videos; >
При проигрывании, соответственно, надо указывать имена файлов, в остальном все аналогично живому вещанию.
ffplay rtmp://localhost/vod/movie1.mp4 ffplay rtmp://localhost/vod/movie2.flv
Ретрансляция
При построении распределенных систем важно иметь возможность ретрансляции потоков для балансировки нагрузки
по большому числу серверов. Модуль реализует два типа ретрансляции: push и pull. Первый тип ретрансляции
состоит в передаче на удаленный сервер локально публикуемого потока, а второй — в передаче удаленного
потока на локальный сервер. Пример push ретрансляции:
application myapp < live on; push rtmp://cdn.example.com; >
В момент, когда начинается публикация по адресу rtmp://localhost/myapp/mystream, создается соединение с удаленным сервером и поток mystream публикуется далее на rtmp://cdn.example.com/myapp/mystream. При прекращении локальной публикации, соединение с cdn.example.com автоматически завершается.
Pull-ретрансляции выполняют обратную операцию:
application myapp < live on; pull rtmp://cdn.example.com; >
В этом примере при появлении клиента, желающего локально проиграть поток rtmp://localhost/myapp/mystream, будет создано соединение с rtmp://cdn.example.com/myapp/mytstream и удаленный поток будет ретранслирован на локальный сервер, после чего станет доступным всем локальным клиентам. В тот момент, когда не останется ни одного клиента, соединение будет завершено.
Вещание на мобильные устройства (HLS)
Для вещания на устройста iPhone/iPad, а также на новые версии Android, используется протокол HLS (HTTP Live Streaming).
Протокол был разработан компанией Apple и представляет из себя «нарезанный» на куски MPEG-TS/H264/AAC поток, отдаваемый по HTTP. К потоку прилагается плейлист в формате m3u8. Отдавать HTTP nginx умеет отлично. Значит, надо лишь создать и обновлять плейлист и фрагменты HLS-потока, а также следить за удалением старых фрагментов. Для этого существует модуль nginx-rtmp-hls.
Он находится в директории hls, однако не собирается по умолчанию т.к. требует библиотеки libavformat, входящей в пакет ffmpeg. Для сборки nginx с поддержкой HLS, надо добавить этот модуль явно при конфигурации:
./configure —add-module=/path/to/nginx-rtmp-module —add-module=/path/to/nginx-rtmp-module/hls
Так вышло, что некоторое время назад проект ffmpeg был форкнут. И теперь у нас есть два проекта — ffmpeg и avconv, а следовательно, тут же начали возникать проблемы совместимости (вернее, несовместимости) библиотек. Для сборки nginx-rtmp нужен оригинальный ffmpeg.
В то же время, некоторые дистрибутивы Linux перешли на использование avconv, который для сборки не подойдет. На этот случай я написал подробную инструкцию.
Для генерации HLS достаточно указать следующие директивы:
application myapp < live on; hls on; hls_path /tmp/hls; hls_fragment 5s; >
Ну и, наконец, в секции http<>, настроить отдачу всего, что связано с HLS:
location /hls < root /tmp; >
Теперь публикуем поток mystream в приложение myapp, а в браузере iPhone набираем в строке адреса example.com/hls/mystream.m3u8. Кроме того, поток можно встроить в html тег video:
Отмечу, что для проигрывания на iPhone поток должен быть закодирован в H264 и AAC. Если исходный поток не соответствует этим условиям, необходимо настроить перекодирование.
Перекодирование
При вещании видео часто возникает необходимость перекодирования входящего потока в другое качество, либо другие кодеки. Эта задача по своей сути кардинально отличается от раздачи RTMP и, в отличие от последней, связана с высокими нагрузками на CPU, большим и активным потреблением памяти, часто опирается на использование многопоточности и является потенциально нестабильной.
По этой причине она не должна включаться в основной процесс сервера, и в идеале должна выполняться отдельным процессом. Стоит отметить, что прекрасный инструмент для решения этой задачи уже существует — это все тот же ffmpeg. Он поддерживает огромное число кодеков, форматов и фильтров, позволяет использовать множество сторонних библиотек.
Вместе с тем, он достаточно прост и активно поддерживается сообществом. Модуль nginx-rtmp предоставляет простой интерфейс для использования ffmpeg. Директива exec позволяет запустить внешнее приложение в момент публикации входящего потока. При завершении публикации приложение также принудительно завершается. Кроме того, поддерживается перезапуск запущенного приложения, если оно внезапно завершилось само.
application myapp < live on; exec ffmpeg -i rtmp://localhost/myapp/$name -c:v flv -c:a -s 32×32 -f flv rtmp://localhost/myapp32x32/$name; >application myapp32x32
В этом примере ffmpeg используется для перекодирования входящего видео в Sorenson-H263, изменении его размера до 32х32 и публикации результата в приложение myapp32x32. Можно одновременно задать несколько директив exec, которые будут производить с потоком любые преобразования и публиковать результат в другие приложения как на локальный, так и на удаленный сервер. Директива поддерживает несколько переменных, среди которых $app (имя приложения) и $name (имя потока).
Воркеры и локальная ретрансляция
Как известно, nginx является однопоточным сервером. Для того, чтобы эффективно использовать все ядра современных процессоров, обычно он запускается в несколько воркеров. Обработка HTTP запросов как правило, происходит независимо друг от друга, и лишь в отдельных случаях (как, например, в случае с кешом), требуется осуществлять доступ к общим данным. Такие данные хранятся в разделяемой памяти.
При живом вещании ситуация иная. Все клиентские соединения, проигрывающие поток, очевидным образом зависят от соединения, публикующего этот поток. Использование разделяемой памяти в данном случае неэффективно, излишне трудоемко, привело бы к синхронизации и большой потере производительности. Поэтому для использования нескольких воркеров был реализован механизм внутренних ретрансляций через UNIX-сокеты. Собственно, такие ретрансляции практически ничем не отличаются от обычных внешних push-ретрансляций. Локальные ретрансляции включаются следующей директивой
rtmp_auto_push on;
Указывать ее надо в корневой секции конфигурационного файла. Отмечу, что локальные ретрансляции нужны только для живых вещаний.
Запись
Часто возникает необходимость записи на диск публикуемых потоков. Модуль позволяет записывать как отдельные данные из потока (аудио, видео, ключевые фреймы) так и поток целиком. Можно установить ограничение на размер файла, а также на число записываемых фреймов. Следующий пример включает запись первых 128К каждого потока.
record all; record_path /tmp/rec; record_max_size 128K;
Запись происходит в формате flv в директорию /tmp/rec.
Управлять записью можно в ручном режиме, включая и отключая ее при помощи http-запроса. Для этого используется control-модуль. Информацию о нем можно найти на сайте проекта.
Авторизация и бизнес-логика
Во многих случаях требуется ввести ограничения или учет операций публикации и проигрывания видео. Это бывает связано с логикой проекта, в котором он используется. Самый частый подобный случай — необходимость авторизации пользователя перед тем, как дать ему доступ к просмотру видео.
Чтобы интегрировать бизнес-логику проекта в вещатель, в модуле реализованы HTTP-колбэки, такие как on_publish и on_play. Серверный код получает всю имеющуюся информацию о клиенте, включая его адрес, имя потока, адрес страницы и т.д. Если возвращается HTTP статус 2xx, то колбек считается завершенным успешно и работа клиента продолжается. В противном случае соединение разрывается.
on_publish http://example.com/check_publisher; on_play http://example.com/check_player;
Статистика
В каждый момент времени к вашему серверу могут быть подсоединены тысячи клиентов. Естественно, нужен интерфейс, позвляющий увидеть их список, а также все основные характеристики публикуемых или проигрываемых ими потоков.
Причем, важно, чтобы эту информацию можно быть как анализировать визуально, так и обрабатывать программно. Такой интерфейс у модуля nginx-rtmp существует. Чтобы его использовать, необходимо в http-секции nginx.conf прописать следующие директивы.
location /stat < rtmp_stat all; rtmp_stat_stylesheet stat.xsl; >location /stat.xsl < root /path/to/stat.xsl/dir/; >
Директива rtmp_stat включает отдачу XML-документа с полным описанием live-клиентов, публикующих или проигрывающих потоки, списком приложений и серверов. Этот документ удобен для программной обработки, но для визуального анализа совершенно не годится.
Чтобы иметь возможность просматривать список клиентов в браузере, директивой rtmp_stat_stylesheet задается относительный путь к таблице стилей XML (stat.xsl). Этот файл лежит в корне проекта. Надо настроить nginx на его раздачу по указанному урлу. Результат можно просматривать в браузере.
Существует возможность явно разрывать клиентские соединения. Для этого используется control-модуль, не описанный в статье.
Простое Интернет-радио
С самого начала статьи я постоянно употреблял слово «видео». Конечно, модуль может вещать не только видео, а также и аудио-потоки. Вот простой пример интернет-радиостанции на bash, вещающей mp3-файлы из /var/music. Этот поток может воспроизводить простой JWPlayer, встроенный в веб-страницу.
while true; do ffmpeg -re -i «`find /var/music -type f -name ‘*.mp3’|sort -R|head -n 1`» -vn -c:a libfaac -ar 44100 -ac 2 -f flv rtmp://localhost/myapp/mystream; done
Совместимость
Модуль совместим со всем основным софтом, работающим с протоколом RTMP, включая FMS/FMLE, Wowza, Wirecast, протестирован с самыми распространенными флеш-проигрывателями JWPlayer, FlowPlayer, StrobeMediaPlayback, а также отлично работает с ffmpeg/avconv и rtmpdump.
Нагрузки
Модуль использует асинхронную однопоточную модель сервера nginx. Это позволяет добиться высокой производительности. Мы используем модуль на машинах Intel Xeon E5320/E5645 в режиме одного воркера. В этом режиме удается достигнуть максимальной пропускной способности имеющихся сетевых карт — 2Gbps.
Пользователи модуля подтверждают сохранение этого же соотношения (2Gbps на ядро) в режиме локальной ретрансляции с несколькими воркерами. Практика показывает, что производительность вещателя обычно упирается в сеть, а не в CPU.
Прямых сравнений с другими продуктами я не проводил, однако, «тяжелые» многопоточные FMS, Wowza и Red5, будучи более функциональными, должны, в силу особенностей реализации, существенно проигрывать моему решению по числу одновременно подсоединенных клиентов и нагрузке на CPU. Это подтверждается многими пользователями, проводившими такие сравнения, в т.ч. в уже упомянутой мной статье.
Заключение
В заключении скажу, что модуль распространяется по лицензии BSD. Он собирается и работает под Linux, FreeBSD и MacOS. В статье описана лишь малая часть функционала nginx-rtmp-module. Желающие могут ознакомиться с проектом по ссылкам, приведенным ниже.
- Страница проекта на гитхабе github.com/arut/nginx-rtmp-module.
- Полное описание директив с примерами github.com/arut/nginx-rtmp-module/wiki/Directives.
- Блог, куда я пишу о новых версиях, багфиксах и новом функционале rarut.wordpress.com.
- Гугл-группы, где отвечаю на вопросы и обсуждаю с пользователями модуля возникающие проблемы groups.google.com/group/nginx-rtmp и groups.google.com/group/nginx-rtmp-ru.
Буду рад, если читателям Хабра проект покажется интересным.
Источник: www.pvsm.ru