Che cos'è EME?

Encrypted Media Extensions fornisce un'API che consente alle applicazioni web di interagire con i sistemi di protezione dei contenuti, per consentire la riproduzione di audio e video criptati.

EME è progettata per consentire l'utilizzo della stessa app e degli stessi file criptati in qualsiasi browser, indipendentemente dal sistema di protezione sottostante. La prima è resa possibile dal flusso e dalle API standardizzate, mentre la seconda è resa possibile dal concetto di Crittografia comune.

EME è un'estensione della specifica HTMLMediaElement, da cui il nome. Essendo una "estensione", il supporto del browser per EME è facoltativo: se un browser non supporta i contenuti multimediali criptati non sarà in grado di riprodurre i contenuti multimediali criptati, ma la tecnologia EME non è necessaria per la conformità delle specifiche HTML. Dalle specifiche EME:

Questa proposta estende HTMLMediaElement fornendo API per controllare la riproduzione dei contenuti protetti.

L'API supporta casi d'uso che vanno dalla semplice decrittografia di chiavi chiare ai video di alto valore (fornendo un'implementazione adeguata dello user agent). Lo scambio di licenze/chiavi è controllato dall'applicazione, consentendo lo sviluppo di applicazioni di riproduzione affidabili che supportano una serie di tecnologie di decrittografia e protezione dei contenuti.

Questa specifica non definisce un sistema di protezione dei contenuti o di gestione dei diritti digitali. Piuttosto, definisce un'API comune che può essere utilizzata per scoprire, selezionare e interagire con questi sistemi, nonché con sistemi di crittografia dei contenuti più semplici. L'implementazione di Digital Rights Management non è necessaria per la conformità con questa specifica: solo il sistema Clear Key deve essere implementato come base di riferimento comune.

L'API comune supporta un semplice insieme di funzionalità di crittografia dei contenuti, lasciando funzioni dell'applicazione come l'autenticazione e l'autorizzazione agli autori delle pagine. Per ottenere questo risultato, è necessario che la pagina utilizzi messaggi specifici del sistema di protezione dei contenuti, anziché presumere che la comunicazione fuori banda tra il sistema di crittografia e una licenza o un altro server.

Le implementazioni EME utilizzano i seguenti componenti esterni:

  • Sistema chiavi: un meccanismo di protezione dei contenuti (DRM). EME non definisce in autonomia i sistemi Key, a parte Clear Key (maggiori informazioni di seguito).
  • Content Decryption Module (CDM): un meccanismo hardware o software lato client che consente la riproduzione di contenuti multimediali criptati. Come con Key Systems, EME non definisce alcun CDM, ma fornisce un'interfaccia per le applicazioni per interagire con i CDM disponibili.
  • Server licenza (chiave): interagisce con un CDM per fornire chiavi per decriptare i contenuti multimediali. La negoziazione con il server delle licenze è responsabilità dell'applicazione.
  • Servizio di imballaggio: codifica e cripta i contenuti multimediali per la distribuzione/il consumo.

Tieni presente che un'applicazione che utilizza EME interagisce con un server di licenze per ottenere le chiavi per attivare la decrittografia, ma l'identità e l'autenticazione utente non fanno parte di EME. Il recupero delle chiavi per abilitare la riproduzione di contenuti multimediali avviene dopo (facoltativamente) aver autenticato un utente. Servizi come Netflix devono autenticare gli utenti all'interno della loro applicazione web: quando un utente accede all'applicazione, l'applicazione determina l'identità e i privilegi dell'utente.

Come funziona EME?

Ecco come interagiscono i componenti di EME, corrispondente all'esempio di codice riportato di seguito:

Se sono disponibili più formati o codec, MediaSource.isTypeSupported() o HTMLMediaElement.canPlayType() possono essere utilizzati entrambi per selezionare quello giusto. Tuttavia, il CDM potrebbe supportare solo un sottoinsieme di ciò che il browser supporta per i contenuti non criptati. È preferibile negoziare una configurazione MediaKeys prima di selezionare un formato e un codec. Se l'applicazione attende l'evento criptato, ma MediaKeys indica che non è in grado di gestire il formato/codec scelto, potrebbe essere troppo tardi per effettuare il passaggio senza interrompere la riproduzione.

Il flusso consigliato consiste nel negoziare prima MediaKeys, utilizzando MediaKeysSystemAccess.getConfiguration() per scoprire la configurazione negoziata.

Se puoi scegliere un solo formato/codec, non è necessario utilizzare getConfiguration(). Tuttavia, è comunque preferibile configurare prima MediaKey. L'unico motivo per attendere l'evento criptato è se non è possibile sapere se i contenuti sono criptati o meno, ma in pratica è improbabile.

  1. Un'applicazione web tenta di riprodurre audio o video con uno o più stream criptati.
  2. Il browser riconosce che i contenuti multimediali sono criptati (vedi la casella sotto per informazioni in merito) e attiva un evento criptato con metadati (initData) ottenuti dai contenuti multimediali relativi alla crittografia.
  3. L'applicazione gestisce l'evento criptato:

    1. Se nessun oggetto MediaKeys è stato associato all'elemento multimediale, seleziona prima un sistema di chiavi disponibile utilizzando navigator.requestMediaKeySystemAccess() per verificare quali sistemi di chiavi sono disponibili, quindi crea un oggetto MediaKeys per un sistema chiavi disponibile tramite un oggetto MediaKeySystemAccess. Tieni presente che l'inizializzazione dell'oggetto MediaKeys dovrebbe avvenire prima del primo evento criptato. L'app consente di ottenere l'URL di un server di licenze a prescindere dalla selezione di un sistema di chiavi disponibile. Un oggetto MediaKeys rappresenta tutte le chiavi disponibili per decriptare i contenuti multimediali per un elemento audio o video. Rappresenta un'istanza CDM e fornisce accesso a CDM, in particolare per la creazione di sessioni chiave, utilizzate per ottenere le chiavi da un server di licenze.

    2. Una volta creato l'oggetto MediaKeys, assegnalo all'elemento multimediale: setMediaKeys() associa l'oggetto MediaKeys a un HTMLMediaElement, in modo che le relative chiavi possano essere utilizzate durante la riproduzione, ovvero durante la decodifica.

  4. L'app crea una MediaKeySession chiamando createSession() su MediaKey. Viene creata una MediaKeySession, che rappresenta la durata di una licenza e delle relative chiavi.

  5. L'app genera una richiesta di licenza passando i dati multimediali ottenuti nel gestore criptato al CDM, chiamando generateRequest() nella sessione MediaKeySession.

  6. Il CDM attiva un evento di messaggio: una richiesta di acquisizione di una chiave da un server di licenze.

  7. L'oggetto MediaKeySession riceve l'evento del messaggio e l'applicazione invia un messaggio al server delle licenze (ad esempio tramite XHR).

  8. L'applicazione riceve una risposta dal server delle licenze e passa i dati al CDM utilizzando il metodo update() di MediaKeySession.

  9. Il CDM decripta i contenuti multimediali utilizzando le chiavi incluse nella licenza. È possibile utilizzare una chiave valida da qualsiasi sessione all'interno delle chiavi MediaKey associate all'elemento multimediale. Il CDM accederà alla chiave e al criterio, indicizzati in base all'ID chiave.

La riproduzione dei contenuti multimediali riprende.

Come fa il browser a sapere che i contenuti multimediali sono criptati?

Queste informazioni sono presenti nei metadati del file del contenitore multimediale, che saranno in un formato come ISO BMFF o WebM. Per ISO BMFF, si tratta di metadati di intestazione, chiamati casella informativa sullo schema di protezione. WebM utilizza l'elemento Matroska ContentEncryption, con alcune aggiunte specifiche per WebM. Per ogni container vengono fornite linee guida in un registry specifico per EME.

Tieni presente che potrebbero esserci più messaggi tra CDM e il server delle licenze e tutte le comunicazioni in questo processo sono opache per il browser e l'applicazione: i messaggi vengono interpretati solo da CDM e dal server delle licenze, anche se il livello app può vedere quale tipo di messaggio sta inviando il CDM. La richiesta di licenza contiene una prova della validità (e della relazione di fiducia) del CDM, nonché una chiave da utilizzare per la crittografia delle chiavi dei contenuti nella licenza risultante.

Ma cosa fanno in realtà i CDM?

Un'implementazione EME non offre di per sé un modo per decriptare i contenuti multimediali, ma semplicemente fornisce un'API che consente a un'applicazione web di interagire con i moduli di decrittografia dei contenuti.

Ciò che in realtà fanno i CDM non è definito dalle specifiche EME e un CDM potrebbe gestire la decodifica (decompressione) dei contenuti multimediali e la decrittografia. A partire da quelli più affidabili, esistono diverse potenziali opzioni per la funzionalità CDM:

  • Solo decrittografia, che consente la riproduzione utilizzando la normale pipeline multimediale, ad esempio tramite un elemento <video>.
  • Decrittografia e decodifica, passaggio di frame video al browser per il rendering.
  • Decrittografia e decodifica, rendering direttamente nell'hardware (ad esempio, nella GPU).

Esistono diversi modi per rendere disponibile un CDM in un'app web:

  • Raggruppa un CDM con il browser.
  • Distribuisci un CDM separatamente.
  • di incorporare un CDM nel sistema operativo.
  • Includi un CDM nel firmware.
  • Incorporare un CDM nell'hardware.

Il modo in cui un CDM viene reso disponibile non è definito dalle specifiche EME, ma in tutti i casi il browser è responsabile del controllo e dell'esposizione del CDM.

EME non impone un particolare sistema chiavi; tra gli attuali browser desktop e mobile, Chrome supporta Widevine, mentre IE11 supporta PlayReady.

Recupero di una chiave da un server licenze

Nel tipico uso commerciale, i contenuti saranno criptati e codificati utilizzando un servizio o uno strumento di pacchettizzazione. Una volta che i contenuti multimediali criptati sono stati resi disponibili online, un client web può ottenere una chiave (contenuta in una licenza) da un server di licenze e utilizzarla per abilitare la decrittografia e la riproduzione dei contenuti.

Il seguente codice (adattato dagli esempi di specifiche) mostra in che modo un'applicazione può selezionare un sistema di chiavi appropriato e ottenere una chiave da un server di licenze.

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

Crittografia comune

Le soluzioni di crittografia comuni consentono ai fornitori di contenuti di criptare e pacchettizzare i propri contenuti una volta per container/codec e di utilizzarli con una varietà di sistemi chiavi, CDM e client, ovvero qualsiasi CDM che supporti la crittografia comune. Ad esempio, un video pacchettizzato con Playready potrebbe essere riprodotto in un browser utilizzando un CDM Widevine che ottiene una chiave da un server licenze Widevine.

Questo è in contrasto con le soluzioni legacy che funzionavano solo con uno stack verticale completo, incluso un singolo client che spesso includeva anche un runtime dell'applicazione.

La crittografia comune (CENC) è uno standard ISO che definisce uno schema di protezione per ISO BMFF. Un concetto simile si applica a WebM.

Cancella chiave

Sebbene EME non definisca la funzionalità DRM, la specifica attualmente impone che tutti i browser che supportano EME debbano implementare la funzionalità Clear Key. Con questo sistema, i contenuti multimediali possono essere criptati con una chiave e quindi riprodotti semplicemente fornendo la chiave. La chiave Clear può essere integrata nel browser: non richiede l'uso di un modulo di decrittografia separato.

Sebbene non sia probabile che venga utilizzato per molti tipi di contenuti commerciali, Clear Key è completamente interoperabile tra tutti i browser che supportano EME. È utile anche per testare le implementazioni EME e le applicazioni che utilizzano EME, senza dover richiedere una chiave dei contenuti a un server licenze. È disponibile un esempio di Clear Key semplice all'indirizzo simpl.info/ck. Di seguito è riportata una procedura dettagliata del codice, che corrisponde ai passaggi descritti sopra, ma senza interazione del server delle licenze.

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

Per testare questo codice, è necessario un video criptato da riprodurre. La crittografia di un video per l'utilizzo con Clear Key può essere eseguita per WebM come da istruzioni webm_crypt. Sono inoltre disponibili servizi commerciali (almeno per ISO BMFF/MP4) e altre soluzioni sono in fase di sviluppo.

HTMLMediaElement è una creatura di semplice bellezza.

Possiamo caricare, decodificare e riprodurre i contenuti multimediali semplicemente fornendo un URL src:

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

L'API Media Source è un'estensione di HTMLMediaElement che consente un controllo più granulare sull'origine dei contenuti multimediali, consentendo a JavaScript di creare flussi per la riproduzione da "blocchi" di video. Questo, a sua volta, consente tecniche come lo streaming adattivo e lo spostamento temporale.

Perché la funzione MSE è importante per l'EME? Perché, oltre a distribuire contenuti protetti, i fornitori di contenuti commerciali devono poter adattare la distribuzione dei contenuti alle condizioni della rete e ad altri requisiti. Netflix, ad esempio, modifica dinamicamente la velocità in bit dello stream al variare delle condizioni della rete. EME funziona con la riproduzione degli stream multimediali forniti da un'implementazione MSE, proprio come farebbe con i contenuti multimediali forniti tramite un attributo src.

Come suddividere e riprodurre i contenuti multimediali codificati con velocità in bit diverse? Consulta la sezione DASH di seguito.

Puoi vedere MSE in azione all'indirizzo simpl.info/mse. Ai fini di questo esempio, un video WebM è suddiviso in cinque parti utilizzando le API file. In un'applicazione di produzione, vengono recuperati blocchi di video tramite AJAX.

Innanzitutto viene creato un buffer di origine:

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

L'intero filmato viene quindi "trasmesso in streaming" a un elemento video aggiungendo ogni blocco utilizzando il metodo 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);
  }
};

Scopri di più su MSE nel documento su MSE.

Multi-dispositivo, multipiattaforma e dispositivi mobili. Comunque sia, il web si trova spesso in condizioni di connettività variabile. La pubblicazione dinamica e adattiva è fondamentale per far fronte ai limiti e alla variabilità della larghezza di banda nel mondo multi-dispositivo.

DASH (noto anche come MPEG-DASH) è progettato per consentire la migliore pubblicazione di contenuti multimediali in un mondo traballante, sia per lo streaming che per il download. Diverse altre tecnologie fanno qualcosa di simile, ad esempio HTTP Live Streaming (HLS) di Apple e Live Streaming di Microsoft, ma DASH è l'unico metodo di streaming a velocità in bit adattiva tramite HTTP e si basa su uno standard aperto. DASH è già utilizzato da siti come YouTube.

Che cosa c'entra tutto questo con EME e MSE? Le implementazioni DASH basate su MSE possono analizzare un manifest, scaricare segmenti di video a una velocità in bit appropriata e trasmetterli a un elemento video quando diventa affamato, utilizzando l'infrastruttura HTTP esistente.

In altre parole, DASH consente ai fornitori di contenuti commerciali di eseguire lo streaming adattivo di contenuti protetti.

DASH fa quello che dice sulla scatola:

  • Dinamico: risponde a condizioni variabili.
  • Adattiva: si adatta per fornire una velocità in bit audio o video appropriata.
  • Streaming: consente sia lo streaming sia il download.
  • HTTP: consente la distribuzione dei contenuti con il vantaggio di HTTP, senza gli svantaggi di un server di streaming tradizionale.

La BBC ha iniziato a fornire stream di prova utilizzando DASH:

I contenuti multimediali vengono codificati diverse volte a velocità in bit diverse. Ogni codifica è chiamata rappresentazione. Questi segmenti sono suddivisi in diversi segmenti multimediali. Il client riproduce un programma richiedendo segmenti, in ordine, da una rappresentazione tramite HTTP. Le rappresentazioni possono essere raggruppate in insiemi di adattamento di rappresentazioni con contenuti equivalenti. Se il client desidera modificare la velocità in bit, può scegliere un'alternativa dall'attuale set di adattamento e iniziare a richiedere segmenti da quella rappresentazione. I contenuti sono codificati in modo da semplificare il passaggio al cliente. Oltre a un certo numero di segmenti multimediali, una rappresentazione include in genere anche un segmento di inizializzazione. Può essere considerata come un'intestazione, contenente informazioni su codifica, dimensioni dei frame e così via. Un cliente deve ottenere questi dati per una determinata rappresentazione prima di utilizzare i segmenti multimediali di quella rappresentazione.

In sintesi:

  1. I contenuti multimediali sono codificati con velocità in bit diverse.
  2. I diversi file con velocità in bit vengono resi disponibili da un server HTTP.
  3. Un'app web client sceglie la velocità in bit da recuperare e riprodurre con DASH.

Nell'ambito del processo di segmentazione dei video, viene creato in modo programmatico un manifest XML noto come MPD (Media Presentaation Description). Questo descrive gli insiemi di adattamenti e le rappresentazioni, con durate e URL. Un MPD ha il seguente aspetto:

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

Questo XML è estratto dal file .mpd utilizzato per il player della demo DASH di YouTube.

Secondo le specifiche DASH, in teoria un file MPD potrebbe essere utilizzato come src per un video. Tuttavia, per offrire maggiore flessibilità agli sviluppatori web, i fornitori di browser hanno scelto di lasciare il supporto DASH fino alle librerie JavaScript che utilizzano MSE, ad esempio dash.js. L'implementazione di DASH in JavaScript consente all'algoritmo di adattamento di evolversi senza richiedere aggiornamenti del browser. L'utilizzo di MSE consente inoltre di sperimentare con formati manifest e meccanismi di pubblicazione alternativi senza richiedere modifiche al browser. Il player Shaka di Google implementa un client DASH con supporto EMM.

Mozilla Developer Network offre istruzioni su come utilizzare gli strumenti WebM e FFmpeg per segmentare i video e creare un MPD.

Conclusione

L'utilizzo del web per offrire video e audio a pagamento sta crescendo a una frequenza enorme. Sembra che ogni nuovo dispositivo, che si tratti di tablet, console per videogiochi, TV connessa a internet o decoder, sia in grado di riprodurre in streaming i contenuti multimediali dei principali fornitori di contenuti tramite HTTP. Oltre l'85% dei browser mobile e desktop ora supportano <video> e <audio> e Cisco stima che i video costituiranno dall'80 al 90% del traffico internet globale dei consumatori entro il 2017. In questo contesto, è probabile che il supporto dei browser per la distribuzione di contenuti protetti diventerà sempre più significativo, in quanto i fornitori di browser riducono il supporto per le API su cui fa affidamento la maggior parte dei plug-in multimediali.

Per approfondire

Specifiche e standard

Specifiche EME: ultima bozza dell'editor Common Encryption (CENC) Media Source Extensions: ultima bozza dell'editor DASH standard (sì, è un PDF) Panoramica dello standard DASH

Articoli

Webinar DTG (parzialmente obsoleto) What is EME?, di Henri Sivonen Media Source Extensions primer MPEG-DASH Test Streams: BBC R&D blog post

Demo

Demo Clear Key: simpl.info/ck Demo Media Source Extensions (MSE) Il Shaka Player di Google implementa un client DASH con supporto EME

Feedback