Signatur
Beschreibung
changeType() gehört zu den Media Source Extensions (MSE). Damit kann ein bestehender SourceBuffer mitten in der Wiedergabe auf ein anderes Containerformat oder einen anderen Codec umgestellt werden, etwa von H.264 in MP4 auf VP9 in WebM oder von AAC auf Opus. Ohne diese Methode müsste man die MediaSource neu aufbauen, und die Wiedergabe würde abreißen.
Typische Einsatzfälle sind adaptives Streaming (DASH/HLS-Player, die zwischen Darstellungen mit unterschiedlichen Codecs wechseln), das Einfügen von Werbung in einem anderen Format und Playlists mit gemischten Quellen. Nach dem Aufruf muss das nächste angehängte Segment ein Initialisierungssegment im neuen Format sein. Erst danach folgen die Mediensegmente.
Die Methode läuft synchron. Vorher darf der Puffer nicht gerade aktualisiert werden (updating === false), und der Typ sollte mit MediaSource.isTypeSupported() geprüft werden. Bereits gepufferte Daten bleiben erhalten. Wie der Übergang an den Segmentgrenzen aussieht, hängt vom mode ("segments" oder "sequence") und vom timestampOffset ab.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | MIME-Typ mit Codec-Angabe für die künftigen Daten, z. B. 'video/webm; codecs="vp9"' oder 'video/mp4; codecs="avc1.64001F"'. Leere Zeichenkette ist nicht erlaubt. |
Rückgabewert
undefined).Beispiele
Codec-Wechsel von MP4/H.264 auf WebM/VP9
const video = document.querySelector('video');
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
// Wartet, bis der SourceBuffer mit dem aktuellen Update fertig ist
const waitForUpdate = (sb) =>
new Promise((resolve) => sb.addEventListener('updateend', resolve, { once: true }));
const fetchSegment = async (url) => (await fetch(url)).arrayBuffer();
mediaSource.addEventListener('sourceopen', async () => {
const mp4Type = 'video/mp4; codecs="avc1.42E01E"';
const webmType = 'video/webm; codecs="vp9"';
const sb = mediaSource.addSourceBuffer(mp4Type);
sb.mode = 'sequence'; // Zeitstempel nahtlos fortsetzen
// Erster Teil: MP4
sb.appendBuffer(await fetchSegment('/media/intro-init.mp4'));
await waitForUpdate(sb);
sb.appendBuffer(await fetchSegment('/media/intro-1.m4s'));
await waitForUpdate(sb);
// Wechsel auf WebM/VP9
if (MediaSource.isTypeSupported(webmType)) {
sb.changeType(webmType);
// Zuerst muss das Initialisierungssegment des neuen Formats kommen
sb.appendBuffer(await fetchSegment('/media/main-init.webm'));
await waitForUpdate(sb);
sb.appendBuffer(await fetchSegment('/media/main-1.webm'));
await waitForUpdate(sb);
}
mediaSource.endOfStream();
});
Sicherer Wechsel mit Feature-Erkennung und Fehlerbehandlung
const switchCodec = async (sourceBuffer, newType) => {
if (typeof sourceBuffer.changeType !== 'function') {
throw new Error('changeType() wird nicht unterstützt');
}
if (!MediaSource.isTypeSupported(newType)) {
throw new Error(`Typ nicht unterstützt: ${newType}`);
}
// Laufendes Update abwarten, sonst InvalidStateError
if (sourceBuffer.updating) {
await new Promise((r) => sourceBuffer.addEventListener('updateend', r, { once: true }));
}
try {
sourceBuffer.changeType(newType);
console.log(`Gewechselt auf ${newType}`);
} catch (err) {
console.error(err.name, err.message);
}
};
// Aufruf, z. B. im DASH-Player bei einem Wechsel der Darstellung
// await switchCodec(videoBuffer, 'video/mp4; codecs="av01.0.05M.08"');
Audio-Wechsel von AAC auf Opus
const audioBuffer = mediaSource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"');
// ... AAC-Segmente anhängen ...
audioBuffer.addEventListener('updateend', function onDone() {
audioBuffer.removeEventListener('updateend', onDone);
audioBuffer.changeType('audio/webm; codecs="opus"');
console.log('Audio-Puffer erwartet jetzt Opus');
});
// Wichtig · Fallstricke
- Ausnahmen:
TypeErrorbei leeremtype.InvalidStateError, wenn derSourceBufferschon aussourceBuffersentfernt wurde oderupdatinggeradetrueist.NotSupportedError, wenn der Browser den Typ nicht unterstützt. - Ist die
MediaSourceim Zustand"ended", setzt der Aufruf sie wieder auf"open"und löstsourceopenaus. - Nach
changeType()muss als Erstes ein Initialisierungssegment im neuen Format angehängt werden. Kommen gleich Mediensegmente, gibt es einen Dekodierfehler und dieMediaSourcewird mit"decode"-Fehler beendet. - Bei Formaten, die Zeitstempel erzeugen müssen (z. B.
audio/mpeg,audio/aac), wirdmodeautomatisch auf"sequence"gesetzt. - Kompatibilität: Läuft in allen aktuellen Desktop-Browsern. Auf iOS-iPhones gibt es MSE erst ab iOS 17.1 über
ManagedMediaSource. Vorher per Feature-Erkennung ('changeType' in SourceBuffer.prototype) prüfen und im Zweifel dieMediaSourceneu anlegen. - Nahtlose Übergänge zwischen Codecs hängen vom Browser ab. Kurze Ruckler an der Wechselstelle kommen vor.