Signatur
Beschreibung
Die Eigenschaft appendWindowStart eines SourceBuffer legt zusammen mit appendWindowEnd das Anhangsfenster fest. Das ist ein Zeitbereich der Präsentation, in dem neu angehängte Mediendaten übernommen werden. Codierte Frames, deren Präsentationszeitstempel vor appendWindowStart liegt, verwirft der Browser beim Parsen von Daten aus appendBuffer(). Sie landen dann nicht im Puffer.
Die Eigenschaft ist eine Gleitkommazahl in Sekunden und hat den Standardwert 0. Du brauchst sie vor allem für drei Aufgaben:
- Segmente zuschneiden: Nur einen Ausschnitt eines Mediensegments übernehmen, zum Beispiel für Vorschauen oder Clips.
- Nahtloses Aneinanderfügen (Splicing): Werbung oder Kapitel zusammensetzen, ohne dass sich die Bereiche überschneiden.
- Überlappende Segmente beim adaptiven Streaming (etwa beim Wechsel der Qualitätsstufe) sauber abgrenzen.
Das Fenster wirkt nur auf Daten, die du danach anhängst. Bereits gepufferte Daten bleiben unverändert. Um sie zu entfernen, rufst du SourceBuffer.remove() auf. Setze die Eigenschaft außerdem nur, wenn updating den Wert false hat, also nicht während eines laufenden Anhänge- oder Entfernvorgangs.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $value Pflicht | number | 0 | Neuer Startzeitpunkt in Sekunden (beim Setzen). Er muss >= 0 und kleiner als appendWindowEnd sein. |
Rückgabewert
0.Beispiele
Wert auslesen und setzen
const video = document.querySelector('video');
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', () => {
const sb = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
console.log(sb.appendWindowStart); // Standardwert
sb.appendWindowStart = 5; // alles vor 5 s verwerfen
console.log(sb.appendWindowStart);
});
Nur einen Ausschnitt (10–20 s) eines Segments übernehmen
const appendClip = async (sb, url, start, end) => {
const data = await (await fetch(url)).arrayBuffer();
// Zuerst das Ende setzen, damit start < end immer gilt
sb.appendWindowEnd = end;
sb.appendWindowStart = start;
await new Promise((resolve, reject) => {
sb.addEventListener('updateend', resolve, { once: true });
sb.addEventListener('error', reject, { once: true });
sb.appendBuffer(data);
});
const { buffered } = sb;
console.log(`Gepuffert: ${buffered.start(0).toFixed(1)}–${buffered.end(0).toFixed(1)} s`);
};
// Aufruf im sourceopen-Handler:
// await appendClip(sourceBuffer, '/media/film.mp4', 10, 20);
Fenster nur setzen, wenn der SourceBuffer bereit ist
const setWindowStart = async (sb, seconds) => {
if (sb.updating) {
// Auf das Ende des laufenden Vorgangs warten
await new Promise((r) => sb.addEventListener('updateend', r, { once: true }));
}
try {
sb.appendWindowStart = seconds;
} catch (err) {
// InvalidAccessError: negativ oder >= appendWindowEnd
// InvalidStateError: SourceBuffer wurde entfernt
console.error(err.name, err.message);
}
};
// Beispiel: ungültiger Wert
// await setWindowStart(sourceBuffer, -1);
// Wichtig · Fallstricke
- Ausnahmen beim Setzen: Ein
TypeErrorbzw.InvalidAccessErrortritt auf, wenn der Wert negativ ist oder größer oder gleichappendWindowEnd. EinInvalidStateErrortritt auf, wenn derSourceBufferausMediaSource.sourceBuffersentfernt wurde oderupdatingden Werttruehat. - Reihenfolge beachten: Wenn du das Fenster nach hinten verschiebst, setze zuerst
appendWindowEndund danachappendWindowStart. Sonst kann die Bedingungstart < endkurzzeitig verletzt sein und eine Ausnahme auslösen. - Keyframes bei Video: Wird ein Frame vor dem Fensterstart verworfen, braucht der Browser für die folgenden Frames wieder einen Keyframe (Random Access Point). Abhängige Frames dazwischen fallen deshalb ebenfalls weg. Der gepufferte Bereich beginnt dann oft erst nach
appendWindowStart. Audio schneiden Browser teilweise genauer zu. - Die Eigenschaft wirkt nicht rückwirkend auf bereits gepufferte Daten. Dafür ist
remove(start, end)da. - Kompatibilität: Media Source Extensions werden von allen modernen Desktop-Browsern unterstützt. Auf dem iPhone gibt es MSE erst ab iOS 17.1, und zwar nur über
ManagedMediaSource. Prüfe die Unterstützung vorher mitMediaSource.isTypeSupported().