v145 · Web APIs · WebRTC · demo

RTP Clock Converter

The RTP 90 kHz video clock is central to synchronisation and quality analysis. Convert an rtpTimestamp from VideoFrame.metadata() to wall-clock time, compute inter-frame deltas, and use the frame-drop detector below — which flags any gap greater than 1.5× the expected frame interval.

Chrome 145: VideoFrame.metadata().rtpTimestamp is now populated for frames received via WebRTC. The 90 kHz RTP clock is standard for video (RFC 3550); audio uses 48 kHz or 8 kHz depending on codec.

Enter an RTP timestamp and frame rate · convert to time · then simulate a frame sequence and inject a drop

Time since origin
rtpTimestamp ÷ 90000
Inter-frame delta
current − previous timestamp
Delta as seconds
delta ÷ 90000
Expected interval
90000 ÷ fps
Drop detected?
delta > 1.5 × expected?
Frame sequence simulator
Fps:
#rtpTimestampdeltasecsstatus
No frames yet — click "+ Frame"
RTP 90 kHz clock — key formulas
time_s = rtpTimestamp / 90000 — convert to seconds (video clock)
interval_ticks = 90000 / fps — expected ticks per frame (30fps → 3000)
delta = ts_current − ts_previous — ticks between consecutive frames
frames_skipped = round(delta / interval) − 1 — dropped frame count
drop_detected = delta > interval * 1.5 — flag condition
wrap = ts > 2^32 → ts - 2^32 — RTP timestamps wrap at 32-bit boundary
// Chrome 145: read rtpTimestamp from VideoFrame.metadata()
const processor = new MediaStreamTrackProcessor({ track: videoTrack });
const reader = processor.readable.getReader();

const FPS = 30;
const EXPECTED_INTERVAL = 90000 / FPS; // 3000 ticks at 30fps

let prevRtp = null;

while (true) {
  const { value: frame, done } = await reader.read();
  if (done) break;

  const { rtpTimestamp } = frame.metadata();

  if (prevRtp !== null) {
    const delta = rtpTimestamp - prevRtp; // handles wrap-around carefully in real code
    const dropped = delta > EXPECTED_INTERVAL * 1.5;
    if (dropped) {
      const skipped = Math.round(delta / EXPECTED_INTERVAL) - 1;
      console.warn(`Dropped ${skipped} frame(s) at rtpTimestamp=${rtpTimestamp}`);
    }
  }

  prevRtp = rtpTimestamp;
  frame.close();
}

see also