Start · Sprachen · JavaScript · Referenz · new VideoEncoder()

new VideoEncoder()

Methode

Erzeugt einen neuen <code>VideoEncoder</code>, der <code>VideoFrame</code>-Objekte in komprimierte <code>EncodedVideoChunk</code>s kodiert und über Callbacks meldet.

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

Signatur

new VideoEncoder(init)

Beschreibung

Der Konstruktor VideoEncoder() legt einen neuen Video-Encoder der WebCodecs API an. Du übergibst ein Objekt mit zwei Callbacks: output wird für jeden fertig kodierten EncodedVideoChunk aufgerufen, error bei einem schwerwiegenden Fehler. Danach steht der Encoder im Zustand "unconfigured".

Bevor du Frames mit encode() übergeben kannst, musst du ihn mit configure() einrichten: Codec (z. B. "vp8", "vp09.00.10.08", "avc1.42001f", "av01.0.04M.08"), Auflösung, Bitrate und Bildrate. Ob eine Konfiguration unterstützt wird, prüfst du vorher mit der statischen Methode VideoEncoder.isConfigSupported().

Typische Anwendungen sind browserseitige Videoaufnahme und -bearbeitung, Echtzeit-Streaming über WebTransport oder WebSockets, Bildschirmaufnahmen und das Erzeugen von Videodateien aus Canvas-Inhalten, jeweils mit Hardwarebeschleunigung und ohne WebAssembly-Encoder.

Parameter

Name Typ Default Beschreibung
$init Pflicht Object Initialisierungsobjekt mit den beiden Pflicht-Callbacks output und error.
$init.output Pflicht (chunk: EncodedVideoChunk, metadata?: EncodedVideoChunkMetadata) => void Wird für jeden kodierten Chunk aufgerufen. metadata.decoderConfig (beim ersten Keyframe bzw. nach Konfigurationswechsel) enthält die Konfiguration für einen passenden VideoDecoder, z. B. description bei H.264 im AVC-Format.
$init.error Pflicht (error: DOMException) => void Wird bei einem schwerwiegenden Fehler aufgerufen. Danach ist der Encoder im Zustand "closed" und nicht mehr verwendbar.

Rückgabewert

Typ
VideoEncoder
Beschreibung
Ein neues VideoEncoder-Objekt mit state === "unconfigured" und encodeQueueSize === 0.

Beispiele

Encoder erzeugen und konfigurieren

const chunks = [];

const encoder = new VideoEncoder({
  output: (chunk, metadata) => {
    chunks.push(chunk);
    if (metadata?.decoderConfig) {
      console.log('Decoder-Konfiguration:', metadata.decoderConfig.codec);
    }
  },
  error: (e) => console.error('Encoder-Fehler:', e.message)
});

console.log(encoder.state);

const config = {
  codec: 'vp8',
  width: 640,
  height: 480,
  bitrate: 1_000_000, // 1 Mbit/s
  framerate: 30
};

const { supported } = await VideoEncoder.isConfigSupported(config);
if (supported) {
  encoder.configure(config);
  console.log(encoder.state);
}
unconfigured configured

Canvas-Animation als Video kodieren

const canvas = new OffscreenCanvas(320, 240);
const ctx = canvas.getContext('2d');
let totalBytes = 0;

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

encoder.configure({ codec: 'vp8', width: 320, height: 240, bitrate: 500_000, framerate: 30 });

for (let i = 0; i < 60; i++) {
  ctx.fillStyle = `hsl(${i * 6}, 80%, 50%)`;
  ctx.fillRect(0, 0, 320, 240);

  // Zeitstempel in Mikrosekunden
  const frame = new VideoFrame(canvas, { timestamp: (i * 1_000_000) / 30 });
  encoder.encode(frame, { keyFrame: i % 30 === 0 });
  frame.close(); // Speicher sofort freigeben!
}

await encoder.flush();
console.log(`60 Frames kodiert, ${totalBytes} Bytes`);
encoder.close();
60 Frames kodiert, 48213 Bytes (Wert variiert)

Kamerastream in Echtzeit kodieren mit Rückstau-Kontrolle

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

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

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

function sendOverNetwork(chunk) {
  const data = new Uint8Array(chunk.byteLength);
  chunk.copyTo(data);
  console.log(chunk.type, data.length);
}

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);
  frame.close();
}
key 18342 delta 2210 delta 1987 ...

// Wichtig · Fallstricke

  • Beide Callbacks sind Pflicht: Fehlt output oder error oder ist es keine Funktion, wirft der Konstruktor einen TypeError.
  • Nur in sicheren Kontexten (HTTPS/localhost) verfügbar, im Fenster und in Dedicated Workers. Für aufwendige Kodierung empfiehlt sich ein Worker, damit der Haupt-Thread frei bleibt.
  • Browser-Unterstützung: Chromium 94+, Safari 16.4+, Firefox 130+. Welche Codecs verfügbar sind, hängt von Plattform und Hardware ab. Prüfe das immer mit VideoEncoder.isConfigSupported(), bevor du configure() aufrufst. Zur Erkennung der Funktion: 'VideoEncoder' in globalThis.
  • Speicherlecks: Rufe nach encode() frame.close() auf. Nicht geschlossene VideoFrames belegen GPU- oder Systemspeicher und können den Kamerastream zum Stillstand bringen.
  • Zeitstempel werden in Mikrosekunden angegeben, nicht in Millisekunden.
  • Der Encoder liefert nur rohe Codec-Daten und keine Containerdatei (MP4/WebM). Zum Muxen brauchst du eine Bibliothek wie mp4-muxer oder webm-muxer.
  • Nach einem Aufruf des error-Callbacks ist die Instanz geschlossen. Du musst dann einen neuen Encoder erzeugen.
  • Beobachte bei Echtzeitanwendungen encodeQueueSize bzw. das Event dequeue, damit sich kein Rückstau aufbaut.