EME? CDM? DRM? CENC? IDK! Что нужно, чтобы сделать собственный видеоплеер в браузере +16


Что означают все эти аббревиатуры? Что нужно, чтобы разработать open source-плеер для просмотра видео с Amazon, Sky и других платформ и смотреть видео от любого провайдера? О том, как происходит процесс потоковой передачи видео, Себастьян Голаш (Sebastian Golasch) рассказал на конференции HolyJS 2018 Piter. Под катом — видео и перевод его доклада.



В данный момент Себастьян (Sebastian Golasch) занимает должность разработчика в Deutsche Telekom. Достаточно долго он работал с Java и PHP, а затем переключился на JS, Python и Rust. Последние семь лет трудится над фирменной платформой умного дома Qivicon.




Немного об истории потокового видео


Сначала давайте обратимся к истории веба, как мы пришли от QuickTime к Netflix за 25 лет. Все началось в 90-х, когда Apple изобрела QuickTime. Его использование в интернете началось в 1993-1994. В то время проигрыватель мог воспроизводить видео с разрешением 156?116 точек и частотой 10 FPS, без аппаратного ускорения (с использованием лишь ресурсов процессора). Такой формат был ориентирован на dial-up соединение 9600 бод – это 9600 бит в секунду, включая служебную информацию.

Это было время браузера Netscape. Видео в браузере выглядело не слишком хорошо, ведь оно не было нативным для веба. Для проигрывания использовалось внешнее программное обеспечение (тот же QuickTime) со своим интерфейсом, которое визуализировалось в браузере при помощи тега embed.



Ситуация стала немного лучше, когда Macromedia выпустила Shockwave Player (после поглощения Macromedia компанией Adobe он стал называться Adobe Flash Player). Первая версия Shockwave Player была выпущена в 1997 году, но воспроизведение видео в нем появилось лишь в 2002 году.

Там использовалсы кодек Sorenson Spark a.k.a. H.263. Он был оптимизирован для небольших разрешений и маленького размера файла. Что это значит? Например, видео продолжительностью 43 секунды, которое использовалось для тестирования Shockwave Player, весило всего 560 Кбайт. Конечно, фильм в таком качестве смотреть было бы не очень приятно, но сама технология для того времени была интересной. Однако, как и в случае с QuickTime, для работы Shockwave Player в браузере требовалась установка дополнительного ПО. У этого плеера было много проблем с безопасностью, но самое главное — это то, что видео все еще было надстройкой над браузером.

В 2007 году Microsoft выпустила Silverlight, чем-то напоминающий Flash. Мы не будем копать глубоко, но у всех этих решений было кое-что общее — «черный ящик». Все проигрыватели работали как надстройка над браузером, и вы понятия не имели, что происходит внутри.



Элемент <Video/>


В 2007 году компания Opera предложила использовать тег <Video/>, то есть сделать нативное видео в браузере. Мы используем его и сегодня. Это легко и удобно, и любое видео можно не только просмотреть, но и скачать. И если даже мы не хотим позволять скачивание видео, мы не можем запретить его загрузку в бразуер. Максимум — это сделать так, чтобы скачать видео было сложнее.



Тег <Video/> — полная противоположность «черному ящику», и просмотреть исходный код очень просто.



DRM


Однако вы не можете просто так кликнуть правой кнопкой мыши по видео на Netflix и выбрать пункт «Сохранить как». Причина этого — в DRM (Digital Restrictions Management, управление цифровыми ограничениями). Это не одна технология и не единое приложение, которое выполняет какую-либо задачу. Это общий термин для обозначения таких понятий, как:

  • Аутентификация и пользовательское шифрование
  • Шифрование, которое зависит от контента
  • Определение прав и применение ограничений
  • Отзыв и обновление
  • Контроль вывода и защита ссылок
  • Экспертиза и отслеживание нарушителей
  • Управление ключами и лицензиями

Чтобы понять, что из себя представляет DRM, нам нужно изучить его экосистему, то есть разобраться, какие компании вовлечены. Это:

  • Владельцы контента — находятся на вершине экосистемы. Например, Disney, MGM или FIFA. Эти компании производят контент, и у них есть права на него.
  • DRM Cores — это компании, которые предоставляют технологию DRM (например, Google, Apple, Microsoft и пр.) В настоящее время существует около 7–8 технологий DRM от разных компаний.
  • Поставщики услуг — разрабатывают серверное ПО, которое шифрует видео.
  • Браузеры, которые фактически являются проигрывателями.
  • Поставщики контента — это компании типа Netflix, Amazon, Sky и пр. Как правило, они не владеют правами на контент, они лицензируют и распространяют его.
  • Продавцы чипов/устройств — тоже вовлечены в экосистему, ведь DRM — это не только софтверная технология. Некоторые компании (преимущественно китайские) разрабатывают чипы, которые кодируют и декодируют видео.

Вы никогда не задумывались над тем, почему при просмотре видео на Netflix в браузере у него не очень большое разрешение (SD), но если посмотреть то же самое видео на Apple TV или на Android TV Box, тот же контент воспроизводится в Full HD или в 4K? За это тоже отвечает DRM. Дело в том, что производители всегда боятся пиратов, ворующих контент. Поэтому чем менее защищена среда, в которой выполняется декодирование видео, тем в более плохом качестве оно показывается пользователю. Например, если декодирование выполняется программно (например, в Chrome или Firefox), видео показывается в самом плохом качестве. В среде, где задействованы аппаратные возможности для декодирования (например, если Android использует GPU), возможностей нелегального копирования контента меньше, и тут качество воспроизведения выше. Наконец, самой защищенной средой считается полностью аппаратная (Apple TV или Android TV Box), где и декодирование, и воспроизведение выполняются без задействования программной части.



Но если говорить о браузерах, то в них декодирование почти всегда выполняется программными средствами. Разные браузеры используют разные системы для DRM. Chrome и Firefox используют Widevine. Эта компания принадлежит Google и лицензирует их DRM-приложения. Таким образом, для декодирования Firefoх скачивает DRM-библиотеку у Google. В браузере можно увидеть, откуда именно идет загрузка.



Apple использует собственную систему FairPlay, которая была создана еще тогда, когда компания представила первые iPhone и iPad. Microsoft также использует свою разработку под названием PlayReady, которая встроена прямо в Windows. В остальных случаях чаще всего используется Widevine. Эта система существует и как приложение, и в виде аппаратного решения — чипов, которые декодируют видео.

CDM


Аббревиатура CDM расшифровывается как Content Decryption Module (модуль декодирования контента). Это какая-то часть программного или аппаратного обеспечения, которая может работать несколькими способами:

  • Дешифровать видео, после чего оно визуализируется в браузере при помощи тега <Video/>.
  • Дешифровать и декодировать видео, после чего передавать необработанные кадры видео для воспроизведения браузеру.
  • Дешифровать и декодировать видео, после чего передавать необработанные кадры видео для воспроизведения при помощи GPU.

Несмотря на поддержку GPU, чаще всего используется второй вариант (по крайней мере если речь идет о Chrome и Firefox).

Cлои декодирования и дешифрования в браузере


Итак, как все это работает вместе? Чтобы это понять, посмотрим на слои декодирования и дешифрования в браузере. Они разделены на:

  • Приложение JavaScript — оно говорит компьютеру, какое видео я собираюсь смотреть.
  • Браузер — проигрыватель, который воспроизводит видеосодержимое.
  • Модуль дешифрования контента.
  • Управление цифровыми правами — все, что касается декодирования видео (я не мог придумать лучшего обозначения, поэтому назвал это именно так).
  • Доверенная исполняющая среда.
  • При этом два первых компонента являются DRM-плеером, модуль дешифрования контента — DRM-клиентом, а два последних компонента — ядром DRM.




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



В качестве примера будем использовать Netflix. Я написал приложение для дебаггинга.

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



Однако, если оставить только те, которые действительно нужны для воспроизведения видео, окажется, что их всего лишь три: manifest, license и первый фрагмент видео.



Плеер Netflix написан на JavaScript и содержит более 76 000 строчек кода, и, конечно, я не смогу разобрать его полностью. Но я хотел бы показать основные части, которые необходимы для воспроизведения защищенного видео.

Мы начнем с шаблона:



EME


Но прежде чем мы углубимся в функции, нам необходимо познакомиться с еще одной технологией — EME (Encrypted Media Extensions, зашифрованные медиарасширения). Эта технология не выполняет дешифрования и декодирования, это просто API браузера. EME служит интерфейсом для CDM, для KeySystem, для сервера с лицензией и для сервера, на котором хранится контент.

Итак, давайте начнем с getKeySystemConfig.



Стоит иметь в виду, что она зависит от провайдера, поэтому тот config, который я привожу тут, работает для Netflix, но не работает, скажем, для Amazon.

В этом config мы должны сказать бэкенд-системе, какой уровень доверенной исполняющей среды мы можем предложить. Это может быть безопасное аппаратное декодирование или безопасное программное декодирование. То есть мы говорим системе о том, какое аппаратное и программное обеспечение будет использоваться для воспроизведения. И это определит качество контента.



После настройки config посмотрим на создание initial MediaKeySystem.



Тут начинается взаимодействие с модулем дешифрования контента. Необходимо сообщить API, какую DRM-систему и KeySystem мы используем. В нашем случае это Widevine.



Следующий шаг необязателен для всех систем, но обязателен для Netflix. Опять же, его необходимость зависит от провайдера. Нам нужно применить к нашим mediaKeys сертификат сервера. Сертификаты сервера представляют собой обычный текст в файле Cadmium.js от Netflix, который можно легко копировать. И когда мы применяем его к mediaKeys, то все общение между сервером с лицензией и нашим браузером становится безопасным благодаря использованию этого сертификата.



Когда это сделано, мы должны обратиться к оригинальному элементу видео и сказать: «Ок, это система ключей, которую мы хотим использовать, а это тег hello video. Давайте мы вас объединим».



А вот последняя функция, которая нужна для настройки видеосистемы.



Это DRM-сессия, или MediaKeySession. Это просто данные, которые идут от провайдера к модулю дешифрования, который подписывает ими запросы. Эти данные также представляют собой обычный текст, который спрятан за несколькими функциями в файле плеера Netflix, откуда я его и скопировал.



Когда мы вызываем create.Session в объекте mediaKeys, необходимо сообщить, какое видео мы поддерживаем. В данном случае это mp4. Это возвращает нас к контексту обмена сообщениями с нашей системой CDM. Нам также нужно, чтобы Netflix применил сертификат сервера в base64 в каждой форме, но весь этот config в сессии create снова предоставляется зависимым от DRM-системы.



Последняя функция тут внизу — keySession.generateRequest строит лицензионный запрос в фоне. Или CDM строит лицензионный запрос в фоне. Иными словами, это необработанные бинарные данные, которые мы должны отправить на лицензионный сервер, чтобы взамен получить действующую лицензию.



Тут интерес представляет cenc. Это ISO-стандарт шифрования, определяющий схему защиты для mp4-видео. У WebM это называется по-другому, но функцию выполняет ту же.

handleMessage — это интерфейс EventListener, который мы настраивали. Когда это событие вызывается событием message в keySession, мы знаем, что мы готовы получить лицензию с сервера.



И в этом callback мы лишь получаем запрос на сервер с лицензией, который отдает некоторые бинарные данные (они также могут отличаться в зависимости от провайдера). Эти данные мы используем для обновления текущей сессии, добавляя лицензию. То есть как только мы получили действующую лицензию с сервера, наша CDM знает, что мы можем декодировать и дешифровать видео.



Если применить это к диаграмме ниже, то получим вот что: мы хотим проиграть видео, и JavaScript-приложение говорит: «Привет, браузер! Я хочу проиграть видео!» — затем использует Encrypted Media Extensions и делает запрос к License Functions в Widevine CDM на получение лицензии. Этот запрос затем возвращается обратно в браузер, и мы можем обменять его на действующую лицензию на сервере лицензий, и затем нужно передать эту лицензию обратно к CDM. Этот процесс и был показан на коде выше.



Но обратите внимание, что мы еще не проиграли ни секунды видео, и это все нам нужно сделать, чтобы в будущем иметь возможность воспроизвести какие-нибудь видеоролики.

MSE


И еще одна технология, которую нам нужно исследовать, — это MSE (Media Source Extensions, расширения для источников мультимедиа). Ее можно назвать сводной сестрой EME (Encrypted Media Extensions). Это тоже API браузера, и она не имеет никакого отношения к DRM. Я рассматриваю ее как программный интерфейс к <Video/> Src. С ее помощью можно создавать бинарные потоки в JavaScript и применять фрагменты видео к элементу <Video/>. Таким образом, благодаря ей исходник тега <Video/> становится динамическим.

Итак, мы можем использовать расширения для источников мультимедиа, инстанцировать и сделать обращение к видео, после чего загрузить фрагменты видео по частям и применить их к тегу <Video/>.



Смысл в том, что, когда вы смотрите двухчасовое видео, вы не хотите ждать, пока оно загрузится полностью. Вместо этого вы разрезаете его на небольшие фрагменты размером примерно от 30 секунд до 2 минут и поочередно применяете их к элементу <Video/>.

Как только наш буфер MediaSource готов и прилинкован к элементу <Video/>, мы можем добавить SourceBuffer. Мы снова должны сказать ему, какой формат видео и какие кодеки мы используем, и тогда он будет создан.



Наконец теперь мы можем начать делать fetch из отдельных фрагментов и отправлять их на нашем SourceBuffer методом append к элементу <Video/>, получая динамически созданное видео. Это также можно использовать для других use-кейсов, когда люди могут самостоятельно комбинировать разные элементы видео, создавая собственные ролики, но мне не хотелось бы зарываться в это слишком глубоко.



Итак, это почти последний шаг, который мы должны сделать. У вас есть сеть распространения информации, у вас есть фрагменты, и затем браузер отправляет зашифрованные и сжатые фрагменты к CDM, где выполняется дешифрование и, возможно, декодирование. Затем дешифрованные и несжатые фрагменты отправляются обратно в браузер, где они визуализируются и показываются.



Manifest


Но есть еще один момент. Как мы узнаем, какие фрагменты нам нужно загрузить, откуда их загружать и когда? И это последняя часть, отсутствующий запрос из манифеста. Когда мы делаем запрос к Netflix за манифестом, ему требуется много данных. Если мы просто хотим проиграть видео, то для нас имеет значение, какую DRM-систему мы используем, какое видео мы хотим просмотреть (Netflix ID, который можно скопировать из URL) и профили. Профили определяют, в каком разрешении мы получаем видео, а также на каком языке мы получаем аудиодорожки, в каком формате (stereo, Dolby Digital и пр.), используем ли мы субтитры и т. д.



MPEG-DASH


Наиболее часто используемым форматом манифеста является MPEG-DASH. Правда, Apple использует иной формат — HSL, который по виду напоминает список файлов в старом плеере Winamp. Но Widevine и Microsoft используют именно MPEG-DASH. В его основе лежит XML, и он определяет все: продолжительность, размер буфера, типы контента, когда какие фрагменты загружаются, фрагменты для разных разрешений, а также адаптивное переключение битрейта. Последнее означает, что в случае если пользователь, например, смотрит видео и при этом скорость загрузки падает, воспроизведение не останавливается, а просто ухудшается качество видео. Это происходит за счет того, что в манифесте определены одни и те же части для разных разрешений, у них одна и та же продолжительность и одни и те же индексы. Поэтому при уменьшении скорости загрузки браузер может просто переключиться на поток с более низким разрешением, не приостанавливая загрузку и не буферизируя данные.

Вот так выглядит манифест для фильма «Стражи Галактики». В нем мы можем увидеть, что при разной скорости загрузки люди получат видео с разным качеством, а также то, что существуют аудиодорожки для людей с нарушениями слуха. В нем также прописано наличие субтитров.



У нас есть продолжительность и указание на время, с которого надо начать воспроизведение. Эта функция используется, например, тогда, когда вы прерываете просмотр и затем снова возвращаетесь к видео, начиная с того места, где остановились.



Тут также снова есть robustness, который говорит: вот этот фрагмент можно проиграть только в том случае, если ваша система соответствует требованиям. В данном случае это декодирование с помощью аппаратных средств — Hardware Secure Codecs.



Для одной и той же части видео можно определить сколько угодно фрагментов с разными разрешениями.



И затем вы получаете URL для загрузки фрагмента, а параметр range показывает диапазон значений в миллисекундах.



Это и есть последняя часть. Вы также иногда получаете манифест из CDN. У некоторых провайдеров есть отдельный сервер для доставки фрагментов, но чаще всего они приходят с той же машины, что и функциональность манифеста. Когда мы скачали манифест, мы знаем, какие фрагменты нам нужно загрузить, мы можем отправить запрос на фрагменты, после чего дешифровать и декодировать из CDM.



В общем-то, это все. Всего, что было сказано выше, достаточно для того, чтобы разработать open source плеер для просмотра видео с Amazon, Sky и других платформ и смотреть видео почти любого провайдера.

MSL


В Netflix посчитали, что стоит добавить дополнительное шифрование сообщений между браузером и сервером. Они назвали это «слой безопасности сообщений» — Message Security Layer, или MSL. Он ничего не делает с видео напрямую, это просто дополнительный слой шифрования. Одна из причин внедрения MSL в том, что HTTPS недостаточно безопасен. С другой стороны, MSL имеет открытый исходный код, поэтому всегда можно посмотреть, как он работает. Тут я не собираюсь углубляться в эту тему, и, если вам это интересно, вы всегда можете найти информацию о том, зачем Netflix делает MSL, в их блоге. На GitHub есть подробная документация по его внедрению и рабочие реализации на Java.

Также есть реализация на Python, которую мы написали с друзьями. Насколько я знаю, это единственный рабочий open source клиент для Netflix. Он работает с Kodi Media Center. Для визуализации можно использовать VLC Player или любое другое подходящее ПО.

И снова «черный ящик»


Итак, вы увидели, что нам понадобилось, чтобы внедрить все это, и насколько часто я упоминал CDM — «черный ящик», который загружается с сайта Google. Таким образом, мы снова вернули видео в «черный ящик». Прекрасный элемент <Video/> снова спрятан от нас. Мы добавили стороннее программное обеспечение, которое нам помогает, но которое при этом является закрытым и которым мы не можем управлять. Оно может делать много незаметных вещей: трекинг, аналитику, отправку данных…



Вот что по этому поводу говорил Тим Бернерс Ли: «Таким образом, в целом важно поддерживать EME как относительно безопасную онлайн-среду, в которой можно смотреть фильмы, а также как наиболее удобную и такую, которая делает ее частью взаимосвязанного дискурса человечества».

Но есть и другие мнения относительно этого. В частности, от Electronic Frontiers Foundation, которая до появления DRM была участником W3C. Вот что они говорят: «В 2013 году EFF была разочарована, узнав, что W3C взяла на себя проект стандартизации EME — зашифрованных медиарасширений. По сути, мы говорим об API, единственной функцией которого должно было стать обеспечение для DRM главной роли в экосистеме браузера. Мы будем продолжать бороться за то, чтобы интернет был свободным и открытым. Мы будем продолжать судиться с правительством США, чтобы отменить законы, которые делают DRM таким токсичным, и мы будем продолжать бороться на уровне общемирового законодательства».

Мне сложно сказать, как к этому относиться. С одной стороны, я всегда за открытый и свободный интернет, в браузерах которого нет закрытого кода, который может отправлять запросы неизвестно куда. С другой стороны, нам нужны сервисы наподобие Netflix, которые взимают плату за видео. Возможно, они могли бы создать собственные приложения для воспроизведения, и тогда интернет отказался бы от такого рода контента.

Уже через месяц, 24-25 ноября, в Москве пройдет HolyJS 2018 Moscow, где Себастьян выступит с докладом «The Universal Serial Web»: подробно разберет новый стандарт WebUSB, возможность работать с USB-устройствами из браузера. Всё это с живыми демо-примерами, очень интересно и наглядно.

P.S. С 1-го ноября установится финальная цена на билеты. Всем, кто идет за свои — скидка 50% от стандартной цены.




К сожалению, не доступен сервер mySQL