Signatur
Beschreibung
Das Ereignis sourceopen gehört zur Media Source Extensions API (MSE). Es wird ausgelöst, sobald ein MediaSource-Objekt an ein Medienelement (<video> oder <audio>) angehängt wurde und sein readyState von "closed" bzw. "ended" auf "open" wechselt. Das passiert typischerweise, nachdem man video.src = URL.createObjectURL(mediaSource) gesetzt hat, oder erneut, wenn nach endOfStream() wieder Daten angehängt werden.
Erst nach diesem Ereignis darf man mit MediaSource.addSourceBuffer() einen SourceBuffer anlegen und Mediensegmente per appendBuffer() einspeisen. Ein Aufruf von addSourceBuffer() vor dem Öffnen führt zu einer InvalidStateError-Ausnahme. sourceopen ist daher der Einstiegspunkt jeder eigenen Streaming-Logik, etwa für adaptives Streaming (DASH/HLS-Player), Live-Streams oder das stückweise Nachladen großer Videodateien.
Den Handler registriert man entweder mit addEventListener("sourceopen", handler) oder über die Eigenschaft onsourceopen. Das Ereignis ist ein einfaches Event ohne zusätzliche Eigenschaften; es bubbelt nicht und ist nicht abbrechbar.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "sourceopen". |
|
| $handler Pflicht | (event: Event) => void | Callback, das ein einfaches Event erhält. event.target ist das auslösende MediaSource-Objekt. |
|
| $options | boolean|AddEventListenerOptions | false | Optionen wie { once: true } – sinnvoll, da die Initialisierung meist nur einmal erfolgen soll. |
Rückgabewert
addEventListener() gibt undefined zurück. Der Handler erhält ein Event-Objekt.Beispiele
Video-Datei stückweise über MSE abspielen
const video = document.querySelector('video');
const mimeCodec = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
const mediaSource = new MediaSource();
mediaSource.addEventListener('sourceopen', async () => {
console.log('readyState:', mediaSource.readyState);
const sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
const response = await fetch('/media/fragmentiert.mp4');
const data = await response.arrayBuffer();
sourceBuffer.addEventListener('updateend', () => {
mediaSource.endOfStream();
video.play();
}, { once: true });
sourceBuffer.appendBuffer(data);
}, { once: true });
video.src = URL.createObjectURL(mediaSource);
} else {
console.error('Codec oder MSE nicht unterstützt');
}
Handler über die onsourceopen-Eigenschaft und Aufräumen der Objekt-URL
const video = document.querySelector('video');
const mediaSource = new MediaSource();
const url = URL.createObjectURL(mediaSource);
mediaSource.onsourceopen = (event) => {
// Objekt-URL wird nach dem Anhängen nicht mehr benötigt
URL.revokeObjectURL(url);
console.log(event.type, event.target === mediaSource);
// Handler entfernen, damit ein späteres erneutes Öffnen nichts doppelt anlegt
mediaSource.onsourceopen = null;
};
video.src = url;
Segmente nacheinander anhängen (einfacher Segment-Loader)
const video = document.querySelector('video');
const mediaSource = new MediaSource();
const segments = ['/seg/init.mp4', '/seg/1.m4s', '/seg/2.m4s', '/seg/3.m4s'];
const waitForUpdate = (sb) =>
new Promise((resolve) => sb.addEventListener('updateend', resolve, { once: true }));
const onOpen = async () => {
mediaSource.removeEventListener('sourceopen', onOpen);
const sb = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.64001f"');
for (const url of segments) {
const chunk = await (await fetch(url)).arrayBuffer();
sb.appendBuffer(chunk);
await waitForUpdate(sb);
console.log('angehängt:', url);
}
mediaSource.endOfStream();
};
mediaSource.addEventListener('sourceopen', onOpen);
video.src = URL.createObjectURL(mediaSource);
// Wichtig · Fallstricke
- Reihenfolge beachten: Den Listener vor dem Setzen von
video.srcregistrieren. Das Ereignis wird zwar asynchron ausgelöst, sauberer und robuster ist diese Reihenfolge aber trotzdem. addSourceBuffer()vorsourceopenwirftInvalidStateError. AuchappendBuffer()darf erst aufgerufen werden, wennsourceBuffer.updatingden Wertfalsehat – sonst folgt ebenfallsInvalidStateError.sourceopenkann mehrfach feuern: NachendOfStream()(Zustand"ended") setzt ein erneutesappendBuffer()den Zustand wieder auf"open". Einmalige Initialisierung deshalb mit{ once: true }absichern.- Gegenstücke:
sourceended(Zustand"ended") undsourceclose(Objekt vom Medienelement getrennt). - Kompatibilität: In allen Desktop-Browsern und Android verfügbar. iOS Safari auf dem iPhone unterstützt klassisches
MediaSourcenicht; ab iOS 17.1 gibt esManagedMediaSourcemit demselben Ereignis. Vorher mit'MediaSource' in windowundMediaSource.isTypeSupported()prüfen. - In Dedicated Workers (Chrome 108+) kann
MediaSourceebenfalls genutzt werden; dort wird derMediaSourceHandlestatt einer Objekt-URL übergeben.