Нередко клиенты спрашивают, умеет ли наш сервер «mp4-стриминг в HTML5». В 99% случаев спрашивающий не понимает о чём говорит. В этом сложно винить клиентов: из-за путаницы с терминами, технической сложности и большого разнообразия вариантов стриминга запутаться очень легко.
В этой статье мы расскажем, какой бывает HTML5-стриминг, какие варианты хорошие, и почему, чёрт побери, нельзя говорит «mp4-стриминг».
▍Термины
HTML5-видео — это когда вы вставляете в веб-страницу тег <video> и указываете ему какой-то src. HTML5-стриминг — это то же HTML5-видео, но когда в src не готовый файл, а постоянно обновляющийся видеопоток. Ролик на Ютубе — это HTML5-видео, трансляция в Твитче — HTML5-стриминг.
Тегу <video> неважно, как видеопоток формируется и передаётся, и сможет ли браузер его проиграть. Главное, чтобы в src была ссылка на какой-то видеопоток. Говоря техническим языком, спецификация ничего не говорит о том, какие протоколы, транспорты и кодеки поддерживаются в HTML5-видео.
Протокол — это то, как два участника видеосвязи (почти всегда это клиент и сервер) обмениваются данными с целью получения данных. Клиентом называют того, кто приходит к серверу и инициирует сессию связи. Видеопоток может течь от сервера к клиенту (тогда это обычное проигрывание) или от клиента к серверу (тогда это публикация). Даже когда гигантский шкаф, жрущий электричество как многоквартирный дом приходит к маленькой IP-камере, то она будет сервером, а этот шкаф клиентом.
Протокол обычно подразумевает хотя бы команду Play (начать проигрывание), но иногда есть и расширенные варианты: пауза, продолжение, публикация, перемотка и т. п.
Примеры протоколов: RTSP, RTMP, HTTP, HLS, IGMP.
Транспорт, или транспортный контейнер, или контейнер — это то, как сжатое видео упаковывается в байты для передачи от одного участника к другому (по какому-то протоколу).
Примеры контейнеров: MPEG-TS, RTMP, RTP.
Обратите внимание, что RTMP оказался и в протоколах, и в транспортах. Это потому, что в описании RTMP есть спецификация и того, что должны слать друг другу стороны, чтобы видео потекло (т. е. протокол), и того, как упаковывать видео (т. е. транспорт). Так бывает не всегда. Например в протоколе RTSP видео упаковывается в транспорт RTP. |
Кодек — многозначный термин. Здесь он означает способ сжать сырое видео. Разница между кодеком и транспортом в том, что кодек — это про подготовку видео, а транспорт — про передачу видео по протоколу. Видео, сжатое одним кодеком, можно пересылать по разными протоколам и разными транспортами. Большинство видеостриминговых серверов не залезают грубже кодированного видео и оперируют только протоколами и транспортами.
Примеры кодеков: h264, aac, mp3.
Из-за того, что термин многозначный, возникает путаница с названиями. Например, H.264 — это стандарт того, как упаковать поток огромных сырых видеокадров в очень мало байтов, libx264 — это библиотека для сжатия по этому стандарту, а ещё есть одноимённый софт под Винду, который умеет декодировать h264 и проигрывать его на экране. |
Итак, в спецификации HTML5 не описаны протоколы, транспорты и кодеки. Поэтому авторы браузеров сами выбирают, что поддерживать, а под «HTML5-стримингом» подразумевают разные вещи.
При этом есть комбинации, которые поддерживаются значительной частью браузеров. Рассмотрим самые перспективные.
▍HLS
HLS — это h264-видео и aac- или mp3-аудио, упакованное в транспорт MPEG-TS. Поток разбивается на сегменты, описанные в m3u8-плейлистах, и раздается по HTTP. HLS поддерживает мультибитрейтные потоки, Live/VOD. Вариант очень простой, но в то же время имеет много деталей, из-за чего на разных устройствах работает по-разному.
Разработали HLS в Эппле, поэтому изначально он работал только в Сафари на iOS и MacOS. Даже Сафари на Windows не умел играть HLS (когда еще была версия под Win).
Тем не менее, сейчас HLS умеют проигрывать все телевизионные приставки и даже почти все устройства на Андроиде.
Но не всё гладко. Производители сторонних плееров плюнули на стандарт Эппла в части донесения разных аудиодорожек и добавили проигрывание всего что есть в обычном MPEG-TS: mpeg2 video, mpeg2 audio и т. п. Из-за этого приходится отдавать разные форматы плейлистов для разных плееров.
▍MPEG-DASH
MPEG-DASH — обычно это h264/h265-видео и aac-аудио, упакованное в транспорт mp4, или vp8/vp9, упакованное в WebM, хотя стандарт и не привязан к конкретным кодекам, протоколам и транспортам. Как и в HLS, поток может разбиваться на сегменты, но это необязательно. Вместо плейлистов — MPD-манифест в XML.
MPEG-DASH во многом похож на HLS. Возможно, он даже популярнее, ведь такие гиганты как Ютуб и Нетфликс уже несколько лет используют его как основной способ раздачи контента.
MPEG-DASH хорош тем, что в большинстве браузеров работает нативно, через MSE (о том, что это такое, — чуть ниже). Для него даже нет реализации на Флеше — это честный, бескомпромиссный HTML5.
Определенно, MPEG-DASH — самый настоящий HTML5-стриминг, за ним будущее.
▍MSE
Когда стало ясно, что Флеш всё-таки умрёт (после сотни ложных похорон), ребром встал вопрос о том, что придёт ему на смену. Хорошо было бы получить в браузерах возможность проигрывать видео по качеству и удобству близко к тому, что умеет Флеш (а он это делает всё-таки хорошо).
Во Флеше давно появился очень удобный механизм для универсального проигрывания разных вариантов — appendBytes. Суть в том, что пользовательский код сам как хочет скачивает кадры сжатого видео, упаковывает в оговоренный контейнер (с Флешем это flv) и засовывает в видеопроигрыватель. Т. е. протокол и транспорт реализуются в пользовательском коде, запускаемом в браузере.
MSE (Media Sources Extensions) — это расширение спецификации HTML5, которое позволяет делать то же, что делает appendBytes во Флеше. К сожалению, MSE намного сложнее как в понимании, так и в реализации.
MPEG-DASH, созданный на его базе, ещё хитрее, поэтому работать с ними то ещё удовольствие: тонны XML, парсинг бинарных контейнеров в Яваскрипте, непродуманные на этапе дизайна вопросы нарезки на сегменты — всё как мы любим, всё что нужно для единой безглючной реализации во всех браузерах.
Интересно, что MSE работает не только с MPEG-DASH, но и с HLS. Существует реализация hls.js, которая скачивает HLS-плейлисты, скачивает MPEG-TS-сегменты, перепаковывает их в нужный для MSE формат и играет через MSE. Эппл даже сделала шаг в сторону совместимости с MPEG-DASH — использование mp4-контейнеров в HLS.
К концу 2017 года Флеш скорее всего умрёт окончательно, и уже сегодня можно смело начинать проект с MPEG-DASH.
▍WebRTC
Во Флеше была сделана годная попытка в одной технологии реализовать и риалтайм-общение, и массовый броадкастинг. К сожалению, в HTML5 так не вышло. Для просмотра трансляций у нас есть MSE, а для видеозвонков — WebRTC.
WebRTC — это SIP в браузере: способ организовать аудио- и видеоканал и канал данных между двумя браузерами при посредничестве сервера.
Технология не предназначена для стриминга, но в принципе может и его, так что было бы неправильно забыть про него. WebRTC тоже считается HTML5, потому что вроде как ничего кроме Яваскрипта в браузере не требует. Зато требует наличия последних версий обоих популярных браузеров, а с Эджем пока вообще не совместимо.
Путаницу в понимании WebRTC вносит его использование в торрент-доставке телевидения. Суть в том, что браузеры через WebRTC организуют сеть каналов данных, а дальше по этой сети раздаются HLS- или MSE-сегменты видео, а проигрывание происходит через Флеш или MSE. Т. е. WebRTC — для доставки, MSE — для проигрывания. Важно не путать это с использованием WebRTC для проигрывания видео.
▍Так что там с mp4-стримингом?
Любой современный браузер скорее всего сможет по протоколу HTTP запросить файл, упакованный в транспорт mp4 и содержащий внутри видео, сжатое кодеком h264/aac. И даже попытаться проиграть его. Это самый удобный, понятный и стандартный вариант проигрывания файлов. Лежит себе файлик на диске, nginx его отдает. Код, проигрывающий mp4 в браузерах достаточно хорош. Например, он умеет даже скачивать куски видео по необходимости (в отличие от Флеш-плеера, который скачивает видео целиком).
Вокруг h264 сложилось немало шумихи по поводу его «закрытости» и «несвободности». Так что есть «открытая» альтернатива, которую форсит Гугл — видеокодеки vp8 и vp9, упакованные в транспорт WebM. WebM — это подмножество транспорта mkv (a. k. a. Матрёшка), который очень похож на mp4 по сути, но отличается от него своей «бинарностью».
Именно отсюда растут ноги у такого явления как «mp4-стриминг», который устроен как WebM. Дело в том что в обычном mp4 в самом начале указывается размер всего контейнера. Поэтому, если мы хотим отдать по обычному mp4 прямой эфир, у нас ничего не получится. А чтобы всё-таки получилось и можно было создавать mp4 без фиксированного конца, придуман следующий ход: сначала пишется mp4 без кадров, а потом в конце подписываются блоками по несколько секунд фрагменты с кадрами. Это называется mp4 fragmented, или mp4 streaming.
По сути это никакой не стриминг, а костыль, позволяющий создать его видимость. Mp4 — отличный формат для скачивания видео, но негодный для стриминга, так что про него можно просто забыть и никогда не использовать термин «mp4-стриминг».
▍Выводы
- Хорошие варианты HTML5-стриминга: MPEG-DASH и HLS. Они подходят и для мобильных устройств, и для ПК, и для приставок.
- Флеш всё-таки умрет, и MSE уже сейчас занимает его место.
- WebRTC — HTML5 технология, в первую очередь, для общения, а не для телевизионного вещания.
- Не приносите в веб старые кодеки и не пытайтесь доставлять mp2video и mp2audio по HLS, даже если ваш плеер это умеет.
- Никогда не говорите «mp4 стриминг». Пожалуйста.
Автор: Эрливидео