Signatur
Beschreibung
Mit close() gibst du die Referenz eines VideoFrame auf die zugrunde liegenden Bilddaten frei. Diese liegen oft im GPU-Speicher oder in einem begrenzten Puffer-Pool des Decoders bzw. der Kamera. Der Speicher wird erst dann tatsächlich freigegeben, wenn kein anderes VideoFrame mehr auf dieselbe Ressource verweist, etwa ein mit clone() erzeugter Klon.
Die WebCodecs-API arbeitet bewusst mit einer expliziten Ressourcenverwaltung. Auf die Garbage Collection solltest du dich nicht verlassen. Ein VideoDecoder oder ein MediaStreamTrackProcessor hält nur eine begrenzte Zahl von Frames vor. Rufst du close() nicht auf, kann der Decoder ins Stocken geraten, die Kamera liefert keine neuen Bilder mehr, oder der Browser gibt in der Konsole eine Warnung wie „A VideoFrame was garbage collected without being closed“ aus.
Nach dem Aufruf ist der Frame detached: format wird zu null, codedWidth, codedHeight, displayWidth und displayHeight werden zu 0, und timestamp sowie duration sind nicht mehr aussagekräftig. Rufst du danach Methoden wie copyTo(), clone() oder allocationSize() auf, wird eine InvalidStateError-DOMException geworfen. Auch als Quelle für drawImage() oder new VideoFrame() lässt sich ein geschlossener Frame nicht mehr verwenden.
Faustregel: Wer einen Frame erhält, etwa im output-Callback eines Decoders, ist für ihn verantwortlich. Er gibt ihn weiter oder schließt ihn, sobald er ihn nicht mehr braucht. Eine Ausnahme ist VideoEncoder.encode(): Die Methode übernimmt den Frame nicht, du musst ihn danach also trotzdem selbst schließen.
Rückgabewert
undefined). Die Freigabe erfolgt synchron.Beispiele
Dekodierte Frames zeichnen und sofort schließen
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const decoder = new VideoDecoder({
output: (frame) => {
// Frame zeichnen und danach sofort freigeben
ctx.drawImage(frame, 0, 0, canvas.width, canvas.height);
frame.close();
},
error: (e) => console.error('Decoder-Fehler:', e)
});
decoder.configure({ codec: 'vp8', codedWidth: 640, codedHeight: 480 });
// decoder.decode(encodedChunk) ...
Kamerabilder mit MediaStreamTrackProcessor verarbeiten
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const [track] = stream.getVideoTracks();
const processor = new MediaStreamTrackProcessor({ track });
const reader = processor.readable.getReader();
let count = 0;
while (count < 100) {
const { value: frame, done } = await reader.read();
if (done) break;
try {
console.log(`Frame ${count++}: ${frame.displayWidth}x${frame.displayHeight}`);
} finally {
// Ohne close() liefert die Kamera nach wenigen Frames keine neuen Bilder mehr
frame.close();
}
}
track.stop();
Zustand nach close() und Umgang mit clone()
const canvas = new OffscreenCanvas(320, 240);
canvas.getContext('2d').fillRect(0, 0, 320, 240);
const frame = new VideoFrame(canvas, { timestamp: 0 });
const copy = frame.clone(); // teilt sich dieselbe Ressource
frame.close();
console.log(frame.format, frame.codedWidth); // geschlossen
console.log(copy.codedWidth); // Klon bleibt gültig
try {
frame.clone();
} catch (e) {
console.log(e.name);
}
copy.close(); // erst jetzt wird der Speicher wirklich freigegeben
Frame nach dem Encodieren freigeben
const encoder = new VideoEncoder({
output: (chunk) => console.log('Chunk:', chunk.byteLength, 'Bytes'),
error: (e) => console.error(e)
});
encoder.configure({ codec: 'vp8', width: 320, height: 240 });
const canvas = new OffscreenCanvas(320, 240);
const frame = new VideoFrame(canvas, { timestamp: 0 });
encoder.encode(frame);
frame.close(); // encode() übernimmt den Frame nicht, also selbst schließen
await encoder.flush();
// Wichtig · Fallstricke
- Immer schließen: Jeder
VideoFrame, auch jeder Klon, muss geschlossen werden. Nicht geschlossene Frames blockieren Decoder- und Kamera-Puffer. Die Folgen sind Einfrieren, Speicherlecks und Konsolenwarnungen. Setzetry … finallyein, damit der Frame auch bei einer Ausnahme freigegeben wird. - Mehrfacher Aufruf:
close()ist idempotent. Ein zweiter Aufruf wirft keinen Fehler. - Nach dem Schließen werfen
clone(),copyTo(),allocationSize()und die Verwendung als Bildquelle eineInvalidStateError. - Übertragung: Mit
postMessage(frame, [frame])übertragene Frames sind im Sender automatisch geschlossen. Der Empfänger muss sie selbst schließen. Ohne Transfer-Liste wird der Frame nur geklont, und du musst beide Seiten schließen. clone()kopiert keine Pixeldaten. Die Methode erzeugt nur eine weitere Referenz auf dieselbe Ressource. Freigegeben wird die Ressource erst, wenn alle Referenzen geschlossen sind.- Kompatibilität: Die WebCodecs-API gibt es nur in sicheren Kontexten (HTTPS). Sie läuft in Chromium ab Version 94, in Safari ab 16.4 und in Firefox ab 130, jeweils im Fenster und in Workern.
MediaStreamTrackProcessorsteht nicht überall zur Verfügung. Prüfe die Unterstützung vorab mit'VideoFrame' in globalThis.