Start · Sprachen · JavaScript · Referenz · ManagedMediaSource

ManagedMediaSource

Schnittstelle

Eine <code>MediaSource</code>-Variante, bei der der Browser Pufferspeicher selbst verwaltet und per Ereignis meldet, wann neue Mediendaten nachgeladen werden sollen.

seit JavaScript Safari 17 (macOS/iPadOS), Safari 17.1 (iOS); nicht Kategorie: webapi

Signatur

interface ManagedMediaSource extends MediaSource

Beschreibung

ManagedMediaSource erweitert MediaSource aus der Media Source Extensions API (MSE). Der Unterschied: Bei einer normalen MediaSource entscheidet allein die Anwendung, wann Segmente mit SourceBuffer.appendBuffer() angehängt oder mit remove() entfernt werden. Bei ManagedMediaSource darf der Browser selbst gepufferte Daten verwerfen, z. B. bei Speicherknappheit, und sagt der Anwendung über Ereignisse, wann sich das Nachladen lohnt.

Das ist vor allem für Mobilgeräte gedacht. Der Browser kann das Nachladen auf Zeiten legen, in denen das Funkmodul ohnehin aktiv ist (z. B. schnelles 5G, WLAN). Das spart Akku und Datenvolumen. Apple hat die Schnittstelle eingeführt, damit MSE-basierte Player (hls.js, dash.js, Shaka Player) auch auf dem iPhone laufen. Dort gibt es die klassische MediaSource nicht.

Zusätzlich zu den geerbten Mitgliedern gibt es:

  • streaming (schreibgeschützt, boolean): true, solange die Anwendung neue Daten anhängen soll.
  • startstreaming-Ereignis: Jetzt sollen Daten geladen werden.
  • endstreaming-Ereignis: Das Laden soll vorerst stoppen.
  • Die sourceBuffers sind vom Typ ManagedSourceBuffer. Dieser feuert bufferedchange, wenn der Browser gepufferte Bereiche entfernt hat.

Die Einrichtung läuft wie bei MSE: Instanz erzeugen, per URL.createObjectURL() (oder srcObject) an ein <video> binden, auf sourceopen warten und dann addSourceBuffer() aufrufen. Unterstützte Formate prüft man mit der statischen Methode ManagedMediaSource.isTypeSupported().

Parameter

Name Typ Default Beschreibung
$(Konstruktor) new ManagedMediaSource() — Der Konstruktor nimmt keine Parameter. Er erzeugt eine neue Instanz mit readyState "closed".

Rückgabewert

Typ
ManagedMediaSource
Beschreibung
new ManagedMediaSource() liefert eine neue Instanz. Sie wird über eine Objekt-URL oder srcObject an ein Medienelement gebunden.

Beispiele

Feature-Erkennung und Einrichtung mit Rückfall auf MediaSource

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

// ManagedMediaSource bevorzugen, sonst klassische MediaSource
const MS = window.ManagedMediaSource ?? window.MediaSource;
if (!MS || !MS.isTypeSupported(mime)) {
  throw new Error('MSE bzw. Codec wird nicht unterstützt');
}

const mediaSource = new MS();

// Pflicht bei ManagedMediaSource in Safari (sonst AirPlay-Alternative nötig)
video.disableRemotePlayback = true;
video.src = URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen', () => {
  URL.revokeObjectURL(video.src);
  const sourceBuffer = mediaSource.addSourceBuffer(mime);
  console.log('Typ:', mediaSource.constructor.name);
  console.log('readyState:', mediaSource.readyState);
}, { once: true });
Typ: ManagedMediaSource readyState: open

Laden über startstreaming/endstreaming steuern

const video = document.querySelector('video');
const mime = 'video/mp4; codecs="avc1.64001f"';
const segmentUrls = ['/seg/init.mp4', '/seg/1.m4s', '/seg/2.m4s', '/seg/3.m4s'];
let next = 0;

const ms = new ManagedMediaSource();
video.disableRemotePlayback = true;
video.src = URL.createObjectURL(ms);

const appendOnce = (sb, data) => new Promise((resolve, reject) => {
  sb.addEventListener('updateend', resolve, { once: true });
  sb.addEventListener('error', reject, { once: true });
  sb.appendBuffer(data);
});

const loadWhileStreaming = async (sb) => {
  // Nur laden, solange der Browser es erlaubt
  while (ms.streaming && next < segmentUrls.length) {
    const res = await fetch(segmentUrls[next++]);
    await appendOnce(sb, await res.arrayBuffer());
  }
  if (next >= segmentUrls.length && ms.readyState === 'open') {
    ms.endOfStream();
  }
};

ms.addEventListener('sourceopen', () => {
  const sb = ms.addSourceBuffer(mime);
  ms.addEventListener('startstreaming', () => {
    console.log('startstreaming – lade Segmente');
    loadWhileStreaming(sb);
  });
  ms.addEventListener('endstreaming', () => {
    console.log('endstreaming – pausiere Laden');
  });
  // Falls streaming bereits aktiv ist
  if (ms.streaming) loadWhileStreaming(sb);
}, { once: true });
startstreaming – lade Segmente endstreaming – pausiere Laden

Vom Browser entfernte Pufferbereiche erkennen (bufferedchange)

const ms = new ManagedMediaSource();
const video = document.querySelector('video');
video.disableRemotePlayback = true;
video.src = URL.createObjectURL(ms);

ms.addEventListener('sourceopen', () => {
  const sb = ms.addSourceBuffer('video/mp4; codecs="avc1.64001f"');

  // ManagedSourceBuffer meldet Änderungen, auch wenn der Browser Daten verwirft
  sb.addEventListener('bufferedchange', (event) => {
    for (let i = 0; i < event.removedRanges.length; i++) {
      const start = event.removedRanges.start(i).toFixed(1);
      const end = event.removedRanges.end(i).toFixed(1);
      console.log(`Entfernt: ${start}s – ${end}s`);
    }
    // Hier z. B. den eigenen Segment-Index aktualisieren,
    // damit entfernte Segmente bei Bedarf neu geladen werden.
  });
}, { once: true });
Entfernt: 0.0s – 12.0s