Signatur
Beschreibung
copyTo() gehört zur WebCodecs-API. Die Methode schreibt die Rohpixel eines VideoFrame in einen vom Aufrufer bereitgestellten Puffer, also in einen ArrayBuffer, ein TypedArray oder eine DataView. So kommt man direkt an die Pixelwerte, etwa für eigene Bildverarbeitung, WebAssembly-Filter, Übertragung per WebRTC-DataChannel oder zum Speichern von Einzelbildern.
Der Rückgabewert ist ein Promise, das mit einem Array von PlaneLayout-Objekten ({ offset, stride }) erfüllt wird, einem pro Ebene. Bei planaren Formaten wie I420 oder NV12 gibt es mehrere Ebenen (Y, U, V bzw. Y, UV), bei RGBA/BGRA nur eine. Anhand des Layouts weiß man, wo welche Ebene im Puffer beginnt und wie viele Bytes eine Zeile umfasst.
Die nötige Puffergröße liefert VideoFrame.allocationSize(options). Übergib dort dieselben Optionen wie an copyTo(). Mit rect kopierst du nur einen Ausschnitt, mit layout bestimmst du eigene Offsets und Strides, und mit format ("RGBA", "RGBX", "BGRA", "BGRX") samt colorSpace kann der Browser beim Kopieren gleich in RGB umrechnen.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $destination Pflicht | ArrayBuffer | SharedArrayBuffer | TypedArray | DataView | Zielpuffer für die Pixeldaten. Er muss mindestens allocationSize(options) Bytes groß sein. |
|
| $options | Object | {} | Optionales Objekt mit folgenden Einstellungen:
|
Rückgabewert
{ offset, stride }-Objekten erfüllt wird, einem pro Ebene im Zielpuffer. Es wird abgelehnt, wenn der Frame bereits geschlossen ist (InvalidStateError), wenn der Puffer zu klein ist oder wenn rect/layout ungültig sind (TypeError).Beispiele
I420-Frame in einen Puffer kopieren und Layout auslesen
// 4×2-Pixel-Frame im Format I420: Y = 8 Byte, U = 2 Byte, V = 2 Byte
const raw = new Uint8Array(12).fill(128);
const frame = new VideoFrame(raw, {
format: 'I420',
codedWidth: 4,
codedHeight: 2,
timestamp: 0
});
const size = frame.allocationSize();
const buffer = new Uint8Array(size);
const layout = await frame.copyTo(buffer);
console.log(size);
console.log(layout);
frame.close(); // Ressourcen sofort freigeben
Frame direkt als RGBA kopieren und in ein Canvas zeichnen
const source = document.querySelector('canvas#quelle');
const target = document.querySelector('canvas#ziel');
const frame = new VideoFrame(source, { timestamp: 0 });
const options = { format: 'RGBA', colorSpace: 'srgb' };
const pixels = new Uint8ClampedArray(frame.allocationSize(options));
await frame.copyTo(pixels, options);
const { width, height } = frame.visibleRect;
frame.close();
// Beispiel-Filter: Farben invertieren
for (let i = 0; i < pixels.length; i += 4) {
pixels[i] = 255 - pixels[i];
pixels[i + 1] = 255 - pixels[i + 1];
pixels[i + 2] = 255 - pixels[i + 2];
}
target.width = width;
target.height = height;
target.getContext('2d').putImageData(new ImageData(pixels, width, height), 0, 0);
Nur einen Ausschnitt eines Kamerabildes kopieren
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const [track] = stream.getVideoTracks();
// MediaStreamTrackProcessor gibt es bisher nur in Chromium-Browsern
const reader = new MediaStreamTrackProcessor({ track }).readable.getReader();
const { value: frame } = await reader.read();
// 64×64-Ausschnitt oben links; gerade Werte wegen der Unterabtastung
const options = { rect: { x: 0, y: 0, width: 64, height: 64 }, format: 'RGBA' };
const buffer = new ArrayBuffer(frame.allocationSize(options));
const layout = await frame.copyTo(buffer, options);
console.log(buffer.byteLength, layout);
frame.close();
track.stop();