Encrypted Media Extensions (EME) ist eine API, mit der Webanwendungen mit Content-Schutzsystemen interagieren können, um die Wiedergabe verschlüsselter Audio- und Videoinhalte zu ermöglichen.
EME soll es ermöglichen, dieselbe App und verschlüsselte Dateien in jedem Browser zu verwenden, unabhängig vom zugrunde liegenden Schutzsystem. Ersteres wird durch die standardisierten APIs und den Ablauf ermöglicht, während letzteres durch das Konzept der gemeinsamen Verschlüsselung ermöglicht wird.
EME ist eine Erweiterung der HTMLMediaElement
-Spezifikation – daher der Name. Da es sich um eine Erweiterung handelt, ist die Browserunterstützung für EME optional: Wenn ein Browser keine verschlüsselten Medien unterstützt, kann er sie nicht wiedergeben. EME ist jedoch nicht für die Einhaltung der HTML-Spezifikation erforderlich. Aus der EME-Spezifikation:
EME-Implementierungen verwenden die folgenden externen Komponenten:
- Schlüsselsystem: Ein Mechanismus zur Inhaltssicherung (Digital Rights Management, DRM). Außer Clear Key werden Schlüsselsysteme von EME nicht definiert. Weitere Informationen dazu findest du unten.
- Content Decryption Module (CDM): Ein clientseitiger Software- oder Hardwaremechanismus, der die Wiedergabe verschlüsselter Medien ermöglicht. Wie bei Key Systems definiert EME keine Datenabgleichsmechanismen, sondern bietet eine Schnittstelle für Anwendungen, über die sie mit verfügbaren Datenabgleichsmechanismen interagieren können.
- Lizenz- (Schlüssel-)Server: Interagiert mit einem CDM, um Schlüssel zur Entschlüsselung von Medien bereitzustellen. Die Verhandlung mit dem Lizenzserver liegt in der Verantwortung der Anwendung.
- Paketierungsservice:Codiert und verschlüsselt Medien für die Bereitstellung/Nutzung.
Eine Anwendung, die EME verwendet, interagiert mit einem Lizenzserver, um Schlüssel zur Dekodierung abzurufen. Nutzeridentität und Authentifizierung sind jedoch keine Bestandteile von EME. Die Abruf von Schlüsseln zur Aktivierung der Medienwiedergabe erfolgt nach der (optionalen) Authentifizierung eines Nutzers. Dienste wie Netflix müssen Nutzer in ihrer Webanwendung authentifizieren: Wenn sich ein Nutzer in der Anwendung anmeldet, bestimmt die Anwendung die Identität und Berechtigungen des Nutzers.
Wie funktioniert die erweiterte Medienwiedergabe?
Hier sehen Sie, wie die Komponenten der erweiterten Medienwiedergabe interagieren, was dem folgenden Codebeispiel entspricht:
- Eine Webanwendung versucht, Audio- oder Videoinhalte mit einem oder mehreren verschlüsselten Streams abzuspielen.
- Der Browser erkennt, dass die Medien verschlüsselt sind (siehe Kasten unten), und löst ein
encrypted
-Ereignis mit Metadaten (initData
) aus, die aus den Medien zur Verschlüsselung stammen. - Die Anwendung verarbeitet das Ereignis
encrypted
:- Wenn dem Medienelement kein
MediaKeys
-Objekt zugeordnet ist, wähle zuerst ein verfügbares Schlüsselsystem aus. Verwende dazunavigator.requestMediaKeySystemAccess()
, um zu prüfen, welche Schlüsselsysteme verfügbar sind. Erstelle dann über einMediaKeySystemAccess
-Objekt einMediaKeys
-Objekt für ein verfügbares Schlüsselsystem. Die Initialisierung des MediaKeys-Objekts sollte vor dem erstenencrypted
-Ereignis erfolgen. Die URL eines Lizenzservers wird von der App unabhängig von der Auswahl eines verfügbaren Schlüsselsystems abgerufen. EinMediaKeys
-Objekt stellt alle Schlüssel dar, die zum Entschlüsseln der Medien für ein Audio- oder Videoelement verfügbar sind. Er stellt eine CDM-Instanz dar und bietet Zugriff auf die CDM, insbesondere zum Erstellen von Schlüsselsitzungen, mit denen Schlüssel von einem Lizenzserver abgerufen werden. - Nachdem du das
MediaKeys
-Objekt erstellt hast, kannst du es dem Medienelement zuweisen:setMediaKeys()
verknüpft dasMediaKeys
-Objekt mit einem HTMLMediaElement, damit seine Schlüssel während der Wiedergabe, also während der Dekodierung, verwendet werden können.
- Wenn dem Medienelement kein
- Die App erstellt eine
MediaKeySession
, indem siecreateSession()
auf derMediaKeys
aufruft. Dadurch wird einMediaKeySession
erstellt, der die Lebensdauer einer Lizenz und ihrer Schlüssel darstellt. - Die App generiert eine Lizenzanfrage, indem sie die im
encrypted
-Handler abgerufenen Mediendaten an die CDM übergibt, indem siegenerateRequest()
auf derMediaKeySession
aufruft. - Das CDM löst ein
message
-Ereignis aus: eine Anfrage zum Abrufen eines Schlüssels von einem Lizenzserver. - Das
MediaKeySession
-Objekt empfängt dasmessage
-Ereignis und die Anwendung sendet eine Nachricht an den Lizenzserver (z. B. über XHR). - Die Anwendung empfängt eine Antwort vom Lizenzserver und übergibt die Daten mit der
update()
-Methode derMediaKeySession
an die CDM. - Der CDM entschlüsselt die Medien mit den Schlüsseln in der Lizenz. Es kann ein gültiger Schlüssel aus einer beliebigen Sitzung innerhalb der
MediaKey
s verwendet werden, die mit dem Medienelement verknüpft sind. Die CDM greift auf den Schlüssel und die Richtlinie zu, die anhand der Schlüssel-ID indexiert sind. - Die Medienwiedergabe wird fortgesetzt.
Puh…
Hinweis: Es kann mehrere Nachrichten zwischen dem CDM und dem Lizenzserver geben. Die gesamte Kommunikation in diesem Prozess ist für den Browser und die Anwendung undurchsichtig: Nachrichten werden nur vom CDM und vom Lizenzserver verstanden. Die App-Ebene kann jedoch sehen, welche Art von Nachricht vom CDM gesendet wird. Der Lizenzantrag enthält einen Nachweis der Gültigkeit der CDM (und der Vertrauensbeziehung) sowie einen Schlüssel, der zum Verschlüsseln der Inhaltsschlüssel in der resultierenden Lizenz verwendet wird.
…aber was machen Datenplattformen eigentlich?
Eine EME-Implementierung bietet an sich keine Möglichkeit, Medien zu entschlüsseln. Sie stellt lediglich eine API für eine Webanwendung bereit, mit der sie mit Content Decryption Modules interagieren kann.
Die tatsächliche Funktionsweise von CDMs wird in der EME-Spezifikation nicht definiert. Eine CDM kann sowohl die Dekodierung (Dekomprimierung) von Medien als auch die Entschlüsselung übernehmen. Es gibt mehrere Optionen für die CDM-Funktionen, die von der am wenigsten bis zur am robustesten reichen:
- Nur Entschlüsselung, ermöglicht die Wiedergabe über die normale Medienpipeline, z. B. über ein
<video>
-Element. - Entschlüsselung und Decodierung, Weitergabe von Videoframes an den Browser zum Rendern.
- Entschlüsselung und Dekodierung, Rendering direkt in der Hardware (z. B. der GPU).
Es gibt mehrere Möglichkeiten, eine CDM für eine Webanwendung verfügbar zu machen:
- Binde ein CDM mit dem Browser zusammen.
- CDM separat bereitstellen
- CDM in das Betriebssystem einbinden
- CDM in die Firmware aufnehmen
- Ein CDM in Hardware einbetten
Wie eine CDM verfügbar gemacht wird, wird in der EME-Spezifikation nicht definiert. In jedem Fall ist der Browser für die Prüfung und Freigabe der CDM verantwortlich.
EME schreibt kein bestimmtes Schlüsselsystem vor. Unter den aktuellen Desktop- und mobilen Browsern unterstützt Chrome Widevine und IE11 PlayReady.
Schlüssel von einem Lizenzserver abrufen
Bei der kommerziellen Nutzung werden Inhalte in der Regel mit einem Verpackungsdienst oder -tool verschlüsselt und codiert. Sobald die verschlüsselten Medien online verfügbar sind, kann ein Webclient einen Schlüssel (in einer Lizenz enthalten) von einem Lizenzserver abrufen und mit dem Schlüssel die Entschlüsselung und Wiedergabe der Inhalte ermöglichen.
Der folgende Code (aus den Beispielen in der Spezifikation adaptiert) zeigt, wie eine Anwendung ein geeignetes Schlüsselsystem auswählen und einen Schlüssel von einem Lizenzserver abrufen kann.
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')
);
}
Gemeinsame Verschlüsselung
Mit Lösungen für die gemeinsame Verschlüsselung können Contentanbieter ihre Inhalte einmal pro Container/Codec verschlüsseln und verpacken und mit einer Vielzahl von Schlüsselsystemen, Content-Distribution-Managern (CDMs) und Clients verwenden, also mit allen CDMs, die die gemeinsame Verschlüsselung unterstützen. Ein mit PlayReady verpacktes Video kann beispielsweise in einem Browser mit einer Widevine-CDM wiedergegeben werden, die einen Schlüssel von einem Widevine-Lizenzserver abholt.
Das ist im Gegensatz zu älteren Lösungen, die nur mit einem vollständigen vertikalen Stack funktionieren, einschließlich eines einzelnen Clients, der oft auch eine Anwendungslaufzeit umfasste.
Common Encryption (CENC) ist ein ISO-Standard, der ein Schutzschema für ISO BMFF definiert. Ein ähnliches Konzept gilt für WebM.
Clear Key
Obwohl EME keine DRM-Funktionen definiert, schreibt die Spezifikation derzeit vor, dass alle Browser, die EME unterstützen, Clear Key implementieren müssen. Mit diesem System können Medien mit einem Schlüssel verschlüsselt und dann einfach durch Angabe dieses Schlüssels wiedergegeben werden. Clear Key kann in den Browser eingebunden werden und erfordert kein separates Entschlüsselungsmodul.
Clear Key wird wahrscheinlich nicht für viele Arten von kommerziellen Inhalten verwendet, ist aber vollständig interoperabel mit allen Browsern, die EME unterstützen. Es eignet sich auch zum Testen von EME-Implementierungen und Anwendungen, die EME verwenden, ohne dass ein Inhaltsschlüssel von einem Lizenzserver angefordert werden muss. Ein einfaches Beispiel für einen Clear Key findest du unter simpl.info/ck. Unten findest du eine Schritt-für-Schritt-Anleitung für den Code, die den oben beschriebenen Schritten entspricht, jedoch ohne Interaktion mit dem Lizenzserver.
// 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]
}));
}
Um diesen Code zu testen, benötigst du ein verschlüsseltes Video, das du abspielen kannst. Die Verschlüsselung eines Videos für die Verwendung mit Clear Key kann für WebM gemäß der Anleitung für webm_crypt erfolgen. Kommerzielle Dienste sind ebenfalls verfügbar (zumindest für ISO BMFF/MP4) und es werden weitere Lösungen entwickelt.
Ähnliche Technologie 1
Media Source Extensions (MSE)
Das HTMLMediaElement ist ein einfaches, aber schönes Element.
Wir können Medien einfach laden, decodieren und abspielen, indem wir eine src-URL angeben:
<video src='foo.webm'></video>
Die Media Source API ist eine Erweiterung von HTMLMediaElement, die eine detailliertere Steuerung der Medienquelle ermöglicht. Mit JavaScript können Streams zur Wiedergabe aus Video-Chunks erstellt werden. Dies ermöglicht wiederum Techniken wie adaptives Streaming und Zeitverschiebung.
Warum ist MSE für EME wichtig? Denn neben der Bereitstellung geschützter Inhalte müssen kommerzielle Anbieter von Inhalten die Bereitstellung von Inhalten an Netzwerkbedingungen und andere Anforderungen anpassen können. Netflix ändert beispielsweise die Streambitrate dynamisch, wenn sich die Netzwerkbedingungen ändern. EME funktioniert bei der Wiedergabe von Medienstreams, die über eine MSE-Implementierung bereitgestellt werden, genauso wie bei Medien, die über ein src
-Attribut bereitgestellt werden.
Wie kann ich Medien, die mit unterschiedlichen Bitraten codiert wurden, in einzelne Segmente aufteilen und abspielen? Weitere Informationen findest du im Abschnitt zu DASH unten.
MSE in Aktion sehen Sie unter simpl.info/mse. In diesem Beispiel wird ein WebM-Video mithilfe der File APIs in fünf Blöcke aufgeteilt. In einer Produktionsanwendung werden Video-Chunks über Ajax abgerufen.
Zuerst wird ein SourceBuffer erstellt:
var sourceBuffer = mediaSource.addSourceBuffer('video/webm; codecs="vorbis,vp8"');
Der gesamte Film wird dann an ein Videoelement „gestreamt“, indem jeder Chunk mit der Methode „appendBuffer()“ angehängt wird:
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);
}
};
Weitere Informationen zu MSE findest du im HTML5 Rocks-Artikel.
Ähnliche Technologie 2
Dynamic Adaptive Streaming over HTTP (DASH)
Ob für mehrere Geräte, mehrere Plattformen oder Mobilgeräte – das Web wird oft unter Bedingungen mit wechselnder Konnektivität genutzt. Die dynamische, adaptive Bereitstellung ist entscheidend, um Bandbreiteneinschränkungen und Variabilität in der Multi-Device-Welt zu bewältigen.
DASH (auch MPEG-DASH genannt) wurde entwickelt, um die bestmögliche Medienübermittlung in einer fehlerhaften Umgebung zu ermöglichen, sowohl für Streaming als auch für Downloads. Es gibt mehrere ähnliche Technologien, z. B. HTTP Live Streaming (HLS) von Apple und Smooth Streaming von Microsoft. DASH ist jedoch die einzige Methode für das Streaming mit adaptiver Bitrate über HTTP, die auf einem offenen Standard basiert. DASH wird bereits von Websites wie YouTube verwendet.
Was hat das mit EME und MSE zu tun? MSE-basierte DASH-Implementierungen können ein Manifest parsen, Videosegmente mit einer geeigneten Bitrate herunterladen und sie einem Videoelement zuführen, wenn es benötigt wird – und zwar mithilfe der vorhandenen HTTP-Infrastruktur.
Mit DASH können kommerzielle Contentanbieter also geschützte Inhalte adaptiv streamen.
DASH hält, was es verspricht:
- Dynamisch: reagiert auf sich ändernde Bedingungen.
- Adaptiv:Die Audio- oder Videobitrate wird angepasst.
- Streaming:Ermöglicht sowohl Streaming als auch Download.
- HTTP:Ermöglicht die Bereitstellung von Inhalten mit den Vorteilen von HTTP, ohne die Nachteile eines herkömmlichen Streamingservers.
Die BBC bietet Teststreams mit DASH an:
Zusammenfassung:
- Medien werden mit unterschiedlichen Bitraten codiert.
- Die verschiedenen Bitratedateien werden von einem HTTP-Server bereitgestellt.
- Eine Client-Web-App wählt aus, welche Bitrate mit DASH abgerufen und wiedergegeben werden soll.
Im Rahmen der Videosegmentierung wird programmatisch ein XML-Manifest erstellt, das als Media Presentation Description (MPD) bezeichnet wird. Hier werden Anpassungssätze und Darstellungen mit Dauern und URLs beschrieben. Eine MPD sieht so aus:
<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>
(Diese XML-Datei stammt aus der .mpd-Datei, die für den YouTube DASH-Demoplayer verwendet wird.)
Gemäß der DASH-Spezifikation kann eine MPD-Datei theoretisch als src
für ein Video verwendet werden. Um Webentwicklern jedoch mehr Flexibilität zu bieten, haben Browseranbieter die DASH-Unterstützung stattdessen JavaScript-Bibliotheken mit MSE wie dash.js überlassen. Durch die Implementierung von DASH in JavaScript kann der Anpassungsalgorithmus weiterentwickelt werden, ohne dass Browserupdates erforderlich sind. Mit MSE können Sie auch mit alternativen Manifestformaten und Bereitstellungsmechanismen experimentieren, ohne Änderungen am Browser vornehmen zu müssen. Der Shaka Player von Google implementiert einen DASH-Client mit EME-Unterstützung.
Im Mozilla Developer Network findest du eine Anleitung dazu, wie du mit WebM-Tools und FFmpeg ein Video segmentierst und eine MPD erstellst.
Fazit
Die Nutzung des Webs für die Bereitstellung kostenpflichtiger Video- und Audioinhalte nimmt rasant zu. Es scheint, als ob jedes neue Gerät, sei es ein Tablet, eine Spielekonsole, ein internetfähiger Fernseher oder eine Set-Top-Box, Medien von den wichtigsten Inhaltsanbietern über HTTP streamen kann. <video>
und <audio>
werden jetzt von über 85 % der mobilen und Desktop-Browser unterstützt. Cisco schätzt, dass Videos bis 2017 80 bis 90 % des weltweiten Internettraffics von Verbrauchern ausmachen werden. In diesem Zusammenhang wird die Browserunterstützung für die Bereitstellung geschützter Inhalte wahrscheinlich immer wichtiger werden, da Browseranbieter die Unterstützung für APIs einschränken, auf die die meisten Medien-Plug-ins angewiesen sind.
Weitere Informationen
Spezifikationen und Standards
- EME-Spezifikation: aktueller Editor's Draft<
- Common Encryption (CENC)
- Erweiterungen für Medienquellen
- DASH-Standard (ja, es ist eine PDF-Datei)
- DASH-Standard
Artikel
- DTG Webinar (teilweise veraltet)
- What is EME? von Henri Sivonen
- Artikel „HTML5 Rocks Media Source Extensions“
- MPEG-DASH-Teststreams: Blogpost der BBC R&D