Start · Sprachen · JavaScript · Referenz · EncodedVideoChunk

EncodedVideoChunk

Schnittstelle

Repräsentiert ein unveränderliches Segment kodierter Videodaten (z. B. ein H.264- oder VP9-Frame) für die Verarbeitung mit <code>VideoDecoder</code> und <code>VideoEncoder</code>.

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

Signatur

interface EncodedVideoChunk

Beschreibung

EncodedVideoChunk gehört zur WebCodecs API und kapselt genau einen kodierten Videoframe samt Metadaten. Ein VideoEncoder übergibt solche Chunks an seinen output-Callback, und ein VideoDecoder erwartet sie als Eingabe für decode(). So bekommen Sie einen direkten, sehr hardwarenahen Zugriff auf Video-Codecs, ohne den Umweg über <video> oder MediaRecorder.

Einen Chunk erzeugen Sie mit new EncodedVideoChunk(init). Das Init-Objekt enthält den Typ ("key" für Schlüsselbilder oder "delta" für abhängige Bilder), einen Zeitstempel in Mikrosekunden, optional eine Dauer und die eigentlichen Bytes. Die Daten werden beim Erzeugen kopiert. Der Chunk ist danach unveränderlich.

Wichtige Eigenschaften und Methoden:

  • type: "key" oder "delta" (nur lesbar)
  • timestamp: Präsentationszeitpunkt in Mikrosekunden (nur lesbar)
  • duration: Dauer in Mikrosekunden oder null (nur lesbar)
  • byteLength: Größe der kodierten Daten in Bytes (nur lesbar)
  • copyTo(destination): kopiert die Bytes in einen ArrayBuffer, eine TypedArray oder eine DataView

Typische Einsatzgebiete sind Demuxing von MP4/WebM-Dateien (z. B. mit mp4box.js), Echtzeit-Streaming über WebTransport oder WebSocket, Videobearbeitung im Browser und das eigene Muxen aufgenommener Kamerabilder.

Rückgabewert

Typ
EncodedVideoChunk
Beschreibung
Ein neues, unveränderliches EncodedVideoChunk-Objekt.

Beispiele

Chunk aus demuxten Daten erzeugen und dekodieren

const decoder = new VideoDecoder({
  output: (frame) => {
    console.log(`Frame ${frame.timestamp} µs, ${frame.displayWidth}x${frame.displayHeight}`);
    frame.close(); // Speicher sofort freigeben
  },
  error: (e) => console.error('Decoder-Fehler:', e)
});

decoder.configure({
  codec: 'vp8',
  codedWidth: 640,
  codedHeight: 480
});

// sampleBytes: Uint8Array aus einem Demuxer (z. B. WebM-Parser)
const feedSample = (sampleBytes, isKeyframe, timestampUs) => {
  const chunk = new EncodedVideoChunk({
    type: isKeyframe ? 'key' : 'delta',
    timestamp: timestampUs,
    duration: 33_333, // ca. 30 fps
    data: sampleBytes
  });
  decoder.decode(chunk);
};
Frame 0 µs, 640x480 Frame 33333 µs, 640x480

Chunks aus dem VideoEncoder empfangen und übertragen

const socket = new WebSocket('wss://example.com/stream');
socket.binaryType = 'arraybuffer';

const encoder = new VideoEncoder({
  output: (chunk, metadata) => {
    // Bytes aus dem Chunk in einen eigenen Puffer kopieren
    const buffer = new Uint8Array(chunk.byteLength);
    chunk.copyTo(buffer);

    console.log(chunk.type, chunk.timestamp, chunk.byteLength);

    // Einfacher Header: 1 Byte Typ + 8 Byte Zeitstempel
    const packet = new Uint8Array(9 + buffer.byteLength);
    const view = new DataView(packet.buffer);
    view.setUint8(0, chunk.type === 'key' ? 1 : 0);
    view.setBigInt64(1, BigInt(chunk.timestamp));
    packet.set(buffer, 9);
    socket.send(packet);
  },
  error: (e) => console.error(e)
});

encoder.configure({ codec: 'vp8', width: 640, height: 480, bitrate: 1_000_000 });
key 0 18423 delta 33333 2140

Empfangenes Paket wieder in einen Chunk umwandeln

const packetToChunk = (arrayBuffer) => {
  const view = new DataView(arrayBuffer);
  const isKey = view.getUint8(0) === 1;
  const timestamp = Number(view.getBigInt64(1));

  return new EncodedVideoChunk({
    type: isKey ? 'key' : 'delta',
    timestamp,
    data: new Uint8Array(arrayBuffer, 9)
  });
};

// Test mit einem künstlichen Paket
const raw = new Uint8Array(12);
new DataView(raw.buffer).setUint8(0, 1);
const chunk = packetToChunk(raw.buffer);
console.log(chunk.type, chunk.timestamp, chunk.byteLength, chunk.duration);
key 0 3 null

// Wichtig · Fallstricke

  • Erster Chunk muss ein Schlüsselbild sein: Nach configure() oder flush() erwartet der VideoDecoder als Erstes einen Chunk vom Typ "key". Sonst wirft decode() einen DataError.
  • Zeiteinheit: timestamp und duration sind in Mikrosekunden angegeben, nicht in Millisekunden. Zeitstempel aus Containern (z. B. MP4-Timescale) müssen Sie also umrechnen.
  • Daten sind nicht direkt lesbar: Es gibt keine data-Eigenschaft. Auf die Bytes kommen Sie nur über copyTo(). Ist der Zielpuffer kleiner als byteLength, wird ein TypeError ausgelöst.
  • Bitstream-Format: Bei H.264/H.265 hängt das erwartete Format (Annex B oder AVC/length-prefixed) davon ab, ob in configure() eine description übergeben wird.
  • Kompatibilität: WebCodecs ist nur in sicheren Kontexten (HTTPS) verfügbar, auch in Workern. Chrome/Edge unterstützen es seit Version 94, Safari seit 16.4 und Firefox seit 130 (Desktop). Prüfen Sie die Unterstützung vorher mit 'EncodedVideoChunk' in globalThis. Die Option transfer ist neuer und wird noch nicht überall unterstützt.
  • Speicher: Anders als VideoFrame hat ein Chunk keine close()-Methode. Er wird vom Garbage Collector freigegeben. Große Warteschlangen sollten Sie trotzdem begrenzen, z. B. über decoder.decodeQueueSize.