Signatur
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
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);
}
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();
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();
}
// Wichtig · Fallstricke
- Beide Callbacks sind Pflicht: Fehlt
outputodererroroder ist es keine Funktion, wirft der Konstruktor einenTypeError. - 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 duconfigure()aufrufst. Zur Erkennung der Funktion:'VideoEncoder' in globalThis. - Speicherlecks: Rufe nach
encode()frame.close()auf. Nicht geschlosseneVideoFrames 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-muxeroderwebm-muxer. - Nach einem Aufruf des
error-Callbacks ist die Instanz geschlossen. Du musst dann einen neuen Encoder erzeugen. - Beobachte bei Echtzeitanwendungen
encodeQueueSizebzw. das Eventdequeue, damit sich kein Rückstau aufbaut.