Пользователь
0,0
рейтинг
3 декабря 2013 в 17:29

Разработка → 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.
Роман Арутюнян @rarutyunyan
карма
83,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (24)

  • +3
    Google/YouTube с начала года отдаёт HD больше 720 в mpeg-dash и браузеры нормально справляются без dash.js
  • 0
    IE11 выпущен и для Windows 7, стоит заметить, поддержка есть и там
    • +3
      Пробовали. dash.js не проигрывает из-за отсутствия Media Source Extensions.
  • 0
    Технология интересная, но baseline profile ощутимо проигрывает по качеству сжатия видео.
    • 0
      Так dash это же вроде как контейнер, а настройки кодирования h264 могут быть любыми.

      • 0
        Автор модуля пишет что только baseline: «Video should be h264 encoded with Baseline profile. Other profiles will not work!»
        nginx-rtmp.blogspot.ru/2013/11/mpeg-dash-live-streaming-in-nginx-rtmp.html
        • +3
          На самом деле работают, но не все. Это я (автор — это я) поторопился написать. С одним из файлов была такая проблема, но с другими не в baseline ее уже не было.

          Однако baseline — все равно вариант предпочтительный, лучше всего поддержан.
  • 0
    Большое спасибо!
    Но сломалось exec_record_done в recorder, в application — работает.
    • 0
      Исправил
  • 0
    В чем преимущество mpeg-dash перед hls?

    И да, пользуюсь случаем, скажу автору спасибо, плагин прекрасный.
    • 0
      Например в том, что его поддерживает Chrome. Причем поддерживает без флеша, реализации HLS на флеше конечно есть.
  • 0
    На мобильный стабильный хроме live-трансляция отказывается работать. Chrome Beta играет вполне.
    Не могу понять, что не нравится стабильному. Не-live трансляции он играет на ура.
    • 0
      Хром нужен новый. Это требование dash.js.
      • 0
        Да, только коммиты в вашем репозитории от 21 ноября, а стабильный хром (31-й) вышел 18 ноября.
        Коммиты в ветке, от которой вы форкались — вообще от сентября.

        Точно в этом дело? Потому что еще раз: dash.js работает на 31-м хроме на VoD примерах.
        • 0
          Разработчики dash.js говорили, что в некоторых случаях нужен был (на тот момент еще) не стабильный.
          Ну и мобильный хром — это, в общем, совсем другой браузер. По крайней мере проигрывание fragmented mp4 там происходит совсем не так, как в обычном хроме.
          • 0
            То бишь, нормально работающего решения для live-трансляций на андроиде в браузере как не было, так и нет? :(
            • 0
              Так HLS стандартным браузером в ведре поддерживается.
              • 0
                давно ли?
                статичное — ок
                live — вовсе нет.

                я чего-то не знаю?
                • 0
                  вы правы.
                  из десктопных браузеров только Safari поддерживает HLS.
                  • 0
                    вышел 32-й хром, в нем работает dash.js
                • 0
                  ведро = андроид
                  Мы режем HLS из потока трансляции, все работает.
    • 0
      Я не умею в падежи.

      На мобильном стабильном хроме live-трансляция отказывается работать. Chrome Beta играет вполне.
      Не могу понять, что не нравится стабильному. Не-live трансляции он играет на ура.
  • 0
    Отличный модуль, большое спасибо!

    1. Не помешал бы пример конфигурации для GStreamer вместо ffmpeg. Например, у меня заработал:

    	gst-launch-1.0 -v -m v4l2src ! video/x-raw,width=640,height=480 \
    		! x264enc tune=zerolatency ! "video/x-h264,profile=baseline" ! h264parse \
    		! flvmux streamable=true name=mux \
    		alsasrc ! queue ! audioconvert ! voaacenc ! aacparse ! mux. \
    		mux. ! rtmpsink location=rtmp://localhost/myapp/mystream
    


    2. dash.js (ваш форк) показывает, но с задержкой около минуты.
    Не нашёл, как задать ему минимальную задержку. Не подскажете?

    Смержил ваш форк dash.js до мастера апстрима, но у меня не заработало, а сейчас разбираться, честно, некогда. А там, может быть, чинили именно эту задержку из-за буферизации.
  • 0
    Подскажите, поддерживает ли модуль при вещании в HLS или MPEG-DASH паузу на live потоках?

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

    Есть ли поддержка? На какую глубину по времени? Что в настройках модуля об этом сказано?

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