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.
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. El primero es posible gracias a las APIs y el flujo estandarizados, mientras que el segundo es posible gracias al concepto de Criptografía común.
EME es una extensión de la especificación HTMLMediaElement, de ahí el nombre. Ser una "extensión" significa que la compatibilidad del navegador con EME es opcional: si un navegador no admite contenido multimedia encriptado, no podrá reproducirlo, pero EME no es obligatorio para el cumplimiento de las especificaciones de HTML. De la especificación de EME:
Esta propuesta extiende HTMLMediaElement y proporciona APIs para controlar la reproducción de contenido protegido.
La API admite casos de uso que van desde la desencriptación de claves claras simples hasta videos de alto valor (siempre que se implemente un usuario-agente adecuado). La aplicación controla el intercambio de licencias o claves, lo que facilita el desarrollo de aplicaciones de reproducción sólidas que admiten una variedad de tecnologías de protección y desencriptación de contenido.
Esta especificación no define un sistema de protección de contenido ni de administración de derechos digitales. En cambio, define una API común que se puede usar para descubrir, seleccionar e interactuar con esos sistemas, así como con sistemas de encriptación de contenido más simples. No se requiere la implementación de la administración de derechos digitales para cumplir con esta especificación: solo se debe implementar el sistema Clear Key como un modelo de referencia común.
La API común admite un conjunto simple de capacidades de encriptación de contenido, lo que deja las funciones de la aplicación, como la autenticación y la autorización, a los autores de la página. Esto se logra mediante la exigencia de que la página medie los mensajes específicos del sistema de protección de contenido en lugar de suponer una comunicación fuera de banda entre el sistema de encriptación y una licencia o algún otro servidor.
Las implementaciones de EME usan los siguientes componentes externos:
- Sistema de claves: Es un mecanismo de protección de contenido (DRM). EME no define los sistemas de claves, excepto Clear Key (obtén más información más abajo).
- Módulo de desencriptación de contenido (CDM): Es un mecanismo de software o hardware del cliente que habilita la reproducción de contenido multimedia encriptado. Al igual que con los sistemas de claves, la EME no define ningún CDM, pero proporciona una interfaz para que las aplicaciones interactúen con los CDM disponibles.
- Servidor de licencias (claves): Interactúa con un CDM para proporcionar claves que desencripten el contenido multimedia. La negociación con el servidor de licencias es responsabilidad de la aplicación.
- Servicio de empaquetado: Codifica y encripta el 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 que permitan la desencriptación, pero la identidad y la autenticación del usuario no forman parte de EME. La recuperación de claves para habilitar la reproducción de contenido multimedia se produce después de autenticar a un usuario (de manera opcional). 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 su identidad y privilegios.
¿Cómo funciona la EME?
A continuación, se muestra cómo interactúan los componentes de EME, que corresponden al ejemplo de código que aparece a continuación:
Si hay varios formatos o códecs disponibles, se pueden usar MediaSource.isTypeSupported() o HTMLMediaElement.canPlayType() para seleccionar el correcto. Sin embargo, es posible que el CDM solo admita un subconjunto de lo que admite el navegador para el contenido no encriptado. Es mejor negociar una configuración de MediaKeys antes de seleccionar un formato y un códec. Si la aplicación espera el evento encriptado, pero MediaKeys muestra que no puede controlar el formato o el códec elegido, es posible que sea demasiado tarde para cambiar sin interrumpir la reproducción.
El flujo recomendado es negociar MediaKeys primero, con MediaKeysSystemAccess.getConfiguration() para conocer la configuración negociada.
Si solo hay un formato o códec para elegir, no es necesario llamar a getConfiguration(). Sin embargo, es preferible configurar MediaKeys primero. El único motivo para esperar el evento encriptado es si no hay forma de saber si el contenido está encriptado o no, pero en la práctica es poco probable.
- Una aplicación web intenta reproducir audio o video que tiene una o más transmisiones encriptadas.
- El navegador reconoce que el contenido multimedia está encriptado (consulta el cuadro a continuación para ver cómo sucede esto) y activa un evento encriptado con metadatos (initData) obtenidos del contenido multimedia sobre la encriptación.
La aplicación controla el evento encriptado:
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 encriptado. La app obtiene una URL de servidor de licencias independientemente de la selección de 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 la CDM, específicamente para crear sesiones de claves, que se usan para obtener claves de un servidor de licencias.
Una vez creado el objeto MediaKeys, asígnale el 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.
La app crea una MediaKeySession llamando a createSession() en MediaKeys. Esto crea un MediaKeySession, que representa la vida útil de una licencia y sus claves.
La app genera una solicitud de licencia pasando los datos multimedia obtenidos en el controlador encriptado al CDM llamando a generateRequest() en MediaKeySession.
El CDM activa un evento de mensaje: una solicitud para adquirir una clave de un servidor de licencias.
El objeto MediaKeySession recibe el evento de mensaje y la aplicación envía un mensaje al servidor de licencias (a través de XHR, por ejemplo).
La aplicación recibe una respuesta del servidor de licencias y pasa los datos al CDM con el método update() de MediaKeySession.
El CDM desencripta el contenido multimedia con las claves de la licencia. Se puede usar una clave válida desde cualquier sesión dentro de MediaKeys asociada con el elemento multimedia. El CDM accederá a la clave y la política, indexadas por el ID de clave.
Se reanuda la reproducción de contenido multimedia.
¿Cómo sabe el navegador que el contenido multimedia está encriptado?
Esta información se encuentra en los metadatos del archivo del contenedor multimedia, que estará en un formato como ISO BMFF o WebM. Para ISO BMFF, esto significa metadatos de encabezado, que se denominan cuadro de información del esquema de protección. WebM usa el elemento Matroska ContentEncryption, con algunas incorporaciones específicas de WebM. Se proporcionan lineamientos para cada contenedor en un registro específico de EME.
Ten en cuenta que puede haber varios mensajes entre el CDM y el servidor de licencias, y que toda la comunicación en este proceso es opaca para el navegador y la aplicación: solo el CDM y el servidor de licencias entienden los mensajes, aunque la capa de la app puede ver qué tipo de mensaje envía el CDM. La solicitud de licencia contiene una prueba de la validez de la CDM (y la relación de confianza), así como una clave para usar cuando se encriptan las claves de contenido en la licencia resultante.
Pero, ¿qué hacen exactamente los CDM?
Una implementación de EME no proporciona, en sí, una forma de desencriptar contenido: solo proporciona una API para que una aplicación web interactúe con los módulos de desencriptación de contenido.
La especificación de EME no define lo que realmente hacen los CDM, y un CDM puede controlar la decodificación (descompresión) del contenido multimedia, así como la desencriptación. De la menos a la más sólida, existen varias opciones posibles para la funcionalidad de la CDM:
- Solo desencriptación, lo que 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, y pasar fotogramas de video al navegador para la renderización
- Desencriptación y decodificación, renderización directamente en el hardware (por ejemplo, la GPU)
Existen varias formas de hacer que un CDM esté disponible para una app web:
- Combina un CDM con el navegador.
- Distribuye un CDM por separado.
- Compila 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 cómo se pone a disposición un CDM, pero, en todos los casos, el navegador es responsable de verificar y exponer el CDM.
EME no exige un sistema de claves en particular. Entre los navegadores para computadoras de escritorio y dispositivos móviles actuales, Chrome admite Widevine y IE11 admite PlayReady.
Cómo obtener una clave de un servidor de licencias
En el uso comercial típico, el contenido se encripta y codifica con una herramienta o un servicio de empaquetado. Una vez que el contenido multimedia encriptado está disponible en línea, un cliente web puede obtener una clave (contenida en una licencia) de un servidor de licencias y usarla para habilitar la desencriptación y la reproducción del contenido.
En el siguiente código (adaptado de los ejemplos de especificaciones), se muestra cómo una aplicación puede seleccionar un sistema de claves adecuado y obtener una clave de un servidor de licencias.
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')
);
}
Encriptación común
Las soluciones de encriptación común permiten a los proveedores de contenido encriptar y empaquetar su contenido una vez por contenedor o códec y usarlo con una variedad de sistemas de claves, CDM y clientes, es decir, cualquier CDM que admita la encriptación común. Por ejemplo, un video empaquetado con PlayReady se puede reproducir en un navegador con un CDM de Widevine que obtiene 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 solo cliente que, a menudo, también incluía un entorno de ejecución de la aplicación.
La encriptación común (CENC) es un estándar ISO que define un esquema de protección para ISO BMFF. Se aplica un concepto similar a WebM.
Borrar clave
Si bien EME no define la funcionalidad de DRM, la especificación actualmente exige que todos los navegadores compatibles con EME implementen Clear Key. Con este sistema, el contenido multimedia se puede encriptar con una clave y, luego, reproducir simplemente proporcionando esa clave. Clear Key se puede incorporar en el navegador: no requiere el uso de un módulo de desencriptación independiente.
Si bien es probable que no se use para muchos tipos de contenido comercial, Clear Key es totalmente interoperable en todos los navegadores que admiten EME. También es útil para probar implementaciones de EME y aplicaciones que usan EME sin 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 similar 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],
}),
);
}
Para probar este código, necesitas un video encriptado para reproducir. La encriptación de un video para su uso con Clear Key se puede realizar en WebM según las instrucciones de webm_crypt. También hay servicios comerciales disponibles (al menos para ISO BMFF/MP4) y se están desarrollando otras soluciones.
Tecnología relacionada 1: Extensiones de origen de medios (MSE)
HTMLMediaElement es una criatura de belleza simple.
Podemos cargar, decodificar y reproducir contenido multimedia simplemente proporcionando una URL de src:
<video src="foo.webm"></video>
La API de Media Source 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 la reproducción a partir de "fragmentos" de video. Esto, a su vez, permite técnicas como la transmisión adaptativa y el cambio de hora.
¿Por qué la MSE es importante para la EME? Esto se debe a que, además de distribuir contenido protegido, los proveedores de contenido comercial deben poder adaptar la entrega de contenido a las condiciones de la red y a otros requisitos. Netflix, por ejemplo, cambia de forma dinámica la tasa de bits de transmisión a medida que cambian las condiciones de la red. EME funciona con la reproducción de transmisiones de contenido multimedia que proporciona una implementación de MSE, al igual que lo haría con el contenido multimedia proporcionado a través de un atributo src.
¿Cómo se fragmenta y reproduce contenido multimedia codificado con diferentes tasas de bits? Consulta la sección de DASH a continuación.
Puedes ver MSE en acción en simpl.info/mse. Para los fines de este ejemplo, un video WebM se divide en cinco segmentos con las APIs de File. En una aplicación de producción, los fragmentos de video se recuperarían a través de AJAX.
Primero, se crea un SourceBuffer:
var sourceBuffer = mediaSource.addSourceBuffer(
'video/webm; codecs="vorbis,vp8"',
);
Luego, se “transmite” toda la película a un elemento de video agregando cada fragmento con el método 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);
}
};
Obtén más información sobre MSE en el instructivo de MSE.
Tecnología relacionada 2: Transmisión adaptable y dinámica a través de HTTP (DASH)
Ya sea multidispositivo, multiplataforma o para dispositivos móviles, la Web a menudo se experimenta en condiciones de conectividad cambiante. La publicación dinámica y adaptativa es fundamental para hacer frente a las limitaciones de ancho de banda y la variabilidad en el mundo multidispositivo.
DASH (también conocido como MPEG-DASH) está diseñado para permitir la mejor entrega de contenido multimedia posible en un mundo inestable, tanto para la transmisión como para la descarga. 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. Sitios como YouTube ya usan DASH.
¿Qué tiene que ver esto con EME y MSE? Las implementaciones de DASH basadas en MSE pueden analizar un manifiesto, descargar segmentos de video con una tasa de bits adecuada y enviarlos a un elemento de video cuando lo necesite, con la infraestructura HTTP existente.
En otras palabras, DASH permite que los proveedores de contenido comercial realicen transmisiones adaptativas de contenido protegido.
La dieta DASH hace lo que dice en la lata:
- Dinámico: Responde a las condiciones cambiantes.
- Adaptativa: Se adapta para proporcionar una tasa de bits de audio o video adecuada.
- Transmisión: Permite la transmisión y la descarga.
- HTTP: Permite 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 con DASH:
El contenido multimedia se codifica varias veces con diferentes tasas de bits. Cada codificación se llama representación. Estos se dividen en varios segmentos de contenido multimedia. El cliente reproduce un programa solicitando segmentos, en orden, desde una representación a través de HTTP. Las representaciones se pueden agrupar en conjuntos de adaptaciones de representaciones que contienen contenido equivalente. Si el cliente desea cambiar la tasa de bits, puede elegir una alternativa del conjunto de adaptación actual y comenzar a solicitar segmentos de esa representación. El contenido se codifica de manera tal que el cliente pueda realizar este cambio con facilidad. Además de una cantidad de segmentos multimedia, una representación también suele tener un segmento de inicialización. Se puede considerar como un encabezado que contiene información sobre la codificación, los tamaños de fotogramas, etcétera. Un cliente debe obtenerlo para una representación determinada antes de consumir segmentos de contenido multimedia de esa representación.
En síntesis:
- El contenido multimedia se codifica con diferentes tasas de bits.
- Los diferentes archivos de tasa de bits están disponibles desde un servidor HTTP.
- 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 de forma programática un manifiesto XML conocido como descripción de presentación multimedia (MPD). Aquí se describen los conjuntos de adaptación y las representaciones, con duraciones y URLs. Un 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 toma de el archivo .mpd que se usa para el reproductor de demostración de DASH de YouTube).
Según la especificación de DASH, en teoría, un archivo MPD podría usarse como src para un video. Sin embargo, para brindar más flexibilidad a los desarrolladores web, los proveedores de navegadores optaron por dejar la compatibilidad con DASH a las bibliotecas de JavaScript que usan MSE, 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 MSE también permite experimentar con formatos de manifiesto y mecanismos de entrega alternativos sin requerir cambios en el navegador. El reproductor Shaka de Google implementa un cliente DASH con compatibilidad con EME.
Mozilla Developer Network tiene instrucciones sobre cómo usar las herramientas de WebM y FFmpeg para segmentar videos y compilar un MPD.
Conclusión
El uso de la Web para publicar audio y video pagados está creciendo a un ritmo enorme. Al parecer, todos los dispositivos nuevos, ya sean tablets, consolas de juegos, TVs conectadas o decodificadores, pueden transmitir contenido multimedia de los principales proveedores de contenido a través de HTTP. Más del 85% de los navegadores para computadoras y dispositivos móviles ahora admiten <video> y <audio>, y Cisco estima que, en 2017, el video representará entre el 80 y el 90 por ciento del tráfico de Internet de los consumidores. En este contexto, es probable que la compatibilidad del navegador con la distribución de contenido protegido sea cada vez más importante, ya que los proveedores de navegadores recortan la compatibilidad con las APIs de las que dependen la mayoría de los complementos multimedia.
Lecturas adicionales
Especificaciones y estándares
Especificación de EME: Versión más reciente del borrador del editor Codificación común (CENC) Extensiones de fuente de medios: Versión más reciente del borrador del editor Estándar DASH (sí, es un PDF) Descripción general del estándar DASH
Artículos
Seminario en línea de DTG (parcialmente obsoleto) What is EME?, de Henri Sivonen Media Source Extensions primer MPEG-DASH Test Streams: entrada de blog de I+D de la BBC
Demostraciones
Demo de Clear Key: simpl.info/ck Demo de extensiones de fuente de medios (MSE) El reproductor Shaka de Google implementa un cliente DASH con compatibilidad con EME.