Pull to refresh

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

Open source *

Что такое 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.
Tags:
Hubs:
Total votes 34: ↑33 and ↓1 +32
Views 51K
Comments Comments 25