Start · Sprachen · JavaScript · Referenz · VideoEncoder.encode()

VideoEncoder.encode()

Methode

Reiht ein <code>VideoFrame</code> zur asynchronen Kodierung ein. Das Ergebnis wird als <code>EncodedVideoChunk</code> an den <code>output</code>-Callback übergeben.

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

Signatur

VideoEncoder.prototype.encode(frame, options)

Beschreibung

encode() übergibt ein VideoFrame an die Kodierwarteschlange eines konfigurierten VideoEncoder. Die Methode kehrt sofort zurück. Die eigentliche Kodierung läuft im Hintergrund, meist hardwarebeschleunigt. Jedes fertige Ergebnis liefert der Browser als EncodedVideoChunk (zusammen mit optionalen Metadaten wie decoderConfig) an den output-Callback, den du im Konstruktor angegeben hast. Fehler landen im error-Callback.

Typische Einsatzfälle sind Videoaufnahmen im Browser (z. B. Kamera- oder Canvas-Inhalte in MP4/WebM schreiben), Echtzeit-Streaming über WebTransport oder WebRTC-Alternativen sowie Videoschnitt und Transkodierung ohne Server. Vor dem ersten Aufruf muss der Encoder mit configure() in den Zustand "configured" gebracht werden.

Mit dem zweiten Parameter kannst du pro Frame steuern, ob ein Keyframe erzeugt werden soll (keyFrame: true). Das ist wichtig für Suchpunkte (Seeking) und für neu hinzukommende Empfänger beim Streaming. Je nach Codec gibt es außerdem Optionen für den Quantisierer, z. B. vp9, av1, avc oder hevc jeweils mit { quantizer }, wenn bitrateMode: "quantizer" konfiguriert ist.

Weil die Kodierung asynchron läuft, solltest du die Warteschlange über encodeQueueSize und das Ereignis dequeue überwachen, damit sich keine Frames aufstauen. Nach dem letzten Frame sorgt flush() dafür, dass alle ausstehenden Chunks ausgegeben werden.

Parameter

Name Typ Default Beschreibung
$frame Pflicht VideoFrame Das zu kodierende Bild. Der Encoder legt intern eine Kopie bzw. Referenz an. Den Frame selbst solltest du danach mit frame.close() freigeben.
$options Object {} Optionale Kodieroptionen pro Frame:
  • keyFrame (boolean, Standard false): erzwingt einen Keyframe.
  • vp9, av1, avc, hevc ({ quantizer: number }): codec-spezifischer Quantisierer. Wirkt nur bei bitrateMode: "quantizer".

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Die kodierten Daten kommen asynchron über den output-Callback als EncodedVideoChunk.

Beispiele

Canvas-Frames kodieren mit regelmäßigen Keyframes

const chunks = [];

const encoder = new VideoEncoder({
  output: (chunk, metadata) => {
    // Chunk-Daten kopieren, z. B. für einen Muxer
    const data = new Uint8Array(chunk.byteLength);
    chunk.copyTo(data);
    chunks.push({ type: chunk.type, timestamp: chunk.timestamp, data });
    if (metadata?.decoderConfig) {
      console.log('Decoder-Konfiguration:', metadata.decoderConfig.codec);
    }
  },
  error: (e) => console.error('Kodierfehler:', 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 < 90; i++) {
  ctx.fillStyle = `hsl(${i * 4}, 80%, 50%)`;
  ctx.fillRect(0, 0, 640, 480);

  const frame = new VideoFrame(canvas, { timestamp: i * (1_000_000 / 30) });
  // Jede Sekunde (alle 30 Frames) ein Keyframe
  encoder.encode(frame, { keyFrame: i % 30 === 0 });
  frame.close(); // Speicher sofort freigeben
}

await encoder.flush();
console.log(`${chunks.length} Chunks, Keyframes: ${chunks.filter(c => c.type === 'key').length}`);
Decoder-Konfiguration: vp8 90 Chunks, Keyframes: 3

Kamera-Stream mit Rückstau-Kontrolle kodieren

const stream = await navigator.mediaDevices.getUserMedia({ video: { width: 1280, height: 720 } });
const [track] = stream.getVideoTracks();
const processor = new MediaStreamTrackProcessor({ track });
const reader = processor.readable.getReader();

const encoder = new VideoEncoder({
  output: (chunk) => sendOverNetwork(chunk),
  error: (e) => console.error(e)
});

encoder.configure({
  codec: 'avc1.42001f',
  width: 1280,
  height: 720,
  bitrate: 2_500_000,
  latencyMode: 'realtime'
});

let frameCount = 0;
while (true) {
  const { value: frame, done } = await reader.read();
  if (done) break;

  // Frames verwerfen, wenn der Encoder nicht hinterherkommt
  if (encoder.encodeQueueSize > 2) {
    frame.close();
    continue;
  }
  encoder.encode(frame, { keyFrame: frameCount++ % 150 === 0 });
  frame.close();
}

function sendOverNetwork(chunk) {
  console.log(chunk.type, chunk.byteLength, 'Bytes');
}
key 48213 Bytes delta 6120 Bytes delta 5874 Bytes ...

Unterstützung prüfen und Zustand absichern

const config = { codec: 'vp09.00.10.08', width: 1920, height: 1080, bitrate: 4_000_000 };

if (!('VideoEncoder' in globalThis)) {
  console.warn('WebCodecs wird nicht unterstützt');
} else {
  const { supported } = await VideoEncoder.isConfigSupported(config);
  console.log('VP9 unterstützt:', supported);

  const encoder = new VideoEncoder({ output: () => {}, error: console.error });
  const frame = new VideoFrame(new OffscreenCanvas(1920, 1080), { timestamp: 0 });

  try {
    encoder.encode(frame); // noch nicht konfiguriert
  } catch (e) {
    console.log(e.name);
  } finally {
    frame.close();
  }
}
VP9 unterstützt: true InvalidStateError

// Wichtig · Fallstricke

  • Zustand: Ist der Encoder nicht im Zustand "configured", wirft encode() einen InvalidStateError. Das passiert vor configure(), nach close() und nach einem Fehler.
  • Geschlossener Frame: Ein bereits geschlossener (detached) VideoFrame führt zu einem TypeError.
  • Speicher: Rufe nach encode() immer frame.close() auf. Nicht geschlossene Frames belegen GPU- bzw. Videospeicher und können die Kamera-Pipeline blockieren. Der Browser gibt dann Warnungen aus.
  • Rückstau: encode() blockiert nie. Überwache encodeQueueSize bzw. das dequeue-Ereignis, sonst wächst die Warteschlange unbegrenzt.
  • Zeitstempel werden in Mikrosekunden angegeben. Monoton steigende Werte sind für die meisten Muxer Pflicht.
  • Keyframes: Der erste ausgegebene Chunk ist immer ein Keyframe. Der Encoder darf auch ohne keyFrame: true selbst Keyframes einfügen.
  • Kompatibilität: WebCodecs gibt es nur in sicheren Kontexten (HTTPS). Es läuft im Fenster und in Dedicated Workers. Die Codec-Unterstützung unterscheidet sich je nach Browser und Hardware, prüfe sie deshalb vorher mit VideoEncoder.isConfigSupported(). Die Quantisierer-Optionen sind neuer und werden nicht überall unterstützt.