Qu'est-ce que l'EME ?

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

EME est conçu pour permettre l'utilisation de la même application et des 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 flux standardisés, 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 de la spécification EME:

Cette proposition étend les API HTMLMediaElement permettant de contrôler la lecture du contenu protégé.

L'API est compatible avec des cas d'utilisation allant du simple déchiffrement de clé clair aux vidéos de grande valeur (sous réserve d'une implémentation appropriée du user-agent). L'échange de licences/clés est contrôlé par l'application, ce qui facilite le développement d'applications de lecture robustes prenant en charge diverses technologies de protection et de déchiffrement de contenu.

Cette spécification ne définit pas de système de protection des contenus ni de gestion des droits numériques. Il définit plutôt une API commune qui peut être utilisée pour découvrir, sélectionner et interagir avec ces systèmes, ainsi qu'avec des systèmes de chiffrement de contenu plus simples. L'implémentation de la gestion des droits numériques n'est pas nécessaire pour respecter cette spécification: seul le système de suppression de clé doit être implémenté comme référence commune.

L'API commune prend en charge un ensemble simple de fonctionnalités de chiffrement de contenu, laissant aux auteurs de pages des fonctions d'application telles que l'authentification et l'autorisation. Pour ce faire, la page doit assurer la médiation des messages spécifiques au système de protection du contenu, plutôt que de prévoir une communication hors bande entre le système de chiffrement et une licence ou un autre serveur.

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 les systèmes de clés eux-mêmes, à l'exception de Clear Key (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, 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 les contenus multimédias. 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 afin d'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 permettant d'activer la lecture de contenus multimédias a lieu après l'authentification d'un utilisateur (éventuellement). 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:

Si plusieurs formats ou codecs sont disponibles, vous pouvez utiliser MediaSource.isTypeSupported() ou HTMLMediaElement.canPlayType() pour sélectionner le bon. Toutefois, il est possible que le CDM ne prenne en charge qu'un sous-ensemble de ceux compatibles avec le navigateur pour le contenu non chiffré. Il est préférable de négocier une configuration MediaKeys avant de sélectionner un format et un codec. Si l'application attend l'événement chiffré, mais que MediaKeys indique qu'elle ne peut pas gérer le format/codec choisi, il est peut-être trop tard pour changer sans interrompre la lecture.

La procédure recommandée consiste à négocier d'abord des MediaKeys, à l'aide de MediaKeysSystemAccess.getConfiguration() pour identifier la configuration négociée.

Si vous n'avez qu'un seul format/codec à choisir, vous n'avez pas besoin de getConfiguration(). Toutefois, il est toujours préférable de configurer d'abord MediaKeys. La seule raison d'attendre l'événement chiffré est s'il n'y a aucun moyen de savoir si le contenu est chiffré ou non, mais dans la pratique, c'est peu probable.

  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 chiffré avec des métadonnées (initData) obtenues à partir du contenu multimédia à propos du chiffrement.
  3. L'application gère l'événement chiffré:

    1. Si aucun objet MediaKeys n'a été associé à l'élément multimédia, commencez par sélectionner 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 chiffré. 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 CDN, en particulier pour créer des sessions de clés permettant d'obtenir des clés auprès d'un serveur de licences.

    2. Une fois l'objet MediaKeys créé, attribuez-le à l'élément multimédia: setMediaKeys() associe cet objet à un élément HTMLMediaElement, afin que ses clés puissent être utilisées lors de la lecture, c'est-à-dire lors du décodage.

  4. L'application crée une MediaKeySession en appelant createSession() sur les MediaKeys. Cette opération crée une "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 chiffré au CDM, en appelant generateRequest() sur MediaKeySession.

  6. Le CDM déclenche un événement de message: une demande d'acquisition d'une clé auprès d'un serveur de licences.

  7. L'objet MediaKeySession reçoit l'événement de 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é.

La lecture des contenus multimédias reprend.

Comment le navigateur peut-il savoir que le contenu multimédia est chiffré ?

Ces informations se trouvent dans les métadonnées du fichier de conteneur multimédia, au format ISO BMFF ou WebM. Pour le format de fichier ISO BMFF, il s'agit des métadonnées d'en-tête, appelées zone d'informations du schéma de protection. WebM utilise l'élément Matroska ContentEncryption, avec quelques ajouts spécifiques à WebM. Des instructions sont fournies pour chaque conteneur dans un registre spécifique à l'EME.

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 ne sont compris que par le CDM et le serveur de licences, bien que la couche d'application puisse voir le type de message envoyé par le CDM. La demande de licence contient la preuve de la validité du CDM (et de la relation de confiance), ainsi qu'une clé à utiliser lors du chiffrement des clés de contenu dans la licence obtenue.

Mais que font réellement les CDM ?

Une implémentation EME ne fournit pas en elle-même un moyen 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 rôle 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 les fonctionnalités 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.

La spécification EME ne définit 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="vp09.00.10.08"'}]}];

    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 d'empaqueter leur contenu une 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 incluant souvent un environnement d'exécution d'application.

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

Effacer la clé

Bien que l'EME ne définisse pas de fonctionnalité DRM, la spécification exige actuellement que tous les navigateurs compatibles avec EME doivent mettre en œuvre Clear Key. À l'aide de ce système, les contenus multimédias peuvent être chiffrés à l'aide d'une clé, puis lus simplement en fournissant 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 entièrement interopérable avec tous les navigateurs compatibles avec EME. Il est également pratique pour tester les implémentations EME et les applications qui utilisent EME, sans avoir à demander une clé de contenu à un serveur de licences. Vous trouverez un exemple simple de clé claire à l'adresse simpl.info/ck. Vous trouverez ci-dessous un tutoriel du code, qui compare les étapes décrites ci-dessus, mais 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.

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, qui permet de contrôler plus précisément la source du contenu multimédia en permettant à JavaScript de 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 pouvoir adapter la diffusion de contenu aux conditions du réseau et à d'autres exigences. Netflix, par exemple, change de manière dynamique le débit du flux lorsque les conditions du réseau changent. L'EME fonctionne avec la lecture des flux multimédias fournis par une implémentation MSE, 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 fragments à 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"',
);

Le film entier est ensuite "diffusé en streaming" vers un élément vidéo en ajoutant chaque fragment à l'aide de la méthode addBuffer() :

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 MSE, consultez le guide de présentation de MSE.

Solution multi-appareil, multiplate-forme, mobile : quel que soit le nom utilisé, le Web se pratique souvent dans des conditions de connectivité variable. La diffusion dynamique et adaptative est essentielle pour faire face aux contraintes de bande passante et à la variabilité dans le monde multi-appareil.

DASH (aussi appelé MPEG-DASH) est conçu pour assurer la meilleure diffusion de médias possible dans un monde irrégulier, à la fois pour le streaming et le téléchargement. Plusieurs autres technologies présentent une approche similaire, comme 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 y en a trop, à l'aide de l'infrastructure HTTP existante.

En d'autres termes, DASH permet aux fournisseurs de contenu commercial d'effectuer un streaming adaptatif du 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 avec l'avantage 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:

Le contenu multimédia est encodé un certain nombre de fois avec des débits différents. Chaque encodage est appelé représentation. Ils sont divisés en plusieurs segments multimédias. Le client lit un programme en demandant des segments, dans l'ordre, à partir d'une représentation via HTTP. Les représentations peuvent être regroupées dans des ensembles d'adaptation de représentations comportant du contenu équivalent. Si le client souhaite modifier le débit, il peut choisir une autre solution dans l'ensemble d'adaptations actuel et commencer à demander des segments à partir de cette représentation. Le contenu est encodé de manière à faciliter cette transition pour le client. Outre le certain nombre de segments multimédias, une représentation comporte généralement un segment d'initialisation. Cela peut être considéré comme un en-tête contenant des informations sur l'encodage, la taille des images, etc. Un client doit l'obtenir pour une représentation donnée avant de consommer des segments multimédias de cette représentation.

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 d'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 telles que dash.js. L'implémentation de DASH dans 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 implémente 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 vidéo et audio payantes se développe à un taux important. 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 pour mobile et ordinateur prennent désormais en charge <video> et <audio>, et Cisco estime que la 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

Spécification EME: dernière version préliminaire de l'éditeur Common Encryption (CENC) Extensions de source média: dernière version du brouillon norme DASH (oui, c'est un PDF) Présentation de la norme DASH

Articles

Webinaire DTG (partiellement obsolète) Qu'est-ce qu'EME ?, par Henri Sivonen Introduction aux extensions Media Source Introduction aux flux de test MPEG-DASH: article de blog BBC R&D

Démonstrations

Démonstration Clear Key: simpl.info/ck Démo Media Source Extensions (MSE) Shaka Player de Google implémente un client DASH compatible avec EME

Commentaires