Signatur
Beschreibung
flush() weist den VideoEncoder an, alle Frames in seiner internen Warteschlange, die bereits per encode() übergeben wurden, fertig zu kodieren. Die dabei entstehenden EncodedVideoChunk-Objekte gehen an den output-Callback, den du im Konstruktor festgelegt hast. Das zurückgegebene Promise wird erst erfüllt, wenn der letzte Chunk ausgegeben wurde.
Brauchen wirst du die Methode vor allem am Ende einer Aufnahme oder eines Exports, zum Beispiel bevor du eine MP4- oder WebM-Datei muxt und abschließt. Ohne flush() bleiben Frames, die der Encoder intern puffert (etwa wegen B-Frames oder Lookahead), möglicherweise ohne Ausgabe. Du kannst die Methode auch mitten im Ablauf aufrufen, um einen festen Synchronisationspunkt zu bekommen.
Der Encoder muss im Zustand "configured" sein. Nach einem erfolgreichen flush() bleibt er konfiguriert und kann weitere Frames annehmen. Häufiges Flushen kann aber die Kompressionseffizienz verschlechtern, weil der Encoder dann Keyframes erzeugen oder seinen internen Zustand zurücksetzen muss.
Rückgabewert
undefined erfüllt wird, sobald alle ausstehenden Kodiervorgänge abgeschlossen und ihre Chunks an den output-Callback übergeben wurden. Es wird mit einer InvalidStateError-DOMException abgelehnt, wenn der Encoder nicht konfiguriert ist, und mit einer AbortError-DOMException, wenn vorher reset() oder close() aufgerufen wird.Beispiele
Frames kodieren und am Ende flushen
const chunks = [];
const encoder = new VideoEncoder({
output: (chunk) => chunks.push(chunk),
error: (e) => console.error('Encoder-Fehler:', e)
});
encoder.configure({
codec: 'vp8',
width: 640,
height: 480,
bitrate: 1_000_000,
framerate: 30
});
const canvas = new OffscreenCanvas(640, 480);
const ctx = canvas.getContext('2d');
for (let i = 0; i < 60; i++) {
ctx.fillStyle = `hsl(${i * 6}, 80%, 50%)`;
ctx.fillRect(0, 0, 640, 480);
const frame = new VideoFrame(canvas, { timestamp: i * 33_333 });
encoder.encode(frame, { keyFrame: i % 30 === 0 });
frame.close(); // Speicher sofort freigeben
}
await encoder.flush();
console.log(`Fertig: ${chunks.length} Chunks`);
encoder.close();
Aufnahme einer Kamera sauber beenden
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const [track] = stream.getVideoTracks();
const reader = new MediaStreamTrackProcessor({ track }).readable.getReader();
const encoder = new VideoEncoder({
output: (chunk, meta) => muxer.addVideoChunk(chunk, meta), // z. B. mp4-muxer
error: console.error
});
encoder.configure({ codec: 'avc1.42001f', width: 1280, height: 720 });
let recording = true;
setTimeout(() => { recording = false; }, 5000);
while (recording) {
const { value: frame, done } = await reader.read();
if (done) break;
encoder.encode(frame);
frame.close();
}
track.stop();
await encoder.flush(); // letzte gepufferte Frames ausgeben
muxer.finalize();
encoder.close();
Fehlerbehandlung bei abgebrochenem Flush
const encoder = new VideoEncoder({ output: () => {}, error: console.error });
encoder.configure({ codec: 'vp8', width: 320, height: 240 });
const pending = encoder.flush();
encoder.reset(); // bricht den Flush ab
try {
await pending;
} catch (err) {
console.log(err.name);
}
// Wichtig · Fallstricke
- Zustand prüfen: Wenn
encoder.statenicht"configured"ist (also"unconfigured"oder"closed"), lehntflush()das Promise mitInvalidStateErrorab. - Nicht bei jedem Frame aufrufen: Häufiges Flushen senkt die Kompressionseffizienz und den Durchsatz. Zum Drosseln eignen sich besser
encodeQueueSizeund dasdequeue-Event. - Rufst du
reset()oderclose()auf, während ein Flush läuft, wird dessen Promise mitAbortErrorabgelehnt. VideoFrame-Objekte nachencode()immer mitclose()freigeben.flush()erledigt das nicht.- Die WebCodecs API funktioniert nur in sicheren Kontexten (HTTPS) und steht auch in Dedicated Workers zur Verfügung. Firefox unterstützt sie erst seit Version 130, Safari hat anfangs nur eine eingeschränkte Codec-Auswahl. Prüfe die Codecs vorher mit
VideoEncoder.isConfigSupported().