Start · Sprachen · JavaScript · Referenz · VideoFrame.clone()

VideoFrame.clone()

Methode

Erstellt ein neues <code>VideoFrame</code>, das auf dieselbe Medienressource wie das Original verweist, aber einen eigenen Lebenszyklus hat.

seit JavaScript WebCodecs API – Chrome/Edge 94+, Safari 16.4+ (tei Kategorie: webapi

Signatur

VideoFrame.prototype.clone()

Beschreibung

Die Methode clone() des VideoFrame-Interfaces aus der WebCodecs API gibt ein neues VideoFrame zurück, das auf dieselbe zugrunde liegende Medienressource zeigt. Die Pixeldaten werden dabei nicht kopiert. Intern wird nur ein Referenzzähler erhöht, deshalb ist der Aufruf sehr günstig.

Gebraucht wird clone(), wenn mehrere unabhängige Verbraucher dasselbe Bild nutzen sollen. Beispiele: Ein Frame wird gleichzeitig an einen VideoEncoder übergeben und auf einem Canvas angezeigt, oder er wird an einen Worker geschickt, während der Haupt-Thread weiter damit arbeitet. Jeder Klon hat einen eigenen Lebenszyklus und muss eigenständig mit close() freigegeben werden. Die Ressource selbst wird erst freigegeben, wenn alle Referenzen geschlossen sind.

Wurde das Original-Frame bereits mit close() geschlossen, wirft clone() eine InvalidStateError-DOMException. Der Klon übernimmt alle Metadaten wie timestamp, duration, codedWidth, displayWidth, format und colorSpace.

Rückgabewert

Typ
VideoFrame
Beschreibung
Ein neues VideoFrame-Objekt, das auf dieselbe Medienressource wie das Original verweist. Es muss separat mit close() freigegeben werden.

Beispiele

Frame klonen und beide Referenzen schließen

const canvas = new OffscreenCanvas(320, 240);
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'teal';
ctx.fillRect(0, 0, 320, 240);

const frame = new VideoFrame(canvas, { timestamp: 0 });
const copy = frame.clone();

console.log(copy.timestamp, copy.displayWidth, copy.displayHeight);

// Beide Referenzen müssen einzeln freigegeben werden
frame.close();
console.log(copy.displayWidth); // Klon ist weiterhin gültig
copy.close();
0 320 240 320

Ein Frame gleichzeitig anzeigen und kodieren

const encoder = new VideoEncoder({
  output: (chunk) => console.log('Chunk:', chunk.byteLength, 'Bytes'),
  error: (e) => console.error(e)
});
encoder.configure({ codec: 'vp8', width: 640, height: 480 });

const display = document.querySelector('canvas').getContext('2d');

const handleFrame = (frame) => {
  // Klon an den Encoder: encode() übernimmt nicht das Schließen
  const forEncoder = frame.clone();
  encoder.encode(forEncoder);
  forEncoder.close();

  // Original für die Anzeige verwenden und danach freigeben
  display.drawImage(frame, 0, 0);
  frame.close();
};
Chunk: 1834 Bytes

Frame an einen Worker übertragen und lokal behalten

const worker = new Worker('analyse-worker.js');

const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const [track] = stream.getVideoTracks();
const reader = new MediaStreamTrackProcessor({ track }).readable.getReader();

const { value: frame } = await reader.read();

// Klon wird übertragen (transfer), Original bleibt im Haupt-Thread
const forWorker = frame.clone();
worker.postMessage({ frame: forWorker }, [forWorker]);

console.log('Lokal:', frame.codedWidth, 'x', frame.codedHeight);
frame.close();
Lokal: 1280 x 720

Fehler beim Klonen eines geschlossenen Frames

const frame = new VideoFrame(new OffscreenCanvas(10, 10), { timestamp: 0 });
frame.close();

try {
  frame.clone();
} catch (err) {
  console.log(err.name);
}
InvalidStateError

// Wichtig · Fallstricke

  • Speicherlecks: Jeder Klon hält die Medienressource fest, oft GPU- oder Decoder-Puffer. Klone, die nie geschlossen werden, können den Decoder blockieren, sodass keine neuen Frames mehr kommen. Rufen Sie immer close() auf und verlassen Sie sich nicht auf die Garbage Collection.
  • Keine tiefe Kopie: clone() kopiert keine Pixeldaten. Für eine echte Kopie der Rohdaten verwenden Sie copyTo() oder erzeugen mit new VideoFrame(frame, init) ein Frame mit geänderten Metadaten.
  • Geschlossene Frames: Der Aufruf auf einem bereits geschlossenen Frame wirft eine InvalidStateError-DOMException.
  • Transfer vs. Klon: Wird ein Frame per postMessage übertragen, wird das Original im Sender getrennt (detached). Wenn der Sender das Frame weiter braucht, übertragen Sie vorher einen Klon.
  • Kompatibilität: Die WebCodecs API gibt es nur in sicheren Kontexten (HTTPS). In Chromium-Browsern ist sie vollständig verfügbar, in Firefox ab Version 130, in Safari teilweise. Prüfen Sie die Unterstützung vorher mit 'VideoFrame' in globalThis.