Signatur
Beschreibung
Die schreibgeschützte Eigenschaft timestamp eines RTCEncodedVideoFrame enthält den RTP-Zeitstempel des Frames. Er gibt an, zu welchem Zeitpunkt das Sampling des Bildes begonnen hat. Bei Video läuft die RTP-Uhr mit 90 000 Ticks pro Sekunde. Der Wert ist also keine Zeit in Millisekunden, sondern eine vorzeichenlose 32-Bit-Ganzzahl, die ab einem zufälligen Startwert hochzählt.
Sie begegnen der Eigenschaft in WebRTC Encoded Transforms, also in einem RTCRtpScriptTransform in einem Worker oder in den älteren Chrome-Insertable-Streams über createEncodedStreams(). Dort liest man kodierte Frames aus einem ReadableStream, verändert sie und schreibt sie weiter. Wofür man den Zeitstempel typischerweise nutzt:
- Abstände zwischen Frames messen und daraus die Bildrate schätzen,
- Metadaten (z. B. Untertitel oder Markierungen) einem bestimmten Frame zuordnen,
- Audio- und Videoframes synchronisieren oder Frames protokollieren und debuggen.
Alle Frames, die zum selben Bild gehören, haben denselben Zeitstempel. Aufeinanderfolgende Bilder haben steigende Werte, bei 30 fps im Idealfall jeweils etwa 3000 Ticks Abstand. Weil die Eigenschaft schreibgeschützt ist, lässt sich der Zeitstempel eines Frames nicht direkt ändern.
Rückgabewert
unsigned long): der RTP-Zeitstempel des Frames im 90-kHz-Takt der Video-RTP-Uhr.Beispiele
Zeitstempel in einem RTCRtpScriptTransform-Worker protokollieren
// worker.js
addEventListener('rtctransform', (event) => {
const { readable, writable } = event.transformer;
const transform = new TransformStream({
transform(frame, controller) {
// frame ist ein RTCEncodedVideoFrame
console.log(`Typ: ${frame.type}, RTP-Zeitstempel: ${frame.timestamp}`);
controller.enqueue(frame);
}
});
readable.pipeThrough(transform).pipeTo(writable);
});
// main.js
const worker = new Worker('worker.js');
const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const [track] = stream.getVideoTracks();
const sender = pc.addTrack(track, stream);
sender.transform = new RTCRtpScriptTransform(worker, { side: 'send' });
Bildrate aus RTP-Zeitstempeln schätzen (mit Überlauf-Behandlung)
const RTP_CLOCK = 90000; // Video-RTP-Takt in Hz
let lastTs = null;
const fpsTransform = new TransformStream({
transform(frame, controller) {
if (lastTs !== null && frame.timestamp !== lastTs) {
// Differenz modulo 2^32, damit der Überlauf korrekt behandelt wird
const delta = (frame.timestamp - lastTs + 2 ** 32) % 2 ** 32;
const fps = RTP_CLOCK / delta;
console.log(`Abstand: ${delta} Ticks ≈ ${fps.toFixed(1)} fps`);
}
lastTs = frame.timestamp;
controller.enqueue(frame);
}
});
addEventListener('rtctransform', ({ transformer }) => {
transformer.readable.pipeThrough(fpsTransform).pipeTo(transformer.writable);
});
Chrome-Legacy-API: createEncodedStreams() auf Empfängerseite
// Nur Chrome, benötigt new RTCPeerConnection({ encodedInsertableStreams: true })
const pc = new RTCPeerConnection({ encodedInsertableStreams: true });
pc.addEventListener('track', (event) => {
const { readable, writable } = event.receiver.createEncodedStreams();
readable
.pipeThrough(new TransformStream({
transform(frame, controller) {
const seconds = frame.timestamp / 90000;
console.log(`Frame bei RTP-Zeit ${seconds.toFixed(3)} s`);
controller.enqueue(frame);
}
}))
.pipeTo(writable);
});
// Wichtig · Fallstricke
- Keine Wanduhrzeit: Der Wert ist ein RTP-Zeitstempel im 90-kHz-Takt, der bei einem zufälligen Offset beginnt. Er lässt sich nicht mit
Date.now()oderperformance.now()vergleichen. Aussagekräftig sind nur Differenzen zwischen Frames desselben Streams. - Überlauf: Als 32-Bit-Wert springt der Zeitstempel nach etwa 13,25 Stunden (232 / 90 000 s) zurück auf 0. Rechnen Sie Differenzen deshalb modulo 232.
- Veraltet: Neuere Fassungen der Spezifikation stellen den RTP-Zeitstempel über
frame.getMetadata().rtpTimestampbereit.timestampist in manchen Dokumentationen als veraltet markiert. Nutzen Sie nach Möglichkeit die Metadaten und prüfen Sie beide Wege per Feature-Erkennung. - Kompatibilität:
RTCRtpScriptTransformgibt es in Firefox und Safari sowie in neueren Chrome-Versionen. Ältere Chrome-Versionen kennen nurcreateEncodedStreams(). Encoded Transforms laufen nur in sicheren Kontexten (HTTPS). - Da die Eigenschaft schreibgeschützt ist, ignoriert eine Zuweisung den neuen Wert stillschweigend. Im Strict Mode wirft sie einen
TypeError.