MPEG-DASH в nginx-rtmp-module: живое видео в браузере без флеша

от автора

Что такое MPEG-DASH

MPEG-DASH — технология нового поколения, позволяющая вещать адаптивный видео-поток. Данные разбиваются на фрагменты и передаются клиенту по протоколу HTTP. Это позволяет надежно передавать видео через существующую HTTP-инфрастуктуру, преодолевать прокси-сервера, а также безболезненно переносить проблемы с сетью, изменения сетевых адресов итд.

DASH — Dynamic Adaptive Streaming over HTTP. Стандарт DASH ISO/IEC 23009-1:2012 был разработан группой MPEG в 2011 году

Технология MPEG-DASH в целом аналогична другой известной технологии HLS (HTTP Live Streaming), разработанной компанией Apple и широко используемой на мобильных устройствах с iOS и Android. Поток представлен в виде небольших по длительности фрагментов и плейлиста (манифеста), содержащего метаданные потока и ссылки на фрагменты.

В HLS плейлист хранится в формате m3u8 (расширение m3u), а фрагменты — в MPEG-TS (часть стандарта MPEG-2). В MPEG-DASH плейлист (манифест) хранится в XML, а фрагменты могут иметь как формат MPEG-TS, так и ISO BMFF (проще говоря, mp4). На практике поддержка MPEG-TS клиентами ограничена, так что ориентироваться приходится на более современный mp4.

В чем же состоит преимущество MPEG-DASH? Главное преимущество в том, что поддержка этой технологии сегодня активно внедряется в браузеры, что дает возможность вещать видео без использования тяжелого и порядком надоевшего flash. Кроме того, MPEG-DASH поддерживается новыми моделями телевизоров в рамках стандарта HbbTV.

Далее я расскажу о самой технологии и опишу, как настроить live вещание в браузере с помощью nginx-rtmp-module и dash.js.

Манифест

Манифест MPEG-DASH — это XML документ. Его спецификация приведена в стандарте ISO/IEC 23009-1:2012. Манифест имеет довольно сложный формат, он поддерживает периоды, сдвижки времени, описание потоков, различные способы нумерации фрагментов. Для живого вещания потока с постоянным аудио и видео каналами, нам достаточно лишь ограниченного набора возможностей:

  • характеристики видео — размеры, fps, кодек, ширина потока
  • характеристики аудио — частота, кодек, ширина потока
  • ссылки на актуальные аудио и видео фрагменты
  • ссылки на инициализирующие фрагменты потоков

Пример манифеста

<?xml version="1.0"?> <MPD     type="dynamic"     xmlns="urn:mpeg:dash:schema:mpd:2011"     availabilityStartTime="2013-11-27T12:40:35+04:00"     availabilityEndTime="2013-11-27T12:41:08+04:00"     minimumUpdatePeriod="PT5S"     minBufferTime="PT5S"     timeShiftBufferDepth="PT0H0M0.00S"     suggestedPresentationDelay="PT10S"     profiles="urn:mpeg:dash:profile:isoff-live:2011">   <Period start="PT0S" id="dash">     <AdaptationSet         segmentAlignment="true"         maxWidth="768"         maxHeight="576"         maxFrameRate="24">       <Representation           id="video"           mimeType="video/mp4"           codecs="avc1.42c028"           width="768"           height="576"           frameRate="24"           sar="1:1"           startWithSAP="1"           bandwidth="641000">         <SegmentTemplate             presentationTimeOffset="0"             timescale="1000"             media="mystream-$Time$.m4v"             initialization="mystream-init.m4v">           <SegmentTimeline>              <S t="0" d="5888"/>              <S t="5888" d="6760"/>              <S t="12648" d="6000"/>              <S t="18648" d="8680"/>              <S t="27328" d="6545"/>           </SegmentTimeline>         </SegmentTemplate>       </Representation>     </AdaptationSet>     <AdaptationSet         segmentAlignment="true">       <AudioChannelConfiguration           schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011"           value="1"/>       <Representation           id="audio"           mimeType="audio/mp4"           codecs="mp4a.40.2"           audioSamplingRate="48000"           startWithSAP="1"           bandwidth="125000">         <SegmentTemplate             presentationTimeOffset="0"             timescale="1000"             media="mystream-$Time$.m4a"             initialization="mystream-init.m4a">           <SegmentTimeline>              <S t="0" d="5888"/>              <S t="5888" d="6760"/>              <S t="12648" d="6000"/>              <S t="18648" d="8680"/>              <S t="27328" d="6545"/>           </SegmentTimeline>         </SegmentTemplate>       </Representation>     </AdaptationSet>   </Period> </MPD> 

Фрагменты

Фрагменты MPEG-DASH имеют формат mp4. Однако, это не совсем те mp4, которыми мы обычно пользуемся, это фрагментированные mp4. Обычный mp4 файл состоит из двух основных частей — метаданные и данные. Метаданные хранятся атоме moov, а данные — в атоме mdat. Метаданные позволяют для каждого семпла узнать его таймстамп, длительность, размер, смещение относительно начала файла итд. Кроме того, в moov хранится информация о кодеках и блок параметров кодеков, без которых невозможно декодирование потока.

Фрагментированные mp4 устроены иначе. Атом moov хранится в отдельном инициализирующем фрагменте и содержит лишь общую информацию о потоке — параметры кодеков, размеры видео, частота дискретизации аудио итд. Каждый фрагмент, в свою очередь, состоит из двух атомов — moof и mdat. Атом метаданных фрагмента moof хранит информацию о семплах, находящихся в этом фрагменте. Формат moof существенно отличается от moov. Кроме того, в отсутствие параметров кодека фрагмент не может быть проигран как независимый mp4-файл.

MPEG-DASH на сервере

Начиная с версии 1.0.8 в nginx-rtmp-module реализована поддержка вещания живых потоков в MPEG-DASH. Происходит это аналогично вещанию в HLS. В указанной директории создаются dash-фрагменты, а также файл манифеста. В процессе вещания старые фрагменты удалятся, новые появляются, плейлист обновляется.

Для сборки nginx с nginx-rtmp-module указываем его в --add-module

./configure --add-module=/path/to/nginx-rtmp-module ... 

После сборки настраиваем MPEG-DASH

rtmp {     server {         listen 1935;          # генерация dash-манифеста и фрагментов в /tmp/dash         application myapp {             live on;             dash on;             dash_path /tmp/dash;         }     } }  ...  http {     server {         listen 8080;          # отдача манифеста и фрагментов         location /dash {             root /tmp;             add_header Cache-Control no-cache;         }     } } 

Вот как выглядит срез MPEG-DASH потока с именем mystream

# инициализирующие фрагменты mystream-init.m4a mystream-init.m4v  # текущие фрагменты # формат имени: mystream-TIME.mp4X # где TIME-таймстамп первого семпла mystream-0.m4a mystream-0.m4v mystream-5888.m4a mystream-5888.m4v mystream-12648.m4a mystream-12648.m4v mystream-18648.m4a mystream-18648.m4v mystream-27328.m4a mystream-27328.m4v  # манифест (плейлист) mystream.mpd  # временные файлы для будущих фрагментов mystream-raw.m4a mystream-raw.m4v 

MPEG-DASH в браузере

Основной инструмент, с помощью которого в настоящий момент реализуется проигрывание MPEG-DASH в браузерах — это плеер dash.js, являющийся референсной реализацией MPEG-DASH клиента и разрабатываемый организацией DASH Industry Forum. Плеер треует от браузера поддержки Media Source Extensions.

В настоящий момент плеер хорошо работает со статичным видео, однако с проигрыванием живых потоков у неего все еще есть определенные проблемы. Так, для поддержки live-вещаний в Chrome мне пришлось немного доработать плеер. Модифицированная версия лежит в бранче live моего форка проекта. Авторы плеера обещали в следующей версии полностью решить проблему с живыми вещаниями.

Скачиваем и устанавливаем dash.js из форка

# скачаем dash.js в /var/www cd /var/www git clone https://github.com/arut/dash.js.git cd dash.js git checkout live 

Открываем в редакторе baseline.html и находим строчку со стандартным урлом

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

Заменяем на наш урл

url = "http://localhost:8080/dash/mystream.mpd". 

Добавляем локейшен в nginx для отдачи содержимиго dash.js, включая тестовую страницу

location /dash.js {     root /var/www; } 

Теперь запускаем вещание с именем mystream

ffmpeg -re -i ~/Videos/sintel.mp4 -c:v libx264 -profile:v baseline -c:a libfaac -ar 44100 -ac 2 -f flv rtmp://localhost/myapp/mystream 

Далее заходим в браузер на страницу http://localhost:8080/dash.js/baseline.html. Здесь, вероятно, придется подождать несколько секунд пока не будет создан манифест вещания и обновить страницу.

Браузеры

Для работы MPEG-DASH через dash.js браузер должен поддерживать Media Source Extensions API. Ситауция с поддержкой этих расширений постоянно улучшается, однако все еще не идеальна.

  • Chrome (в т.ч. мобильный начиная с Android 4.2) — поддерживается в текущей версии
  • IE — поддерживается с версии 11 начиная с Windows 8
  • Firefox — не поддерживается. Разработчики обещают поддержку Media Source Extensions в ближайшие месяцы
  • Safari — не поддерживается. Однако, Safari — единственный десктопный браузер, поддерживающий HLS.

ссылка на оригинал статьи http://habrahabr.ru/post/204666/