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.
    Метки:
    Поделиться публикацией
    Похожие публикации
    Комментарии 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
      В чем преимущество 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 потоках?

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

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

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