Start · Sprachen · JavaScript · Referenz · RTCEncodedVideoFrame.data

RTCEncodedVideoFrame.data

Eigenschaft

Gibt einen <code>ArrayBuffer</code> mit den kodierten Nutzdaten eines Video-Frames zurück. Die Eigenschaft ist beschreibbar, damit Transformationen die Daten ersetzen können.

seit JavaScript WebRTC Encoded Transform: Chrome 86+ (Insertable S Kategorie: webapi

Signatur

RTCEncodedVideoFrame.data

Beschreibung

Die Eigenschaft data eines RTCEncodedVideoFrame enthält die kodierten Bytes eines Video-Frames als ArrayBuffer, also z. B. VP8-, VP9-, AV1- oder H.264-Daten. Auf die Frames greift man über die WebRTC Encoded Transform-API zu, und zwar zwischen Encoder und Paketierer (Senden) oder zwischen Depaketierer und Decoder (Empfangen).

Typische Einsatzfälle sind Ende-zu-Ende-Verschlüsselung (etwa über eine SFU), das Einbetten von Metadaten oder das Analysieren des Bitstroms. Dazu liest man data, erzeugt einen neuen Puffer und weist ihn data wieder zu, bevor man den Frame an den TransformStream-Controller weitergibt.

Auf den ArrayBuffer selbst greift man über typisierte Ansichten wie Uint8Array oder DataView zu. Ob es sich um einen Schlüsselbild-Frame ("key") oder einen Delta-Frame ("delta") handelt, verrät frame.type. Weitere Angaben wie Payload-Typ, SSRC und Abmessungen liefert frame.getMetadata().

Rückgabewert

Typ
ArrayBuffer
Beschreibung
Ein Puffer mit den kodierten Frame-Daten. Beim Setzen muss ebenfalls ein ArrayBuffer zugewiesen werden.

Beispiele

Frame-Daten im Worker per XOR verschlüsseln (Sender)

// worker.js
const KEY = 0x5a;

const encrypt = (frame, controller) => {
  const src = new Uint8Array(frame.data);
  const out = new Uint8Array(src.length);
  // Die ersten 10 Bytes (VP8-Header) unverändert lassen,
  // damit der Paketierer weiterarbeiten kann
  const headerLen = frame.type === 'key' ? 10 : 3;
  for (let i = 0; i < src.length; i++) {
    out[i] = i < headerLen ? src[i] : src[i] ^ KEY;
  }
  frame.data = out.buffer;
  controller.enqueue(frame);
};

onrtctransform = ({ transformer }) => {
  transformer.readable
    .pipeThrough(new TransformStream({ transform: encrypt }))
    .pipeTo(transformer.writable);
};

Transform im Hauptthread an einen Sender hängen

const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const [track] = stream.getVideoTracks();
const sender = pc.addTrack(track, stream);

const worker = new Worker('worker.js');
sender.transform = new RTCRtpScriptTransform(worker, { side: 'send' });

Frame-Größen analysieren

onrtctransform = ({ transformer }) => {
  transformer.readable
    .pipeThrough(new TransformStream({
      transform(frame, controller) {
        console.log(frame.type, frame.data.byteLength, 'Bytes');
        controller.enqueue(frame);
      }
    }))
    .pipeTo(transformer.writable);
};
key 18342 Bytes delta 1204 Bytes delta 987 Bytes

// Wichtig · Fallstricke

  • Kodierte Daten: data enthält keine Pixel, sondern den komprimierten Bitstrom. Rohe Bilddaten erhält man über VideoFrame (WebCodecs) oder ein Canvas.
  • Header erhalten: Wenn man codec-spezifische Header (z. B. den VP8-Payload-Header) mitverschlüsselt, können SFUs und Paketierer die Frames nicht mehr verarbeiten. Bei H.264 können außerdem die NAL-Unit-Grenzen verloren gehen.
  • Zuweisen statt kopieren: Änderungen an einer Uint8Array-Ansicht wirken direkt auf den Puffer. Einen Puffer anderer Länge muss man dagegen neu zuweisen (frame.data = neu.buffer). Denk daran, den Frame danach mit controller.enqueue() weiterzugeben.
  • Kompatibilität: Der Standardweg ist RTCRtpScriptTransform in Worker-Threads (Firefox, Safari, neuere Chrome-Versionen). Ältere Chromium-Versionen kennen nur die proprietären Insertable Streams (createEncodedStreams() mit encodedInsertableStreams: true). Prüfe daher per Feature-Erkennung, was verfügbar ist.
  • Sicherheit: Ein einfaches XOR ist keine echte Verschlüsselung. Nutze für Ende-zu-Ende-Verschlüsselung z. B. AES-GCM über crypto.subtle und verwalte die Schlüssel sauber (SFrame-Standard).