¿EME, qué imperdible?

Introducción a las extensiones de medios encriptados

Las extensiones de medios encriptados proporcionan una API que permite que las aplicaciones web interactúen con los sistemas de protección de contenido para permitir la reproducción de audio y video encriptados.

El EME está diseñado para permitir que se usen la misma app y los mismos archivos encriptados en cualquier navegador, independientemente del sistema de protección subyacente. La primera es posible gracias al flujo y las APIs estandarizadas, mientras que la segunda es posible gracias al concepto de la encriptación común.

EME es una extensión de la especificación HTMLMediaElement, de ahí su nombre. Si se trata de una "extensión", significa que la compatibilidad del navegador con EME es opcional. Si un navegador no admite contenido multimedia encriptado, no podrá reproducir ese tipo de contenido, pero EME no es necesario para cumplir con las especificaciones de HTML. A partir de las especificaciones de EME:

Las implementaciones de EME usan los siguientes componentes externos:

  • Sistema de claves: Es un mecanismo de protección de contenido (DRM). EME no define Key Systems en sí, a excepción de Clear Key (obtén más información al respecto a continuación).
  • Módulo de desencriptación de contenido (CDM): Es un mecanismo de software o hardware del cliente que permite la reproducción de contenido multimedia encriptado. Al igual que con los sistemas de claves, EME no define ningún CDM, sino que proporciona una interfaz para que las aplicaciones interactúen con los CDM que están disponibles.
  • Servidor de licencias (clave): Interactúa con un CDM para proporcionar claves para desencriptar el contenido multimedia. La negociación con el servidor de licencias es responsabilidad de la aplicación.
  • Servicio de empaquetado: Codifica y encripta contenido multimedia para su distribución o consumo.

Ten en cuenta que una aplicación que usa EME interactúa con un servidor de licencias para obtener claves para habilitar la desencriptación, pero la identidad del usuario y la autenticación no son parte de EME. La recuperación de claves para habilitar la reproducción de contenido multimedia ocurre después de que se autentica a un usuario (opcionalmente). Los servicios como Netflix deben autenticar a los usuarios dentro de su aplicación web: cuando un usuario accede a la aplicación, esta determina la identidad y los privilegios del usuario.

¿Cómo funciona EME?

A continuación, se muestra cómo interactúan los componentes de EME, que corresponde al siguiente ejemplo de código:

  1. Una aplicación web intenta reproducir audio o video que tiene una o más transmisiones encriptadas.
  2. El navegador reconoce que el contenido multimedia está encriptado (consulta el cuadro que aparece a continuación para ver cómo sucede) y activa un evento encrypted con metadatos (initData) obtenidos de los medios sobre la encriptación.
  3. La aplicación controla el evento encrypted:
    1. Si no se asoció ningún objeto MediaKeys con el elemento multimedia, primero selecciona un sistema de claves disponible con navigator.requestMediaKeySystemAccess() para verificar qué sistemas de claves están disponibles y, luego, crea un objeto MediaKeys para un sistema de claves disponible a través de un objeto MediaKeySystemAccess. Ten en cuenta que la inicialización del objeto MediaKeys debe ocurrir antes del primer evento encrypted. La app realiza la obtención de una URL del servidor de licencias independientemente de seleccionar un sistema de claves disponible. Un objeto MediaKeys representa todas las claves disponibles para desencriptar el contenido multimedia de un elemento de audio o video. Representa una instancia de CDM y proporciona acceso a este, específicamente para crear sesiones de claves que se usan para obtener claves de un servidor de licencias.
    2. Una vez que se creó el objeto MediaKeys, asígnalo al elemento multimedia: setMediaKeys() asocia el objeto MediaKeys con un HTMLMediaElement, de modo que sus claves se puedan usar durante la reproducción, es decir, durante la decodificación.
  4. La app crea un MediaKeySession llamando a createSession() en el MediaKeys. Esto crea un MediaKeySession, que representa la vida útil de una licencia y sus claves.
  5. Para generar una solicitud de licencia, la app pasa los datos multimedia obtenidos en el controlador encrypted al CDM. Para ello, llama a generateRequest() en MediaKeySession.
  6. El CDM activa un evento message: una solicitud para adquirir una clave de un servidor de licencias.
  7. El objeto MediaKeySession recibe el evento message y la aplicación envía un mensaje al servidor de licencias (por ejemplo, a través de XHR).
  8. La aplicación recibe una respuesta del servidor de licencias y pasa los datos al CDM con el método update() de MediaKeySession.
  9. El CDM desencripta el contenido multimedia usando las claves de la licencia. Se puede usar una clave válida de cualquier sesión dentro de los MediaKey asociados con el elemento multimedia. El CDM accederá a la clave y la política, indexadas por ID de clave.
  10. Se reanudará la reproducción de contenido multimedia.

¡Uf!

Ten en cuenta que puede haber varios mensajes entre el CDM y el servidor de licencias, y que todas las comunicaciones de este proceso son opacas para el navegador y la aplicación: los mensajes solo son comprensibles para el CDM y el servidor de licencias, aunque la capa de la app puede ver qué tipo de mensaje envía el CDM. La solicitud de licencia contiene pruebas de la validez del CDM (y de la relación de confianza), así como una clave para usar al encriptar las claves de contenido de la licencia resultante.

... pero, ¿qué hacen realmente los CDM?

Una implementación de EME no proporciona por sí misma una forma de desencriptar el contenido multimedia, sino que simplemente proporciona una API para que una aplicación web interactúe con los módulos de desencriptación de contenido.

Lo que los CDM en realidad no hacen está definido por la especificación de EME, y un CDM puede manejar la decodificación (descompresión) de medios y la desencriptación. Existen varias opciones potenciales para la funcionalidad de CDM, desde la menos hasta la más sólida:

  • Solo desencriptación, habilita la reproducción con la canalización de contenido multimedia normal, por ejemplo, a través de un elemento <video>.
  • Desencriptación y decodificación, que pasa fotogramas del video al navegador para su renderización.
  • Desencriptación y decodificación, que se renderizan directamente en el hardware (por ejemplo, la GPU)

Existen varias formas de hacer que un CDM esté disponible para una app web:

  • Empaqueta un CDM con el navegador.
  • Distribuye un CDM por separado.
  • Compilar un CDM en el sistema operativo
  • Incluye un CDM en el firmware.
  • Incorporar un CDM en el hardware

La especificación de EME no define la forma en que un CDM se pone a disposición, pero en todos los casos el navegador es responsable de examinar y exponer al CDM.

EME no exige un sistema de claves específico. Entre los navegadores actuales para computadoras de escritorio y dispositivos móviles, Chrome es compatible con Widevine y, además, IE11 es compatible con PlayReady.

Obtén una clave de un servidor de licencias

En el uso comercial típico, el contenido se encriptará y se codificará con un servicio o una herramienta de empaquetado. Una vez que el medio encriptado está disponible en línea, un cliente web puede obtener una clave (contenida en una licencia) de un servidor de licencias y usar la clave para habilitar la desencriptación y reproducción del contenido.

El siguiente código (adaptado de los ejemplos de especificaciones) muestra cómo una aplicación puede seleccionar un sistema de claves apropiado y obtener una clave de un servidor de licencias.

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

Encriptación común

Las soluciones de cifrado comunes permiten a los proveedores de contenido encriptar y empaquetar su contenido una vez por contenedor/códec y usarlo con una variedad de sistemas clave, CDM y clientes: es decir, cualquier CDM que admita la encriptación común. Por ejemplo, un video empaquetado con Playready podría reproducirse en un navegador que utilice un CDM de Widevine y obtener una clave de un servidor de licencias de Widevine.

Esto contrasta con las soluciones heredadas que solo funcionarían con una pila vertical completa, incluido un único cliente que a menudo también incluía un entorno de ejecución de aplicaciones.

La encriptación común (CENC) es un estándar ISO que define un esquema de protección para ISO BMFF; un concepto similar se aplica a WebM.

Borrar clave

Aunque EME no define la funcionalidad de DRM, actualmente, la especificación exige que todos los navegadores compatibles con EME implementen la función Borrar clave. Con este sistema, el contenido multimedia se puede encriptar con una clave y, luego, reproducir el contenido con solo proporcionar esa clave. La clave Clear Key puede integrarse en el navegador: no requiere el uso de otro módulo de desencriptación.

Si bien es poco probable que se use para muchos tipos de contenido comercial, Clear Key es completamente interoperable en todos los navegadores compatibles con EME. También es útil para probar implementaciones de EME y aplicaciones que usan EME, sin la necesidad de solicitar una clave de contenido a un servidor de licencias. Hay un ejemplo simple de Clear Key en simpl.info/ck. A continuación, se muestra una explicación del código, que es paralela a los pasos descritos anteriormente, aunque sin interacción con el servidor de licencias.

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

Si quieres probar este código, necesitas un video encriptado para reproducirlo. Para WebM, se puede encriptar un video para usarlo con la clave simple de acuerdo con las instrucciones de webm_crypt. También hay disponibles servicios comerciales (al menos para ISO BMFF/MP4) y se están desarrollando otras soluciones.

Extensiones de fuente de medios (MSE)

El HTMLMediaElement es un elemento de belleza simple.

Podemos cargar, decodificar y reproducir contenido multimedia con solo proporcionar una URL src:

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

La API de fuente de medios es una extensión de HTMLMediaElement que permite un control más detallado sobre la fuente de contenido multimedia, ya que permite que JavaScript cree transmisiones para reproducir a partir de "fragmentos" de video. Esto, a su vez, permite técnicas como la transmisión adaptable y el cambio de tiempo.

¿Por qué el EME es importante para EME? Porque, además de distribuir contenido protegido, los proveedores de contenido comercial deben poder adaptar la publicación de contenido a las condiciones de la red y otros requisitos. Por ejemplo, Netflix cambia dinámicamente la tasa de bits de la transmisión a medida que cambian las condiciones de la red. El EME funciona con la reproducción de transmisiones de contenido multimedia proporcionadas por una implementación de EME, al igual que con contenido multimedia proporcionado mediante un atributo src.

¿Cómo fragmentar y reproducir contenido multimedia codificado a distintas tasas de bits? Consulte la sección de la forma de comer DASH a continuación.

Puedes ver el ECM en acción en simpl.info/mse. A los efectos de este ejemplo, un video de WebM se divide en cinco partes con las APIs de File. En una aplicación de producción, los fragmentos de video se recuperaban a través de Ajax.

Primero, se crea un SourceBuffer:

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

Luego, la película completa se "transmite" a un elemento de video agregando cada fragmento con el método 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);
  }
};

Obtenga más información sobre ECM en el artículo HTML5 Rocks.

Transmisión adaptable y dinámica a través de HTTP (DASH)

Multidispositivo, multiplataforma, móvil: como lo llames, la web a menudo se experimenta en condiciones de conectividad cambiante. La entrega dinámica y adaptable es crucial para hacer frente a las restricciones y la variabilidad del ancho de banda en un mundo de múltiples dispositivos.

DASH (también conocido como MPEG-DASH) está diseñado para permitir la mejor publicación de contenido multimedia posible en un mundo inestable, tanto para la transmisión como para las descargas. Varias otras tecnologías hacen algo similar, como HTTP Live Streaming (HLS) de Apple y Smooth Streaming de Microsoft, pero DASH es el único método de transmisión de tasa de bits adaptable a través de HTTP que se basa en un estándar abierto. Algunos sitios como YouTube ya utilizan la forma de comer DASH.

¿Qué tiene que ver esto con EME y EME? Las implementaciones de DASH basadas en MSE pueden analizar un manifiesto, descargar segmentos de video a una tasa de bits adecuada y enviarlos a un elemento de video cuando se le antoja, a través de la infraestructura HTTP existente.

En otras palabras, DASH permite a los proveedores de contenido comercial realizar transmisiones adaptables de contenido protegido.

La forma de comer DASH hace lo que dice en la lata:

  • Dinámico: responde a las condiciones cambiantes.
  • Adaptable: Se adapta para proporcionar una tasa de bits de audio o video adecuada.
  • Transmisión: Permite transmitir y descargar.
  • HTTP: Habilita la entrega de contenido con la ventaja de HTTP, sin las desventajas de un servidor de transmisión tradicional.

La BBC comenzó a proporcionar transmisiones de prueba mediante DASH:

En síntesis:

  1. El contenido multimedia está codificado con distintas tasas de bits.
  2. Los diferentes archivos de tasa de bits están disponibles desde un servidor HTTP.
  3. Una app web cliente elige qué tasa de bits recuperar y reproducir con DASH.

Como parte del proceso de segmentación de videos, se compila mediante programación un manifiesto XML conocido como descripción de presentación multimedia (MPD). Esto describe los conjuntos de adaptación y las representaciones, con duraciones y URLs. Una MPD se ve de la siguiente manera:

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

(Este XML se tomó del archivo .mpd que se utiliza para el reproductor de demostración de YouTube DASH).

Según la especificación de DASH, en teoría se podría usar un archivo MPD como src para un video. Sin embargo, para brindar más flexibilidad a los desarrolladores web, los proveedores de navegadores decidieron dejar la compatibilidad de DASH con las bibliotecas de JavaScript mediante ECM, como dash.js. La implementación de DASH en JavaScript permite que el algoritmo de adaptación evolucione sin requerir actualizaciones del navegador. El uso de ECM también permite experimentar con formatos de manifiesto alternativos y mecanismos de entrega sin necesidad de realizar cambios en el navegador. El Shaka Player de Google implementa un cliente de DASH compatible con EME.

Mozilla Developer Network tiene instrucciones sobre cómo usar las herramientas de WebM y FFmpeg para segmentar videos y crear una MPD.

Conclusión

El uso de la Web para reproducir audio y video de pago está creciendo a un gran ritmo. Parece que todos los dispositivos nuevos, ya sean tablets, consolas de juegos, TV conectadas o decodificadores, pueden transmitir medios de los principales proveedores de contenido a través de HTTP. Más del 85% de los navegadores para dispositivos móviles y computadoras ahora admiten <video> y <audio>, y Cisco estima que los videos representarán entre el 80% y el 90% del tráfico mundial de Internet de los consumidores para el 2017. En este contexto, es probable que la compatibilidad de los navegadores con la distribución de contenido protegido sea cada vez más significativa, ya que los proveedores de navegadores restringen la compatibilidad con las APIs de las que dependen la mayoría de los complementos multimedia.

Lecturas adicionales

Especificaciones y estándares

Artículos