Start · Sprachen · JavaScript · Referenz · new MediaSource()

new MediaSource()

Methode

Erzeugt ein neues, leeres <code>MediaSource</code>-Objekt ohne <code>SourceBuffer</code>, das als Medienquelle an ein <code>&lt;video&gt;</code>- oder <code>&lt;audio&gt;</code>-Element gebunden werden kann.

seit JavaScript Media Source Extensions; Safari auf dem iPhone ers Kategorie: webapi

Signatur

new MediaSource()

Beschreibung

Der Konstruktor MediaSource() gehört zu den Media Source Extensions (MSE). Er erzeugt ein neues MediaSource-Objekt ohne Quellpuffer. Mit diesem Objekt kannst du Mediendaten selbst in ein HTMLMediaElement einspeisen, statt einfach eine Datei-URL in src einzutragen. Darauf bauen adaptives Streaming (DASH, HLS über hls.js oder dash.js), Live-Streams und eigene Puffer-Strategien auf.

Nach dem Erzeugen ist readyState gleich "closed". Erst wenn du das Objekt an ein Medienelement bindest, wird es geöffnet. Dafür erzeugst du mit URL.createObjectURL(mediaSource) eine Objekt-URL und weist sie video.src zu. Alternativ setzt du in neueren Browsern video.srcObject auf das Objekt, das mediaSource.handle liefert. Danach wechselt readyState auf "open" und das Ereignis sourceopen wird ausgelöst.

Erst im sourceopen-Handler legst du mit addSourceBuffer(mimeType) einen oder mehrere SourceBuffer an. In diese hängst du dann mit appendBuffer() Mediensegmente an, z. B. fragmentiertes MP4 oder WebM. Wenn alle Daten angehängt sind, schließt endOfStream() den Stream ab.

Prüfe vor dem Erzeugen mit MediaSource.isTypeSupported(), ob der Browser das gewünschte Container- und Codec-Format unterstützt.

Rückgabewert

Typ
MediaSource
Beschreibung
Ein neues MediaSource-Objekt mit readyState === "closed", leerer sourceBuffers-Liste und duration gleich NaN.

Beispiele

MediaSource erzeugen und an ein Video binden

const video = document.querySelector('video');
const mediaSource = new MediaSource();
console.log(mediaSource.readyState);

video.src = URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen', () => {
  console.log(mediaSource.readyState);
  // Objekt-URL wird nicht mehr gebraucht
  URL.revokeObjectURL(video.src);
}, { once: true });
closed open

Fragmentiertes MP4 laden und abspielen

const mime = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
const video = document.querySelector('video');

if (!('MediaSource' in window) || !MediaSource.isTypeSupported(mime)) {
  console.error('MSE oder Codec nicht unterstützt');
} else {
  const mediaSource = new MediaSource();
  video.src = URL.createObjectURL(mediaSource);

  mediaSource.addEventListener('sourceopen', async () => {
    const sourceBuffer = mediaSource.addSourceBuffer(mime);
    const response = await fetch('/media/film-fragmented.mp4');
    const data = await response.arrayBuffer();

    sourceBuffer.addEventListener('updateend', () => {
      if (mediaSource.readyState === 'open') {
        mediaSource.endOfStream();
      }
      video.play();
    }, { once: true });

    sourceBuffer.appendBuffer(data);
  }, { once: true });
}

Segmente nacheinander anhängen (Warteschlange)

const mime = 'video/webm; codecs="vp9, opus"';
const segmente = ['/seg/init.webm', '/seg/1.webm', '/seg/2.webm'];
const video = document.querySelector('video');
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);

const warteAufUpdate = (sb) =>
  new Promise((resolve) => sb.addEventListener('updateend', resolve, { once: true }));

mediaSource.addEventListener('sourceopen', async () => {
  const sb = mediaSource.addSourceBuffer(mime);
  for (const url of segmente) {
    const buf = await (await fetch(url)).arrayBuffer();
    sb.appendBuffer(buf);
    await warteAufUpdate(sb); // nie anhängen, solange sb.updating true ist
  }
  mediaSource.endOfStream();
  console.log('Dauer:', mediaSource.duration);
}, { once: true });
Dauer: 12.5

// Wichtig · Fallstricke

  • Kompatibilität: Chrome, Edge, Firefox und Safari auf dem Desktop unterstützen den Konstruktor seit Langem. Auf dem iPhone gibt es MSE erst ab iOS 17.1, und dort nur als ManagedMediaSource. Prüfe deshalb beide Varianten: window.ManagedMediaSource || window.MediaSource. Wenn beide fehlen, kannst du bei HLS auf natives Abspielen zurückfallen.
  • addSourceBuffer() zu früh aufgerufen: Vor sourceopen wirft der Aufruf einen InvalidStateError.
  • Ein Anhängevorgang nach dem anderen: Solange sourceBuffer.updating den Wert true hat, darfst du nicht erneut appendBuffer() aufrufen, sonst gibt es einen InvalidStateError. Warte auf updateend.
  • Nur fragmentierte Formate: Normale MP4-Dateien mit moov-Atom am Ende funktionieren nicht. Du brauchst fragmentiertes MP4 (fMP4), WebM oder MPEG-TS, sofern der Browser es unterstützt.
  • Speicher: Gib Objekt-URLs mit URL.revokeObjectURL() frei. Entferne bei langen Streams alte Bereiche mit sourceBuffer.remove(), sonst wirft appendBuffer() irgendwann einen QuotaExceededError.
  • Dedicated Worker: Neuere Chromium-Versionen erlauben den Konstruktor auch in einem Worker. Das Objekt wird dann über mediaSource.handle und postMessage() übertragen.