Start · Sprachen · JavaScript · Referenz · SourceBuffer.buffered

SourceBuffer.buffered

Eigenschaft

Liefert als normalisiertes <code>TimeRanges</code>-Objekt die Zeitbereiche, die gerade im <code>SourceBuffer</code> gepuffert sind. Die Eigenschaft ist schreibgeschützt.

seit JavaScript Media Source Extensions – Baseline: alle modernen Kategorie: webapi

Signatur

get SourceBuffer.buffered

Beschreibung

Die schreibgeschützte Eigenschaft buffered eines SourceBuffer sagt dir, welche Abschnitte der Medien-Zeitachse (in Sekunden) in diesem Puffer liegen und abgespielt werden können. Du bekommst ein TimeRanges-Objekt zurück. Es ist normalisiert: Die Bereiche sind aufsteigend sortiert, überlappen sich nicht und grenzen nicht direkt aneinander. Mit length, start(i) und end(i) liest du die einzelnen Bereiche aus.

Eigene Streaming-Player auf Basis der Media Source Extensions (MSE) nutzen diese Eigenschaft ständig, zum Beispiel für adaptives Streaming wie DASH oder HLS. Typische Aufgaben:

  • Den Puffervorlauf vor der aktuellen Abspielposition messen, um zu entscheiden, ob das nächste Segment geladen werden muss.
  • Alte Bereiche finden, die man mit SourceBuffer.remove() freigeben kann, um Speicher zu sparen und einen QuotaExceededError zu vermeiden.
  • Lücken im Puffer erkennen, etwa nach einem Sprung (Seek) oder bei fehlerhaften Segmenten.

Achtung: Diese Bereiche gelten nur für diesen einen SourceBuffer. Wenn Audio und Video in getrennten Puffern liegen, kann das Medienelement nur dort abspielen, wo sich die Bereiche beider Puffer überschneiden. Diese Schnittmenge liefert HTMLMediaElement.buffered bzw. MediaSource automatisch.

Rückgabewert

Typ
TimeRanges
Beschreibung
Ein normalisiertes TimeRanges-Objekt mit den gepufferten Bereichen in Sekunden. Es ist leer (length === 0), wenn noch nichts angehängt wurde.

Beispiele

Alle gepufferten Bereiche ausgeben

const video = document.querySelector('video');
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);

mediaSource.addEventListener('sourceopen', async () => {
  const mime = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
  const sb = mediaSource.addSourceBuffer(mime);

  const data = await (await fetch('/media/segment-0.mp4')).arrayBuffer();
  sb.appendBuffer(data);

  sb.addEventListener('updateend', () => {
    const ranges = sb.buffered;
    for (let i = 0; i < ranges.length; i++) {
      console.log(`Bereich ${i}: ${ranges.start(i).toFixed(2)}s – ${ranges.end(i).toFixed(2)}s`);
    }
  }, { once: true });
});
Bereich 0: 0.00s – 4.00s

Puffervorlauf vor der Abspielposition berechnen

// Gibt zurück, wie viele Sekunden ab currentTime lückenlos gepuffert sind
const bufferAhead = (sourceBuffer, currentTime) => {
  const ranges = sourceBuffer.buffered;
  for (let i = 0; i < ranges.length; i++) {
    if (currentTime >= ranges.start(i) && currentTime <= ranges.end(i)) {
      return ranges.end(i) - currentTime;
    }
  }
  return 0; // currentTime liegt in einer Lücke
};

// Im Player-Loop: nächstes Segment nur laden, wenn weniger als 10 s gepuffert sind
const checkBuffer = () => {
  const ahead = bufferAhead(sb, video.currentTime);
  console.log(`Vorlauf: ${ahead.toFixed(1)} s`);
  if (ahead < 10 && !sb.updating) {
    loadNextSegment();
  }
};
video.addEventListener('timeupdate', checkBuffer);
Vorlauf: 7.3 s

Alten Puffer freigeben, um Speicher zu sparen

// Alles entfernen, was mehr als 30 s hinter der Abspielposition liegt
const evictOldData = (sb, currentTime, keepBehind = 30) => {
  if (sb.updating || sb.buffered.length === 0) return;
  const start = sb.buffered.start(0);
  const removeEnd = currentTime - keepBehind;
  if (removeEnd > start) {
    sb.remove(start, removeEnd);
    console.log(`Entferne ${start.toFixed(1)}s – ${removeEnd.toFixed(1)}s`);
  }
};

evictOldData(sb, video.currentTime);
Entferne 0.0s – 42.5s

// Wichtig · Fallstricke

  • Nur eine Momentaufnahme: Das zurückgegebene TimeRanges-Objekt aktualisiert sich nicht selbst. Lies buffered deshalb nach jedem updateend oder Sprung (Seek) neu aus.
  • Ausnahme: Wurde der SourceBuffer schon aus seiner MediaSource entfernt (removeSourceBuffer()), wirft der Zugriff einen InvalidStateError.
  • Während updating === true kann der Wert noch den alten Stand zeigen. Werte ihn am besten erst im updateend-Ereignis aus.
  • Kleine Lücken: Zeitstempel von Segmenten passen oft nicht exakt zueinander. Dann entstehen Mini-Lücken von wenigen Millisekunden, und die Wiedergabe kann hängen bleiben. Viele Player überspringen solche Lücken mit einer Toleranz, z. B. 0,1 s.
  • Getrennte Puffer: Bei getrennten Audio- und Video-Puffern zählt für die Wiedergabe die Schnittmenge. Diese liefert HTMLMediaElement.buffered.
  • Kompatibilität: MSE wird in allen modernen Desktop-Browsern unterstützt. Auf dem iPhone ist MSE erst ab iOS 17.1 als ManagedMediaSource verfügbar. Prüfe die Unterstützung vorher, z. B. mit 'MediaSource' in window und MediaSource.isTypeSupported().