ЭМЕ, какого черта?

Введение в расширения зашифрованного мультимедиа

Encrypted Media Extensions предоставляет API, который позволяет веб-приложениям взаимодействовать с системами защиты контента, позволяя воспроизводить зашифрованные аудио и видео.

EME разработан так, чтобы одно и то же приложение и зашифрованные файлы можно было использовать в любом браузере, независимо от базовой системы защиты. Первое стало возможным благодаря стандартизированным API и потоку, а второе стало возможным благодаря концепции общего шифрования.

EME — это расширение спецификации HTMLMediaElement , отсюда и название. Будучи «расширением», означает, что поддержка EME браузером не является обязательной: если браузер не поддерживает зашифрованные носители, он не сможет воспроизводить зашифрованные носители, но EME не требуется для соответствия спецификациям HTML. Из спецификации EME :

Реализации EME используют следующие внешние компоненты:

  • Ключевая система: механизм защиты контента (DRM). EME не определяет сами системы ключей, за исключением Clear Key (подробнее об этом ниже).
  • Модуль расшифровки контента (CDM): программный или аппаратный механизм на стороне клиента, который позволяет воспроизводить зашифрованные носители. Как и в случае с ключевыми системами, EME не определяет никаких CDM, но предоставляет приложениям интерфейс для взаимодействия с доступными CDM.
  • Сервер лицензий (ключей): взаимодействует с CDM для предоставления ключей для расшифровки мультимедиа. За согласование с сервером лицензий отвечает приложение.
  • Служба упаковки: кодирует и шифрует носители для распространения/потребления.

Обратите внимание, что приложение, использующее EME, взаимодействует с сервером лицензий, чтобы получить ключи для дешифрования, но идентификация пользователя и аутентификация не являются частью EME. Получение ключей для включения воспроизведения мультимедиа происходит после (необязательно) аутентификации пользователя. Такие службы, как Netflix, должны аутентифицировать пользователей в своем веб-приложении: когда пользователь входит в приложение, приложение определяет его личность и привилегии.

Как работает ЭМЕ?

Вот как взаимодействуют компоненты EME, что соответствует примеру кода ниже:

  1. Веб-приложение пытается воспроизвести аудио или видео, содержащее один или несколько зашифрованных потоков.
  2. Браузер распознает, что носитель зашифрован (см. поле ниже, как это происходит), и запускает encrypted событие с метаданными ( initData ), полученными от носителя о шифровании.
  3. Приложение обрабатывает encrypted событие:
    1. Если объект MediaKeys не связан с медиа-элементом, сначала выберите доступную систему ключей с помощью navigator.requestMediaKeySystemAccess() , чтобы проверить, какие системы ключей доступны, затем создайте объект MediaKeys для доступной системы ключей с помощью объекта MediaKeySystemAccess . Обратите внимание, что инициализация объекта MediaKeys должна произойти до первого encrypted события. Получение URL-адреса сервера лицензий осуществляется приложением независимо от выбора доступной системы ключей. Объект MediaKeys представляет все ключи, доступные для расшифровки мультимедиа для аудио- или видеоэлемента. Он представляет собой экземпляр CDM и обеспечивает доступ к CDM, в частности, для создания сеансов ключей, которые используются для получения ключей с сервера лицензий.
    2. После создания объекта MediaKeys назначьте его медиа-элементу: setMediaKeys() связывает объект MediaKeys с HTMLMediaElement, чтобы его ключи можно было использовать во время воспроизведения, то есть во время декодирования.
  4. Приложение создает MediaKeySession , вызывая createSession() для MediaKeys . При этом создается MediaKeySession , который представляет срок действия лицензии и ее ключей.
  5. Приложение генерирует запрос лицензии, передавая медиаданные, полученные в encrypted обработчике, в CDM, вызывая generateRequest() в MediaKeySession .
  6. CDM запускает событие message : запрос на получение ключа от сервера лицензий.
  7. Объект MediaKeySession получает событие message , и приложение отправляет сообщение на сервер лицензий (например, через XHR).
  8. Приложение получает ответ от сервера лицензий и передает данные в CDM, используя метод update() класса MediaKeySession .
  9. CDM расшифровывает носитель, используя ключи лицензии. Можно использовать действительный ключ из любого сеанса в пределах MediaKey , связанного с медиа-элементом. CDM получит доступ к ключу и политике, индексированным по идентификатору ключа.
  10. Воспроизведение мультимедиа возобновляется.

Уф…

Обратите внимание, что между CDM и сервером лицензий может быть несколько сообщений, и вся связь в этом процессе непрозрачна для браузера и приложения: сообщения понимаются только CDM и сервером лицензий, хотя уровень приложения может видеть , какой тип сообщения CDM отправляет. Запрос лицензии содержит подтверждение действительности CDM (и доверительных отношений), а также ключ, который будет использоваться при шифровании ключа(ов) контента в полученной лицензии.

…но чем на самом деле занимаются CDM?

Реализация EME сама по себе не обеспечивает способ расшифровки мультимедиа: она просто предоставляет API для веб-приложения для взаимодействия с модулями расшифровки контента.

То, что на самом деле делают CDM, не определено спецификацией EME, и CDM может обрабатывать как декодирование (распаковку) мультимедиа, так и дешифрование. Существует несколько потенциальных вариантов функциональности CDM, от наименее до наиболее надежного:

  • Только расшифровка, обеспечивающая воспроизведение с использованием обычного медиаконвейера, например, через элемент <video> .
  • Расшифровка и декодирование, передача видеокадров в браузер для рендеринга.
  • Расшифровка и декодирование, рендеринг непосредственно в оборудовании (например, в графическом процессоре).

Существует несколько способов сделать CDM доступным для веб-приложения:

  • Объедините CDM с браузером.
  • Распространите CDM отдельно.
  • Встройте CDM в операционную систему.
  • Включите CDM в прошивку.
  • Встройте CDM в аппаратное обеспечение.

Способ предоставления CDM не определяется спецификацией EME, но во всех случаях браузер несет ответственность за проверку и раскрытие CDM.

EME не требует использования конкретной системы ключей; Среди современных настольных и мобильных браузеров Chrome поддерживает Widevine, а IE11 поддерживает PlayReady.

Получение ключа с сервера лицензий

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

Следующий код (адаптированный из примеров спецификации ) показывает, как приложение может выбрать подходящую систему ключей и получить ключ с сервера лицензий.

var video = document.querySelector('video');

var config = [{initDataTypes: ['webm'],
  videoCapabilities: [{contentType: 'video/webm; codecs="vp9"'}]}];

if (!video.mediaKeys) {
  navigator.requestMediaKeySystemAccess('org.w3.clearkey',
      config).then(
    function(keySystemAccess) {
      var promise = keySystemAccess.createMediaKeys();
      promise.catch(
        console.error.bind(console, 'Unable to create MediaKeys')
      );
      promise.then(
        function(createdMediaKeys) {
          return video.setMediaKeys(createdMediaKeys);
        }
      ).catch(
        console.error.bind(console, 'Unable to set MediaKeys')
      );
      promise.then(
        function(createdMediaKeys) {
          var initData = new Uint8Array([...]);
          var keySession = createdMediaKeys.createSession();
          keySession.addEventListener('message', handleMessage,
              false);
          return keySession.generateRequest('webm', initData);
        }
      ).catch(
        console.error.bind(console,
          'Unable to create or initialize key session')
      );
    }
  );
}

function handleMessage(event) {
  var keySession = event.target;
  var license = new Uint8Array([...]);
  keySession.update(license).catch(
    console.error.bind(console, 'update() failed')
  );
}

Общее шифрование

Решения Common Encryption позволяют поставщикам контента шифровать и упаковывать свой контент один раз для каждого контейнера/кодека и использовать его с различными ключевыми системами, CDM и клиентами: то есть с любым CDM, поддерживающим Common Encryption. Например, видео, упакованное с помощью Playready, можно воспроизвести в браузере с помощью CDM Widevine, получившего ключ с сервера лицензий Widevine.

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

Common Encryption (CENC) — это стандарт ISO , определяющий схему защиты ISO BMFF; аналогичная концепция применима и к WebM.

Очистить ключ

Хотя EME не определяет функциональность DRM, в настоящее время спецификация требует, чтобы все браузеры, поддерживающие EME, реализовывали Clear Key. Используя эту систему, медиафайлы можно зашифровать с помощью ключа, а затем воспроизвести, просто предоставив этот ключ. Clear Key может быть встроен в браузер: он не требует использования отдельного модуля расшифровки.

Хотя Clear Key вряд ли будет использоваться для многих типов коммерческого контента, он полностью совместим со всеми браузерами, поддерживающими EME. Это также удобно для тестирования реализаций EME и приложений, использующих EME, без необходимости запрашивать ключ контента с сервера лицензий. На simpl.info/ck есть простой пример Clear Key. Ниже приведено пошаговое описание кода, которое аналогично описанным выше шагам, но без взаимодействия с сервером лицензий.

// Define a key: hardcoded in this example
// – this corresponds to the key used for encryption
var KEY = new Uint8Array([
  0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b,
  0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c
]);

var config = [{
  initDataTypes: ['webm'],
  videoCapabilities: [{
    contentType: 'video/webm; codecs="vp8"'
  }]
}];

var video = document.querySelector('video');
video.addEventListener('encrypted', handleEncrypted, false);

navigator.requestMediaKeySystemAccess('org.w3.clearkey', config).then(
  function(keySystemAccess) {
    return keySystemAccess.createMediaKeys();
  }
).then(
  function(createdMediaKeys) {
    return video.setMediaKeys(createdMediaKeys);
  }
).catch(
  function(error) {
    console.error('Failed to set up MediaKeys', error);
  }
);

function handleEncrypted(event) {
  var session = video.mediaKeys.createSession();
  session.addEventListener('message', handleMessage, false);
  session.generateRequest(event.initDataType, event.initData).catch(
    function(error) {
      console.error('Failed to generate a license request', error);
    }
  );
}

function handleMessage(event) {
  // If you had a license server, you would make an asynchronous XMLHttpRequest
  // with event.message as the body.  The response from the server, as a
  // Uint8Array, would then be passed to session.update().
  // Instead, we will generate the license synchronously on the client, using
  // the hard-coded KEY at the top.
  var license = generateLicense(event.message);

  var session = event.target;
  session.update(license).catch(
    function(error) {
      console.error('Failed to update the session', error);
    }
  );
}

// Convert Uint8Array into base64 using base64url alphabet, without padding.
function toBase64(u8arr) {
  return btoa(String.fromCharCode.apply(null, u8arr)).
      replace(/\+/g, '-').replace(/\//g, '_').replace(/=*$/, '');
}

// This takes the place of a license server.
// kids is an array of base64-encoded key IDs
// keys is an array of base64-encoded keys
function generateLicense(message) {
  // Parse the clearkey license request.
  var request = JSON.parse(new TextDecoder().decode(message));
  // We only know one key, so there should only be one key ID.
  // A real license server could easily serve multiple keys.
  console.assert(request.kids.length === 1);

  var keyObj = {
    kty: 'oct',
    alg: 'A128KW',
    kid: request.kids[0],
    k: toBase64(KEY)
  };
  return new TextEncoder().encode(JSON.stringify({
    keys: [keyObj]
  }));
}

Чтобы протестировать этот код, вам понадобится зашифрованное видео для воспроизведения. Шифрование видео для использования с помощью Clear Key можно выполнить для WebM в соответствии с инструкциями webm_crypt . Также доступны коммерческие услуги (по крайней мере, для ISO BMFF/MP4) и разрабатываются другие решения.

Расширения медиа-источников (MSE)

HTMLMediaElement — это создание простой красоты.

Мы можем загружать, декодировать и воспроизводить мультимедиа, просто указав URL-адрес src:

<video src='foo.webm'></video>

API источника мультимедиа — это расширение HTMLMediaElement, обеспечивающее более детальный контроль над источником мультимедиа, позволяя JavaScript создавать потоки для воспроизведения из «кусков» видео. Это, в свою очередь, позволяет использовать такие методы, как адаптивная потоковая передача и сдвиг во времени.

Почему MSE важен для EME? Потому что помимо распространения защищенного контента поставщики коммерческого контента должны иметь возможность адаптировать доставку контента к условиям сети и другим требованиям. Netflix, например, динамически меняет битрейт потока при изменении условий сети. EME работает с воспроизведением медиапотоков, предоставляемых реализацией MSE, так же, как и с мультимедиа, предоставляемым через атрибут src .

Как разбить и воспроизвести медиафайлы, закодированные с разным битрейтом? См. раздел DASH ниже.

Вы можете увидеть MSE в действии по адресу simpl.info/mse ; для целей этого примера видео WebM разделено на пять частей с помощью API-интерфейсов файлов. В производственном приложении фрагменты видео будут извлекаться через Ajax.

Сначала создается SourceBuffer:

var sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vorbis,vp8"');

Затем весь фильм «транслируется» в элемент видео путем добавления каждого фрагмента с помощью метода AppendBuffer():

reader.onload = function (e) {
  sourceBuffer.appendBuffer(new Uint8Array(e.target.result));
  if (i === NUM_CHUNKS - 1) {
    mediaSource.endOfStream();
  } else {
    if (video.paused) {
      // start playing after first chunk is appended
      video.play();
    }
    readChunk_(++i);
  }
};

Узнайте больше о MSE в статье HTML5 Rocks .

Динамическая адаптивная потоковая передача через HTTP (DASH)

Мульти-устройство, мультиплатформенность, мобильность — как бы вы это ни называли, Интернет часто работает в условиях изменчивого подключения. Динамическая, адаптивная доставка имеет решающее значение для преодоления ограничений пропускной способности и изменчивости в мире множества устройств.

DASH (также известный как MPEG-DASH) предназначен для обеспечения наилучшей доставки мультимедиа в нестабильном мире как для потоковой передачи, так и для загрузки. Некоторые другие технологии делают нечто подобное, например, HTTP Live Streaming (HLS) от Apple и Smooth Streaming от Microsoft, но DASH — единственный метод потоковой передачи с адаптивным битрейтом через HTTP, основанный на открытом стандарте. DASH уже используется на таких сайтах, как YouTube.

Какое это имеет отношение к EME и MSE? Реализации DASH на основе MSE могут анализировать манифест, загружать сегменты видео с соответствующим битрейтом и передавать их видеоэлементу, когда он становится голодным, используя существующую инфраструктуру HTTP.

Другими словами, DASH позволяет поставщикам коммерческого контента осуществлять адаптивную потоковую передачу защищенного контента.

DASH делает то, что написано на банке:

  • Динамический: реагирует на изменяющиеся условия.
  • Адаптивный: адаптируется для обеспечения соответствующего битрейта аудио или видео.
  • Потоковая передача: позволяет как потоковую передачу, так и загрузку.
  • HTTP: обеспечивает доставку контента с преимуществами HTTP, без недостатков традиционного сервера потоковой передачи.

BBC начала предоставлять тестовые трансляции с использованием DASH :

Обобщить:

  1. Мультимедиа кодируется с разными битрейтами.
  2. Файлы с различным битрейтом доступны с HTTP-сервера.
  3. Клиентское веб-приложение выбирает битрейт для получения и воспроизведения с помощью DASH.

В рамках процесса сегментации видео программно создается XML-манифест, известный как описание медиапрезентации (MPD). Здесь описываются наборы адаптации и представления с длительностью и URL-адресами. МПД выглядит следующим образом:

<MPD xmlns="urn:mpeg:DASH:schema:MPD:2011" mediaPresentationDuration="PT0H3M1.63S" minBufferTime="PT1.5S" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011"
type="static">
  <Period duration="PT0H3M1.63S" start="PT0S">
    <AdaptationSet>
      <ContentComponent contentType="video" id="1" />
      <Representation bandwidth="4190760" codecs="avc1.640028" height="1080" id="1" mimeType="video/mp4" width="1920">
        <BaseURL>car-20120827-89.mp4</BaseURL>
        <SegmentBase indexRange="674-1149">
          <Initialization range="0-673" />
        </SegmentBase>
      </Representation>
      <Representation bandwidth="2073921" codecs="avc1.4d401f" height="720" id="2" mimeType="video/mp4" width="1280">
        <BaseURL>car-20120827-88.mp4</BaseURL>
        <SegmentBase indexRange="708-1183">
          <Initialization range="0-707" />
        </SegmentBase>
      </Representation>

      …

    </AdaptationSet>
  </Period>
</MPD>

(Этот XML-файл взят из файла .mpd, используемого для демонстрационного проигрывателя YouTube DASH .)

Согласно спецификации DASH, файл MPD теоретически может использоваться в качестве src видео. Однако, чтобы предоставить веб-разработчикам больше гибкости, производители браузеров решили оставить поддержку DASH на усмотрение библиотек JavaScript, использующих MSE, таких как Dash.js. Реализация DASH в JavaScript позволяет алгоритму адаптации развиваться без необходимости обновления браузера. Использование MSE также позволяет экспериментировать с альтернативными форматами манифестов и механизмами доставки, не требуя изменений в браузере. Google Shaka Player реализует клиент DASH с поддержкой EME.

В сети разработчиков Mozilla есть инструкции по использованию инструментов WebM и FFmpeg для сегментации видео и построения MPD.

Заключение

Использование Интернета для доставки платного видео и аудио растет огромными темпами . Кажется, что каждое новое устройство, будь то планшет, игровая консоль, подключенный телевизор или телеприставка, способно передавать потоковое мультимедиа от основных поставщиков контента через HTTP. Более 85% мобильных и настольных браузеров теперь поддерживают <video> и <audio> , и, по оценкам Cisco, к 2017 году видео будет составлять от 80 до 90 процентов глобального потребительского интернет-трафика. В этом контексте поддержка браузерами защищенного распространения контента, вероятно, будет становится все более значимым, поскольку производители браузеров сокращают поддержку API, на которые опирается большинство медиа-плагинов.

дальнейшее чтение

Спецификации и стандарты

Статьи