Signatur
Beschreibung
Das Interface MediaSourceHandle gehört zu den Media Source Extensions (MSE). Es ermöglicht, ein MediaSource-Objekt in einem dedizierten Worker zu erzeugen und zu befüllen, die Wiedergabe aber im Haupt-Thread über ein <video>- oder <audio>-Element laufen zu lassen. So lassen sich aufwendige Arbeiten wie das Laden von Segmenten, Demuxen, Transmuxen oder Entschlüsseln aus dem Haupt-Thread herausnehmen. Die Oberfläche bleibt dadurch flüssig, und die Wiedergabe stockt nicht, wenn der Haupt-Thread gerade beschäftigt ist.
Man erzeugt ein Handle nicht selbst, es gibt keinen Konstruktor. Stattdessen liest man im Worker die Eigenschaft MediaSource.prototype.handle aus. Dieses Objekt ist übertragbar (transferable): Man schickt es mit postMessage(handle, [handle]) an den Haupt-Thread und weist es dort HTMLMediaElement.srcObject zu. Die eigentliche Datenversorgung über SourceBuffer.appendBuffer() läuft weiter im Worker.
Das Interface hat keine eigenen Eigenschaften oder Methoden. Es ist nur ein undurchsichtiger Verweis auf das zugehörige MediaSource. Ob ein Browser MSE in Workern unterstützt, prüft man mit der statischen Eigenschaft MediaSource.canConstructInDedicatedWorker.
Rückgabewert
MediaSource.prototype.handle in einem dedizierten Worker abgerufen. Für jede MediaSource gibt es genau ein Handle, jeder Zugriff liefert dasselbe Objekt.Beispiele
Worker: MediaSource erzeugen und Handle übertragen
// media-worker.js
const mediaSource = new MediaSource();
const handle = mediaSource.handle;
// Handle als übertragbares Objekt an den Haupt-Thread senden
postMessage({ type: 'handle', handle }, [handle]);
mediaSource.addEventListener('sourceopen', async () => {
const mime = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
const sourceBuffer = mediaSource.addSourceBuffer(mime);
const response = await fetch('/media/video-fragmentiert.mp4');
const data = await response.arrayBuffer();
sourceBuffer.addEventListener('updateend', () => {
if (mediaSource.readyState === 'open') {
mediaSource.endOfStream();
}
}, { once: true });
sourceBuffer.appendBuffer(data);
console.log('Segment wird im Worker angehängt');
});
Haupt-Thread: Handle an ein Video-Element binden
const video = document.querySelector('video');
const worker = new Worker('media-worker.js');
worker.addEventListener('message', ({ data }) => {
if (data.type === 'handle') {
console.log(data.handle instanceof MediaSourceHandle);
// Wichtig: srcObject verwenden, nicht src/createObjectURL
video.srcObject = data.handle;
video.play().catch((err) => console.warn('Autoplay blockiert:', err));
}
});
Feature-Erkennung mit Rückfall auf den Haupt-Thread
const supportsWorkerMse = () =>
'MediaSource' in window &&
MediaSource.canConstructInDedicatedWorker === true &&
'MediaSourceHandle' in window;
const video = document.querySelector('video');
if (supportsWorkerMse()) {
const worker = new Worker('media-worker.js');
worker.onmessage = ({ data }) => {
if (data.type === 'handle') video.srcObject = data.handle;
};
console.log('MSE läuft im Worker');
} else {
// Rückfall: klassisches MSE im Haupt-Thread
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
console.log('MSE läuft im Haupt-Thread');
}
// Wichtig · Fallstricke
- Browser-Unterstützung: Chromium-Browser ab Version 108 unterstützen die Schnittstelle. In anderen Browsern fehlt sie teilweise oder ganz. Deshalb vorher immer
MediaSource.canConstructInDedicatedWorkerprüfen und einen Rückfall auf den Haupt-Thread vorsehen. - Nur dedizierte Worker: In Shared Workern und Service Workern kann man
MediaSourcenicht erzeugen. - Übertragen statt kopieren: Das Handle muss in der Transfer-Liste von
postMessage()stehen. Ohne diese Liste wirft der Aufruf einenDataCloneError. Ein Handle lässt sich nur einmal übertragen. Nach der Übertragung ist es im Worker nicht mehr nutzbar, und eine zweite Übertragung schlägt fehl. srcObjectstattsrc: Im Worker erzeugtURL.createObjectURL()keine Wiedergabe-URL für eineMediaSource. Im Haupt-Thread muss man das Handlevideo.srcObjectzuweisen.- Das Handle lässt sich nur an ein einziges Medienelement binden. Die
MediaSourceselbst und ihreSourceBuffer-Objekte bleiben im Worker. Man steuert sie also dort, zum Beispiel fürappendBuffer(),endOfStream()oderduration. - Ereignisse des Medienelements wie
seekingodertimeupdatekommen im Haupt-Thread an. Wenn der Worker darauf reagieren soll, muss man sie ihm selbst perpostMessage()weiterleiten.