Signatur
Beschreibung
Die schreibgeschützte Eigenschaft timestamp eines EncodedVideoChunk-Objekts gibt den Präsentationszeitstempel des Chunks in Mikrosekunden an. Der Wert wird beim Aufruf des Konstruktors new EncodedVideoChunk({ timestamp, ... }) festgelegt oder vom VideoEncoder gesetzt. Er stammt aus dem timestamp des zugehörigen VideoFrame.
Der Zeitstempel wird gebraucht, um kodierte Daten richtig anzuordnen und zu synchronisieren. Das gilt etwa beim Muxen in einen Container (MP4, WebM), beim Übertragen über WebTransport oder WebRTC-ähnliche Pipelines und beim Abgleich mit Audiospuren (EncodedAudioChunk.timestamp). Beim Dekodieren gibt der VideoDecoder den Wert unverändert an das erzeugte VideoFrame weiter.
Wichtig: timestamp ist ein Präsentationszeitstempel, keine Dekodierreihenfolge. Bei Codecs mit B-Frames (z. B. H.264 oder HEVC) kann die Ausgabereihenfolge des Encoders von der zeitlichen Reihenfolge abweichen. Der Wert kann auch negativ sein, etwa bei Vorlauf-Frames oder Edit-Lists.
Beispiele
Chunk erzeugen und Zeitstempel auslesen
// Rohdaten eines bereits kodierten Keyframes (Platzhalter)
const data = new Uint8Array([0x00, 0x00, 0x00, 0x01, 0x65]);
const chunk = new EncodedVideoChunk({
type: 'key',
timestamp: 33_333, // 33,333 ms = zweiter Frame bei 30 fps
duration: 33_333,
data
});
console.log(chunk.timestamp);
console.log(`${(chunk.timestamp / 1_000_000).toFixed(3)} s`);
Zeitstempel im VideoEncoder-Output protokollieren
const encoder = new VideoEncoder({
output: (chunk, metadata) => {
console.log(`${chunk.type}-Chunk @ ${chunk.timestamp} µs, ${chunk.byteLength} Bytes`);
},
error: (e) => console.error('Encoder-Fehler:', 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 < 3; i++) {
ctx.fillStyle = `hsl(${i * 120}, 80%, 50%)`;
ctx.fillRect(0, 0, 640, 480);
// Zeitstempel des Frames landet später im Chunk
const frame = new VideoFrame(canvas, { timestamp: i * 33_333 });
encoder.encode(frame, { keyFrame: i === 0 });
frame.close();
}
await encoder.flush();
Chunks vor dem Muxen nach Präsentationszeit sortieren
const chunks = [];
const encoder = new VideoEncoder({
output: (chunk) => chunks.push(chunk),
error: console.error
});
// ... configure() und encode() wie gewohnt ...
const sortByPresentation = (list) =>
[...list].sort((a, b) => a.timestamp - b.timestamp);
const ordered = sortByPresentation(chunks);
const totalDurationUs = ordered.length
? ordered.at(-1).timestamp + (ordered.at(-1).duration ?? 0) - ordered[0].timestamp
: 0;
console.log(`Gesamtdauer: ${totalDurationUs / 1000} ms`);
// Wichtig · Fallstricke
- Einheit Mikrosekunden: Die Einheit ist nicht Millisekunden wie bei
performance.now()und nicht Sekunden wie beiHTMLMediaElement.currentTime. Für Container wie MP4 musst du den Wert in die Timescale des Tracks umrechnen, z. B. mitMath.round(ts * timescale / 1e6). - Schreibgeschützt: Eine Zuweisung wie
chunk.timestamp = 0wird stillschweigend ignoriert, im Strict Mode wirft sie einenTypeError. Um einen anderen Zeitstempel zu setzen, erzeugst du einen neuen Chunk: Die Daten kopierst du mitcopyTo()heraus und übergibst sie annew EncodedVideoChunk(). - Keine Dekodierreihenfolge: Bei B-Frames sind die Zeitstempel in der Ausgabereihenfolge des Encoders nicht zwingend aufsteigend. Einen separaten DTS gibt es nicht. Beim Muxen musst du ihn gegebenenfalls selbst ableiten.
- Genauigkeit: Werte jenseits von
Number.MAX_SAFE_INTEGERsind in der Praxis kein Thema. Bei 30 fps entstehen aber Rundungsfehler (33 333,33… µs pro Frame). Berechne die Zeitstempel deshalb aus der Frame-Nummer (Math.round(i * 1e6 / fps)), statt sie aufzusummieren. - Kompatibilität: Die WebCodecs-API ist nur in sicheren Kontexten (HTTPS) verfügbar. Sie läuft im Hauptthread und in Workern. Chromium unterstützt sie seit Version 94, Firefox seit 130. Safari unterstützt die Video-Teile ab 16.4. Prüfe die Verfügbarkeit mit
'EncodedVideoChunk' in globalThis.