Encrypted Media Extensions (EME) fornece uma API que permite que aplicativos da Web interajam com sistemas de proteção de conteúdo, para permitir a reprodução de áudio e vídeo criptografados.
O EME foi projetado para permitir que o mesmo app e arquivos criptografados sejam usados em qualquer navegador, independentemente do sistema de proteção. O primeiro é possibilitado pelo fluxo e APIs padronizados, enquanto o segundo é possibilitado pelo conceito de criptografia comum.
O EME é uma extensão da especificação HTMLMediaElement
, daí o nome. Ser uma "extensão" significa que o suporte do navegador para o EME é opcional: se um navegador não oferece suporte a mídia criptografada, ele não poderá reproduzir mídia criptografada, mas o EME não é necessário para conformidade com as especificações HTML. De a especificação EME:
As implementações de EME usam os seguintes componentes externos:
- Sistema de chaves:um mecanismo de proteção de conteúdo (DRM, na sigla em inglês). O EME não define os Key Systems em si, exceto Clear Key (mais sobre isso abaixo).
- Módulo de descriptografia de conteúdo (CDM, na sigla em inglês): um mecanismo de software ou hardware do lado do cliente que permite a reprodução de mídia criptografada. Assim como o Key Systems, o EME não define nenhum CDM, mas fornece uma interface para que os aplicativos interajam com os CDMs disponíveis.
- Servidor de licença (chave): interage com um CDM para fornecer chaves para descriptografar mídia. A negociação com o servidor de licença é de responsabilidade do aplicativo.
- Serviço de empacotamento: codifica e criptografa mídia para distribuição/consumo.
Observe que um aplicativo que usa o EME interage com um servidor de licenças para conseguir chaves para ativar a descriptografia, mas a identidade e a autenticação do usuário não fazem parte do EME. A recuperação de chaves para ativar a reprodução de mídia acontece após (opcionalmente) a autenticação de um usuário. Serviços como a Netflix precisam autenticar os usuários no aplicativo da Web. Quando um usuário faz login no aplicativo, ele determina a identidade e os privilégios do usuário.
Como funciona o EME?
Confira como os componentes do EME interagem, correspondendo ao exemplo de código abaixo:
- Um aplicativo da Web tenta reproduzir áudio ou vídeo com um ou mais streams criptografados.
- O navegador reconhece que a mídia está criptografada (consulte o quadro abaixo para saber como isso acontece) e dispara um evento
encrypted
com metadados (initData
) extraídos da mídia sobre a criptografia. - O aplicativo processa o evento
encrypted
:- Se nenhum objeto
MediaKeys
tiver sido associado ao elemento de mídia, primeiro selecione um sistema de chaves disponível usandonavigator.requestMediaKeySystemAccess()
para verificar quais sistemas de chaves estão disponíveis e crie um objetoMediaKeys
para um sistema de chaves disponível usando um objetoMediaKeySystemAccess
. A inicialização do objeto MediaKeys precisa acontecer antes do primeiro eventoencrypted
. A obtenção de um URL do servidor de licença é feita pelo app, independentemente da seleção de um sistema de chaves disponível. Um objetoMediaKeys
representa todas as chaves disponíveis para descriptografar a mídia de um elemento de áudio ou vídeo. Ele representa uma instância do CDM e fornece acesso a ele, especificamente para criar sessões de chaves, que são usadas para receber chaves de um servidor de licença. - Depois que o objeto
MediaKeys
for criado, atribua-o ao elemento de mídia:setMediaKeys()
associa o objetoMediaKeys
a um HTMLMediaElement, para que as chaves possam ser usadas durante a reprodução, ou seja, durante a decodificação.
- Se nenhum objeto
- O app cria um
MediaKeySession
chamandocreateSession()
noMediaKeys
. Isso cria umMediaKeySession
, que representa a validade de uma licença e as chaves dela. - O app gera uma solicitação de licença transmitindo os dados de mídia recebidos no gerenciador
encrypted
para o CDM, chamandogenerateRequest()
noMediaKeySession
. - O CDM dispara um evento
message
: uma solicitação para adquirir uma chave de um servidor de licença. - O objeto
MediaKeySession
recebe o eventomessage
, e o aplicativo envia uma mensagem ao servidor de licença (por XHR, por exemplo). - O aplicativo recebe uma resposta do servidor de licença e transmite os dados ao CDM usando o método
update()
doMediaKeySession
. - O CDM descriptografa a mídia usando as chaves da licença. Uma chave válida pode ser usada em qualquer sessão nas
MediaKey
s associadas ao elemento de mídia. O CDM acessará a chave e a política, indexadas por ID da chave. - A reprodução de mídia é retomada.
Ufa…
Pode haver várias mensagens entre o CDM e o servidor de licenças, e toda a comunicação nesse processo é obscura para o navegador e o aplicativo: as mensagens só são entendidas pelo CDM e pelo servidor de licenças, embora a camada do app possa ver que tipo de mensagem o CDM está enviando. A solicitação de licença contém provas da validade (e relação de confiança) do CDM, bem como uma chave para usar ao criptografar as chaves de conteúdo na licença resultante.
…mas o que os CDMs realmente fazem?
Uma implementação de EME não oferece uma maneira de descriptografar mídia: ela simplesmente fornece uma API para um aplicativo da Web interagir com os módulos de descriptografia de conteúdo.
O que os CDMs realmente fazem não é definido pela especificação EME, e um CDM pode processar a decodificação (descompressão) de mídia, bem como a descriptografia. Há várias opções possíveis para a funcionalidade do CDM, do menos ao mais robusto:
- Apenas descriptografia, permitindo a reprodução usando o pipeline de mídia normal, por exemplo, por um elemento
<video>
. - Descriptografia e decodificação, transmitindo frames de vídeo para o navegador para renderização.
- Descriptografia e decodificação, renderização diretamente no hardware (por exemplo, a GPU).
Há várias maneiras de disponibilizar um CDM para um app da Web:
- Agrupe um CDM com o navegador.
- Distribua um CDM separadamente.
- Crie um CDM no sistema operacional.
- Inclua um CDM no firmware.
- Incorpore um CDM no hardware.
A forma como um CDM é disponibilizado não é definida pela especificação EME, mas, em todos os casos, o navegador é responsável por verificar e expor o CDM.
O EME não exige um sistema de chaves específico. Entre os navegadores para computador e dispositivos móveis atuais, o Chrome oferece suporte ao Widevine, e o IE11 oferece suporte ao PlayReady.
Como receber uma chave de um servidor de licença
No uso comercial típico, o conteúdo é criptografado e codificado usando um serviço ou ferramenta de empacotamento. Depois que a mídia criptografada é disponibilizada on-line, um cliente da Web pode obter uma chave (contida em uma licença) de um servidor de licença e usá-la para ativar a descriptografia e a reprodução do conteúdo.
O código abaixo (adaptado dos exemplos de especificação) mostra como um aplicativo pode selecionar um sistema de chaves adequado e receber uma chave de um servidor de licença.
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')
);
}
Criptografia comum
As soluções de criptografia comum permitem que os provedores de conteúdo criptografem e empacotem o conteúdo uma vez por contêiner/codec e o usem com vários sistemas de chaves, CDMs e clientes, ou seja, qualquer CDM compatível com a criptografia comum. Por exemplo, um vídeo empacotado com o Playready pode ser reproduzido em um navegador usando um CDM do Widevine que recebe uma chave de um servidor de licença do Widevine.
Isso contrasta com as soluções legadas que só funcionam com uma pilha vertical completa, incluindo um único cliente que também costuma incluir um ambiente de execução de aplicativo.
A Criptografia comum (CENC) é um padrão ISO que define um esquema de proteção para o ISO BMFF. Um conceito semelhante se aplica ao WebM.
Remover chave
Embora o EME não defina a funcionalidade DRM, a especificação atualmente exige que todos os navegadores compatíveis com o EME implementem a chave clara. Com esse sistema, a mídia pode ser criptografada com uma chave e reproduzida simplesmente fornecendo essa chave. A chave clara pode ser integrada ao navegador: ela não exige o uso de um módulo de descriptografia separado.
Embora não seja provável que seja usado para muitos tipos de conteúdo comercial, o Clear Key é totalmente interoperável em todos os navegadores compatíveis com o EME. Ele também é útil para testar implementações de EME e aplicativos que usam EME, sem a necessidade de solicitar uma chave de conteúdo de um servidor de licença. Há um exemplo simples de chave clara em simpl.info/ck. Veja abaixo um tutorial do código, que é paralelo às etapas descritas acima, embora sem interação com o servidor de licença.
// 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 testar esse código, é necessário ter um vídeo criptografado para assistir. A criptografia de um vídeo para uso com Clear Key pode ser feita para WebM de acordo com as instruções de webm_crypt. Serviços comerciais também estão disponíveis (pelo menos para ISO BMFF/MP4), e outras soluções estão sendo desenvolvidas.
Tecnologia relacionada no 1
Extensões de fonte de mídia (MSE)
O HTMLMediaElement é uma criatura de beleza simples.
É possível carregar, decodificar e reproduzir mídias simplesmente fornecendo um URL de src:
<video src='foo.webm'></video>
A API Media Source é uma extensão do HTMLMediaElement que permite um controle mais preciso sobre a origem da mídia, permitindo que o JavaScript crie streams para reprodução de "fragmentos" de vídeo. Isso, por sua vez, permite técnicas como streaming adaptável e mudança de tempo.
Por que a MSE é importante para a EME? Porque, além de distribuir conteúdo protegido, os provedores de conteúdo comercial precisam adaptar a entrega de conteúdo às condições de rede e outros requisitos. A Netflix, por exemplo, muda dinamicamente a taxa de bits do streaming conforme as condições da rede mudam. O EME funciona com a reprodução de streams de mídia fornecidos por uma implementação de MSE, assim como faria com mídia fornecida por um atributo src
.
Como dividir e reproduzir mídia codificada em diferentes taxas de bits? Consulte a seção DASH abaixo.
Veja o MSE em ação em simpl.info/mse. Para este exemplo, um vídeo WebM é dividido em cinco partes usando as APIs de arquivo. Em um aplicativo de produção, blocos de vídeo seriam recuperados via Ajax.
Primeiro, um SourceBuffer é criado:
var sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vorbis,vp8"');
Depois, o filme inteiro é transmitido a um elemento de vídeo, anexando-se cada fragmento usando o método anexeBuffer():
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);
}
};
Saiba mais sobre o MSE no artigo do HTML5 Rocks (link em inglês).
Tecnologia relacionada no 2
Dynamic Adaptive Streaming over HTTP (DASH)
Multidispositivo, multiplataforma, dispositivos móveis - seja qual for o nome, a Web geralmente é vivenciada em condições de conectividade inconstante. A entrega dinâmica e adaptativa é essencial para lidar com restrições de largura de banda e variabilidade no mundo de vários dispositivos.
O DASH (também conhecido como MPEG-DASH) foi projetado para permitir a melhor entrega de mídia possível em um mundo instável, para streaming e download. Várias outras tecnologias fazem algo semelhante, como o HTTP Live Streaming (HLS) da Apple e o Streaming suave da Microsoft, mas o DASH é o único método de streaming com taxa de bits adaptável via HTTP baseado em um padrão aberto. O DASH já está em uso em sites como o YouTube.
Qual é a relação disso com EME e MSE? As implementações DASH com base em MSE podem analisar um manifesto, fazer o download de segmentos de vídeo com uma taxa de bits apropriada e inseri-los em um elemento de vídeo quando houver necessidade, usando a infraestrutura HTTP existente.
Em outras palavras, o DASH permite que os provedores de conteúdo comercial façam streaming adaptável de conteúdo protegido.
O DASH faz o que diz:
- Dinâmico: responde a condições variáveis.
- Adaptável: se adapta para fornecer uma taxa de bits de áudio ou vídeo adequada.
- Streaming: permite streaming e download.
- HTTP: permite a entrega de conteúdo com a vantagem do HTTP, sem as desvantagens de um servidor de streaming tradicional.
A BBC começou a oferecer transmissões de teste usando o DASH:
Para resumir:
- A mídia é codificada em diferentes taxas de bits.
- Os diferentes arquivos de bitrate são disponibilizados em um servidor HTTP.
- Um app da Web cliente escolhe qual taxa de bits recuperar e reproduzir com o DASH.
Como parte do processo de segmentação de vídeo, um manifesto XML conhecido como descrição de apresentação de mídia (MPD, na sigla em inglês) é criado de forma programática. Isso descreve conjuntos de adaptações e representações, com durações e URLs. Uma MPD tem a seguinte aparência:
<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 foi extraído do arquivo .mpd usado para o player de demonstração do YouTube DASH.
De acordo com a especificação DASH, um arquivo MPD pode, em teoria, ser usado como src
para um vídeo. No entanto, para dar mais flexibilidade aos desenvolvedores da Web, os fornecedores de navegadores optaram por deixar o suporte ao DASH para bibliotecas JavaScript usando MSE, como dash.js. A implementação do DASH em JavaScript permite que o algoritmo de adaptação evolua sem exigir atualizações do navegador. O uso do MSE também permite experimentar formatos de manifesto e mecanismos de entrega alternativos sem precisar fazer mudanças no navegador. O Shaka Player do Google implementa um cliente DASH com suporte a EME.
A Mozilla Developer Network tem instruções sobre como usar ferramentas WebM e FFmpeg para segmentar vídeos e criar um MPD.
Conclusão
O uso da Web para veicular áudio e vídeo pagos está crescendo a uma taxa enorme. Parece que todo novo dispositivo, seja um tablet, console de jogos, smart TV ou conversor, pode transmitir mídia dos principais provedores de conteúdo por HTTP. Mais de 85% dos navegadores para dispositivos móveis e computadores agora são compatíveis com <video>
e <audio>
, e a Cisco estima que os vídeos serão de 80 a 90% do tráfego global de Internet dos consumidores até 2017. Nesse contexto, o suporte do navegador para a distribuição de conteúdo protegido provavelmente vai se tornar cada vez mais significativo, já que os fornecedores de navegador restringem o suporte a APIs que a maioria dos plug-ins de mídia depende.
Leitura adicional
Especificações e padrões
- Especificações do EME: rascunho mais recente do editor<
- Criptografia comum (CENC)
- Extensões de fonte de mídia
- Norma DASH (sim, é um PDF)
- Sobre a norma DASH
Artigos
- Webinar sobre a DTG (parcialmente obsoleto)
- O que é EME?, por Henri Sivonen
- HTML5 Rocks Media Source Extensions article
- Transmissões de teste MPEG-DASH: postagem do blog da BBC R&D