EME WTF?

Présentation des API Encrypted Media Extensions

Les API Encrypted Media Extensions permettent aux applications Web d'interagir avec des systèmes de protection de contenu pour permettre la lecture de contenus audio et vidéo chiffrés.

EME est conçu pour permettre d'utiliser la même application et les mêmes fichiers chiffrés dans n'importe quel navigateur, quel que soit le système de protection sous-jacent. Le premier est possible grâce aux API et à la procédure standardisées, tandis que le second est rendu possible grâce au concept de chiffrement commun.

EME est une extension de la spécification HTMLMediaElement, d'où son nom. Le terme "extension" signifie que la compatibilité du navigateur avec EME est facultative: si un navigateur n'est pas compatible avec un contenu multimédia chiffré, il ne pourra pas lire ce type de contenu, mais l'EME n'est pas requis pour la conformité avec les spécifications HTML. À partir des spécifications EME:

Les implémentations d'EME utilisent les composants externes suivants:

  • Système de clés:mécanisme de protection du contenu (DRM). L'EME ne définit pas lui-même les systèmes de clés, à l'exception de "Clear Key" (Effacer la clé) (plus d'informations à ce sujet ci-dessous).
  • Module de déchiffrement de contenu (CDM) : mécanisme logiciel ou matériel côté client qui permet la lecture de contenus multimédias chiffrés. Comme pour Key Systems, l'EME ne définit pas de CDM, mais fournit une interface permettant aux applications d'interagir avec les CDM disponibles.
  • Serveur de licence (clé):interagit avec un CDM pour fournir des clés permettant de déchiffrer le contenu multimédia. La négociation avec le serveur de licences relève de la responsabilité de l'application.
  • Service de packaging:encode et chiffre les médias en vue de leur distribution/consommation.

Notez qu'une application qui utilise EME interagit avec un serveur de licences pour obtenir les clés permettant le déchiffrement, mais l'identité et l'authentification des utilisateurs ne font pas partie de l'EME. La récupération des clés pour permettre la lecture de contenus multimédias a lieu après (éventuellement) l'authentification de l'utilisateur. Les services tels que Netflix doivent authentifier les utilisateurs dans leur application Web: lorsqu'un utilisateur se connecte à l'application, celle-ci détermine l'identité et les privilèges de l'utilisateur.

Comment fonctionne l'EME ?

Voici comment les composants d'EME interagissent, correspondant à l'exemple de code ci-dessous:

  1. Une application Web tente de lire un contenu audio ou vidéo comportant un ou plusieurs flux chiffrés.
  2. Le navigateur reconnaît que le contenu multimédia est chiffré (voir l'encadré ci-dessous pour en savoir plus) et déclenche un événement encrypted avec des métadonnées (initData) obtenues auprès du média à propos du chiffrement.
  3. L'application gère l'événement encrypted :
    1. Si aucun objet MediaKeys n'a été associé à l'élément multimédia, sélectionnez d'abord un système de clés disponible à l'aide de navigator.requestMediaKeySystemAccess() pour vérifier quels systèmes de clés sont disponibles, puis créez un objet MediaKeys pour un système de clés disponible via un objet MediaKeySystemAccess. Notez que l'initialisation de l'objet MediaKeys doit avoir lieu avant le premier événement encrypted. L'application se charge d'obtenir l'URL d'un serveur de licences indépendamment de la sélection d'un système de clés disponible. Un objet MediaKeys représente toutes les clés disponibles pour déchiffrer le contenu multimédia d'un élément audio ou vidéo. Il représente une instance CDM et permet d'accéder au CDM, en particulier pour créer des sessions de clés, qui permettent d'obtenir des clés auprès d'un serveur de licences.
    2. Une fois l'objet MediaKeys créé, affectez-le à l'élément multimédia: setMediaKeys() associe l'objet MediaKeys à un HTMLMediaElement, afin que ses touches puissent être utilisées pendant la lecture, c'est-à-dire lors du décodage.
  4. L'application crée un MediaKeySession en appelant createSession() sur MediaKeys. Cela crée un MediaKeySession, qui représente la durée de vie d'une licence et de sa ou ses clés.
  5. L'application génère une demande de licence en transmettant les données multimédias obtenues dans le gestionnaire encrypted au CDM, en appelant generateRequest() sur le MediaKeySession.
  6. Le CDM déclenche un événement message, à savoir une demande d'acquisition d'une clé auprès d'un serveur de licences.
  7. L'objet MediaKeySession reçoit l'événement message et l'application envoie un message au serveur de licences (via XHR, par exemple).
  8. L'application reçoit une réponse du serveur de licences et transmet les données au CDM à l'aide de la méthode update() de MediaKeySession.
  9. Le CDM déchiffre le contenu multimédia à l'aide des clés de la licence. Une clé valide peut être utilisée depuis n'importe quelle session au sein des MediaKeys associés à l'élément multimédia. Le CDM accède à la clé et à la stratégie, indexées par ID de clé.
  10. La lecture des contenus multimédias reprend.

Ouf...

Notez qu'il peut y avoir plusieurs messages entre le CDM et le serveur de licences, et que toutes les communications de ce processus sont opaques pour le navigateur et l'application: les messages sont uniquement compris par le CDM et le serveur de licences, bien que la couche d'application puisse voir quel type de message le CDM envoie. La demande de licence contient la preuve de la validité du CDM (et de la relation de confiance), ainsi qu'une clé à utiliser pour chiffrer les clés de contenu de la licence obtenue.

... mais que font réellement les CDM ?

Une implémentation EME ne permet pas à elle seule de déchiffrer des contenus multimédias. Elle fournit simplement une API permettant à une application Web d'interagir avec les modules de déchiffrement de contenu.

Le fonctionnement des CDM n'est pas défini par la spécification EME, et un CDM peut gérer le décodage (décompression) des médias ainsi que le déchiffrement. Il existe plusieurs options possibles pour la fonctionnalité CDM, de la moins à la plus robuste:

  • Déchiffrement uniquement, activation de la lecture à l'aide du pipeline multimédia normal, par exemple via un élément <video>.
  • Déchiffrement et décodage, transmission des images vidéo au navigateur pour le rendu
  • Déchiffrement et décodage, rendu direct dans le matériel (par exemple, le GPU)

Il existe plusieurs façons de mettre un CDM à la disposition d'une application Web:

  • Incluez un CDM dans le navigateur.
  • Distribuez un CDM séparément.
  • Intégrer un CDM dans le système d'exploitation
  • Incluez un CDM dans le micrologiciel.
  • Intégrez un CDM dans le matériel.

Les spécifications EME ne définissent pas la manière dont un CDM est disponible, mais dans tous les cas, le navigateur est chargé d'examiner et d'exposer le CDM.

EME n'impose aucun système de clés particulier. Parmi les navigateurs mobiles et de bureau actuels, Chrome est compatible avec Widevine et IE11 est compatible avec PlayReady.

Obtenir une clé auprès d'un serveur de licences

Dans le cadre d'une utilisation commerciale classique, le contenu est chiffré et encodé à l'aide d'un service ou d'un outil de packaging. Une fois les médias chiffrés mis à disposition en ligne, un client Web peut obtenir une clé (contenue dans une licence) auprès d’un serveur de licences et l’utiliser pour permettre le déchiffrement et la lecture du contenu.

Le code suivant (adapté à partir des exemples de spécifications) montre comment une application peut sélectionner un système de clés approprié et obtenir une clé auprès d'un serveur de licences.

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')
  );
}

Chiffrement courant

Les solutions de chiffrement courantes permettent aux fournisseurs de contenu de chiffrer et de packager leur contenu une seule fois par conteneur/codec et de l'utiliser avec divers systèmes de clés, CDM et clients, c'est-à-dire tout CDM compatible avec le chiffrement commun. Par exemple, une vidéo empaquetée à l'aide de Playready peut être lue dans un navigateur à l'aide d'un CDM Widevine obtenant une clé auprès d'un serveur de licences Widevine.

Cela diffère des anciennes solutions qui ne fonctionneraient qu'avec une pile verticale complète, y compris un client unique qui comprenait souvent également un environnement d'exécution d'application.

Le chiffrement commun (CENC) est une norme ISO définissant un schéma de protection pour le format ISO BMFF. Un concept similaire s'applique au WebM.

Effacer la clé

Bien qu'EME ne définisse pas de fonctionnalité DRM, les spécifications exigent actuellement que tous les navigateurs compatibles avec EME doivent mettre en œuvre Clear Key. Ce système permet de chiffrer un contenu multimédia à l'aide d'une clé, puis de le lire en fournissant simplement cette clé. La fonctionnalité Clear Key peut être intégrée au navigateur: elle ne nécessite pas l'utilisation d'un module de déchiffrement distinct.

Bien qu'elle ne soit pas susceptible d'être utilisée pour de nombreux types de contenus commerciaux, cette fonctionnalité est totalement interopérable avec tous les navigateurs compatibles avec EME. Il est également pratique pour tester les implémentations EME et les applications utilisant EME, sans avoir à demander une clé de contenu à un serveur de licences. Vous trouverez un exemple simple de clé de chiffrement à l'adresse simpl.info/ck. Vous trouverez ci-dessous une présentation du code, qui ressemble aux étapes décrites ci-dessus, sans interaction avec le serveur de licences.

// 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]
  }));
}

Pour tester ce code, vous avez besoin d'une vidéo chiffrée à lire. Vous pouvez chiffrer une vidéo à utiliser avec Clear Key pour WebM conformément aux instructions webm_crypt. Des services commerciaux sont également disponibles (au moins pour le format ISO BMFF/MP4), et d'autres solutions sont en cours de développement.

Media Source Extensions (MSE)

L'élément HTMLMediaElement est d'une beauté simple.

Il est possible de charger, de décoder et de lire des contenus multimédias en fournissant simplement une URL src:

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

L'API Media Source est une extension de HTMLMediaElement. Elle permet de contrôler plus précisément la source du contenu multimédia, en autorisant JavaScript à créer des flux pour la lecture à partir de "morceaux" de vidéo. Cela permet à des techniques telles que le streaming adaptatif et le décalage temporel.

Pourquoi la MSE est-elle importante pour les EM ? Parce qu'en plus de distribuer du contenu protégé, les fournisseurs de contenu commercial doivent être en mesure d'adapter la diffusion de contenu aux conditions du réseau et à d'autres exigences. Netflix, par exemple, modifie de façon dynamique le débit du flux en fonction de l'évolution des conditions du réseau. L'EME fonctionne avec la lecture des flux multimédias fournis par une implémentation MSE, tout comme il le ferait avec un contenu multimédia fourni via un attribut src.

Comment fragmenter et lire des contenus multimédias encodés à différents débits ? Consultez la section DASH ci-dessous.

Vous pouvez voir la MSE en action à l'adresse simpl.info/mse. Pour les besoins de cet exemple, une vidéo WebM est divisée en cinq parties à l'aide des API File. Dans une application de production, des fragments de vidéo sont récupérés via Ajax.

Un SourceBuffer est d'abord créé:

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

L'intégralité du film est ensuite "diffusée en streaming" vers un élément vidéo en ajoutant chaque bloc à l'aide de la méthode "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);
  }
};

Pour en savoir plus sur la MSE, consultez cet article sur HTML5 Rocks.

Streaming adaptatif dynamique sur HTTP (DASH)

Multi-appareil, multiplateforme, mobile : quel que soit le terme utilisé, le Web évolue souvent dans des conditions de connectivité évolutive. La diffusion dynamique et adaptative est essentielle pour faire face aux contraintes et à la variabilité de la bande passante dans un monde multi-appareil.

DASH (également appelé MPEG-DASH) est conçu pour assurer la meilleure diffusion multimédia possible dans un monde irrégulier, tant pour le streaming que pour le téléchargement. D'autres technologies offrent des fonctionnalités similaires, telles que le HTTP Live Streaming (HLS) d'Apple et le Smooth Streaming de Microsoft, mais DASH est la seule méthode de streaming à débit adaptatif via HTTP qui est basée sur une norme ouverte. DASH est déjà utilisé par des sites comme YouTube.

Quel est le rapport avec les EME et les MSE ? Les implémentations DASH basées sur MSE peuvent analyser un fichier manifeste, télécharger des segments de vidéo à un débit approprié et les transmettre à un élément vidéo lorsqu'il en a besoin, à l'aide de l'infrastructure HTTP existante.

En d'autres termes, DASH permet aux fournisseurs de contenu commercial de diffuser de manière adaptative le contenu protégé.

DASH fait ce qu'il dit sur l'étain:

  • Dynamique:réagit à l'évolution des conditions.
  • Adaptative:s'adapte pour fournir un débit audio ou vidéo approprié.
  • Streaming:permet le streaming et le téléchargement.
  • HTTP:permet de diffuser du contenu en profitant du protocole HTTP, sans les inconvénients d'un serveur de streaming traditionnel.

La BBC a commencé à fournir des flux de test à l'aide de DASH:

En résumé :

  1. Le contenu multimédia est encodé à différents débits.
  2. Les différents fichiers de débit sont mis à disposition à partir d'un serveur HTTP.
  3. Une application Web cliente choisit le débit à récupérer et à lire avec DASH.

Dans le cadre du processus de segmentation vidéo, un fichier manifeste XML appelé Media Presentation Description (MPD) est créé de manière programmatique. Cette section décrit les ensembles et les représentations d'adaptation, avec des durées et des URL. Une description de la présentation du média se présente comme suit:

<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>

(Ce fichier XML est tiré du fichier .mpd utilisé pour le lecteur de démonstration YouTube DASH.)

Conformément à la spécification DASH, un fichier MPD peut en théorie être utilisé comme src pour une vidéo. Toutefois, pour offrir plus de flexibilité aux développeurs Web, les fournisseurs de navigateurs ont choisi de laisser la prise en charge de DASH aux bibliothèques JavaScript utilisant MSE comme dash.js. L'implémentation de DASH en JavaScript permet à l'algorithme d'adaptation d'évoluer sans nécessiter de mises à jour du navigateur. L'utilisation de MSE permet également de tester d'autres formats de fichiers manifestes et mécanismes de diffusion sans avoir à modifier le navigateur. Le Shaka Player de Google met en œuvre un client DASH compatible avec EME.

Mozilla Developer Network contient des instructions sur l'utilisation des outils WebM et de FFmpeg pour segmenter des vidéos et créer une description de la présentation du média.

Conclusion

L'utilisation du Web pour la diffusion d'annonces audio et vidéo payantes se développe à un rythme élevé. Il semble que chaque nouvel appareil, qu'il s'agisse d'une tablette, d'une console de jeu, d'une télévision connectée ou d'un boîtier décodeur, est capable de diffuser en streaming les contenus multimédias des principaux fournisseurs de contenu via HTTP. Plus de 85 % des navigateurs mobiles et pour ordinateur sont désormais compatibles avec <video> et <audio>. Selon Cisco, le trafic vidéo représentera 80 à 90 % du trafic Internet mondial des consommateurs d'ici 2017. Dans ce contexte, la compatibilité des navigateurs pour la distribution de contenu protégé devrait devenir de plus en plus importante, car les fournisseurs de navigateurs réduisent la prise en charge des API utilisées par la plupart des plug-ins multimédias.

Documentation complémentaire

Spécifications et normes

Articles