Start · Sprachen · JavaScript · Referenz · RTCEncodedVideoFrame.timestamp

RTCEncodedVideoFrame.timestamp

Eigenschaft

Schreibgeschützter RTP-Zeitstempel eines kodierten Videoframes. Er gibt an, wann das Sampling des Frames begonnen hat, gemessen im 90-kHz-Takt.

seit JavaScript WebRTC Encoded Transform: Chrome 86+, Firefox 117+ deprecated seit ja Kategorie: webapi

Signatur

RTCEncodedVideoFrame.timestamp

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

Typ
number
Beschreibung
Vorzeichenlose 32-Bit-Ganzzahl (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' });
Typ: key, RTP-Zeitstempel: 1843201290 Typ: delta, RTP-Zeitstempel: 1843204290 Typ: delta, RTP-Zeitstempel: 1843207290

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);
});
Abstand: 3000 Ticks ≈ 30.0 fps

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);
});
Frame bei RTP-Zeit 20480.013 s

// 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() oder performance.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().rtpTimestamp bereit. timestamp ist in manchen Dokumentationen als veraltet markiert. Nutzen Sie nach Möglichkeit die Metadaten und prüfen Sie beide Wege per Feature-Erkennung.
  • Kompatibilität: RTCRtpScriptTransform gibt es in Firefox und Safari sowie in neueren Chrome-Versionen. Ältere Chrome-Versionen kennen nur createEncodedStreams(). 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.