Signatur
Beschreibung
Der Konstruktor VideoDecoder() gehört zur WebCodecs API und erzeugt einen Decoder mit Low-Level-Zugriff auf die Video-Codecs des Browsers (H.264/AVC, H.265/HEVC, VP8, VP9, AV1). Anders als beim <video>-Element steuerst du selbst, welche kodierten Daten (EncodedVideoChunk) wann dekodiert werden, und bekommst jedes Bild als VideoFrame zurück.
Nach dem Konstruktor-Aufruf ist der Decoder im Zustand "unconfigured". Bevor du mit decode() dekodieren kannst, musst du configure() mit einer passenden Codec-Konfiguration aufrufen. Die Ausgabe läuft asynchron: Jeder fertig dekodierte Frame wird an den output-Callback übergeben, jeder schwere Fehler an den error-Callback. Danach wechselt der Decoder in den Zustand "closed".
Typische Einsatzfälle sind eigene Videoplayer (z. B. mit WebTransport oder WebSocket als Transportweg), Cloud-Gaming, Videobearbeitung im Browser, Frame-genaues Scrubbing sowie das Weiterverarbeiten einzelner Frames in Canvas, WebGL oder WebGPU. Der Decoder funktioniert auch in Dedicated Workern. Das ist empfehlenswert, damit der Haupt-Thread entlastet wird.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $init Pflicht | Object | Initialisierungsobjekt mit den beiden Pflicht-Callbacks output und error. |
|
| $init.output Pflicht | (frame: VideoFrame) => void | Wird für jeden dekodierten Frame mit einem VideoFrame aufgerufen. Wenn du den Frame nicht mehr brauchst, musst du frame.close() aufrufen. |
|
| $init.error Pflicht | (error: DOMException) => void | Wird bei einem schweren Fehler aufgerufen, z. B. EncodingError bei beschädigten Daten oder NotSupportedError bei einer nicht unterstützten Konfiguration. Danach ist der Decoder geschlossen. |
Rückgabewert
VideoDecoder-Instanz im Zustand "unconfigured".Beispiele
Decoder erzeugen und konfigurieren
const decoder = new VideoDecoder({
output: (frame) => {
console.log(`Frame: ${frame.codedWidth}x${frame.codedHeight} @ ${frame.timestamp}µs`);
frame.close(); // Speicher sofort freigeben
},
error: (e) => console.error('Decoder-Fehler:', e.name, e.message),
});
console.log(decoder.state);
decoder.configure({
codec: 'vp8',
codedWidth: 640,
codedHeight: 480,
});
console.log(decoder.state);
Unterstützung prüfen und Frames auf ein Canvas zeichnen
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const config = {
codec: 'avc1.42E01E', // H.264 Baseline
codedWidth: 1280,
codedHeight: 720,
hardwareAcceleration: 'prefer-hardware',
};
const setupDecoder = async () => {
if (!('VideoDecoder' in window)) {
throw new Error('WebCodecs wird nicht unterstützt');
}
const { supported } = await VideoDecoder.isConfigSupported(config);
if (!supported) throw new Error(`Codec ${config.codec} nicht unterstützt`);
const decoder = new VideoDecoder({
output: (frame) => {
ctx.drawImage(frame, 0, 0, canvas.width, canvas.height);
frame.close();
},
error: (e) => console.error(e),
});
decoder.configure(config);
return decoder;
};
const decoder = await setupDecoder();
console.log('Bereit:', decoder.state);
Kodierte Chunks dekodieren und am Ende leeren
// chunks: Array aus { data: ArrayBuffer, timestamp: number, key: boolean },
// z. B. aus einem MP4-Demuxer wie mp4box.js
const decodeAll = async (chunks, config) => {
let count = 0;
const decoder = new VideoDecoder({
output: (frame) => { count++; frame.close(); },
error: (e) => console.error('Abbruch:', e),
});
decoder.configure(config);
for (const c of chunks) {
// Staudruck begrenzen: nicht zu viele Chunks in die Warteschlange
while (decoder.decodeQueueSize > 10) {
await new Promise((r) => decoder.addEventListener('dequeue', r, { once: true }));
}
decoder.decode(new EncodedVideoChunk({
type: c.key ? 'key' : 'delta',
timestamp: c.timestamp,
data: c.data,
}));
}
await decoder.flush(); // wartet, bis alle Frames ausgegeben wurden
decoder.close();
console.log(`${count} Frames dekodiert`);
};
// Wichtig · Fallstricke
- Beide Callbacks sind Pflicht: Fehlt
outputodererroroder ist einer davon keine Funktion, wirft der Konstruktor einenTypeError. frame.close()nicht vergessen:VideoFrame-Objekte belegen oft GPU- oder Hardware-Puffer. Werden sie nicht geschlossen, kann der Decoder ins Stocken geraten, weil sein Frame-Pool erschöpft ist, und es gibt Speicherlecks.- Der erste Chunk muss ein Keyframe sein (
type: 'key'), auch nachconfigure()oderreset(). Sonst wird einDataErrorgeworfen. - Bei H.264/HEVC im AVC-Format (MP4) musst du in
configure()dasdescription-Feld (avcC-Box) mitgeben. Ohne dieses Feld erwartet der Decoder Annex-B-Daten. - Prüfe die Konfiguration vorher mit
VideoDecoder.isConfigSupported(). Welche Codecs verfügbar sind, hängt von Browser, Betriebssystem und Hardware ab. - Kompatibilität: Nur in sicheren Kontexten (HTTPS) verfügbar, im Window und in Dedicated Workern. Chromium-Browser ab 94, Safari ab 16.4 (nur Video), Firefox ab 130. Vorher per Feature-Erkennung prüfen (
'VideoDecoder' in globalThis). - Die WebCodecs API enthält keinen Demuxer. Container wie MP4 oder WebM musst du selbst oder mit einer Bibliothek zerlegen.