Start · Sprachen · JavaScript · Referenz · RTCVideoSourceStats.framesPerSecond

RTCVideoSourceStats.framesPerSecond

Eigenschaft

Gibt an, wie viele Frames diese Videoquelle in der letzten Sekunde an die zugehörige Spur geliefert hat.

seit JavaScript Chrome 108+, Safari 16.4+, Firefox nicht unterstüt Kategorie: webapi

Signatur

RTCVideoSourceStats.framesPerSecond

Beschreibung

Die schreibgeschützte Eigenschaft framesPerSecond gehört zum Wörterbuch RTCVideoSourceStats, also zu Statistik-Objekten mit type === "media-source" und kind === "video". Sie gibt an, wie viele Frames die lokale Videoquelle (z. B. Kamera oder Bildschirmfreigabe) in der letzten Sekunde erzeugt hat. Den Wert bekommt man über RTCPeerConnection.getStats() oder RTCRtpSender.getStats().

Die Messung erfolgt vor dem Encoder. Deshalb eignet sich der Wert gut, um Probleme an der Quelle von Problemen bei der Kodierung zu unterscheiden. Liefert die Kamera etwa nur 15 fps, obwohl 30 fps angefordert wurden, liegt das Problem bei der Quelle, zum Beispiel wegen schlechter Beleuchtung oder CPU-Drosselung. Sind die framesPerSecond der Quelle hoch, die des zugehörigen outbound-rtp-Eintrags aber niedrig, drosselt dagegen der Encoder oder die Bandbreitenanpassung.

Die Eigenschaft ist optional. In der ersten Sekunde nach dem Start der Quelle fehlt sie oft, weil noch kein vollständiges Messintervall vorliegt. Für eine eigene, genauere Rate über längere Zeiträume kann man auch die Differenz von frames zwischen zwei Messungen durch den Zeitabstand der timestamp-Werte teilen.

Rückgabewert

Typ
number | undefined
Beschreibung
Anzahl der Frames, die die Quelle in der letzten Sekunde erzeugt hat, als Gleitkommazahl. undefined, solange noch kein Messwert vorliegt oder der Browser die Eigenschaft nicht unterstützt.

Beispiele

Bildrate der lokalen Kamera auslesen

const pc = new RTCPeerConnection();
const stream = await navigator.mediaDevices.getUserMedia({ video: { frameRate: 30 } });
const [track] = stream.getVideoTracks();
pc.addTrack(track, stream);

// Kurz warten, damit ein Messintervall vorliegt
await new Promise((r) => setTimeout(r, 2000));

const report = await pc.getStats();
report.forEach((stat) => {
  if (stat.type === 'media-source' && stat.kind === 'video') {
    console.log(`Quelle: ${stat.width}x${stat.height} @ ${stat.framesPerSecond ?? 'n/a'} fps`);
  }
});
Quelle: 1280x720 @ 30 fps

Quelle und Encoder vergleichen (Engpass finden)

const diagnoseFps = async (sender) => {
  const report = await sender.getStats();
  let sourceFps, sentFps;
  report.forEach((s) => {
    if (s.type === 'media-source' && s.kind === 'video') sourceFps = s.framesPerSecond;
    if (s.type === 'outbound-rtp' && s.kind === 'video') sentFps = s.framesPerSecond;
  });
  if (sourceFps === undefined) return 'Noch keine Messwerte';
  if (sourceFps < 20) return `Quelle liefert nur ${sourceFps} fps (Kamera/Licht prüfen)`;
  if (sentFps !== undefined && sentFps < sourceFps * 0.7) {
    return `Encoder drosselt: ${sourceFps} → ${sentFps} fps`;
  }
  return `OK: ${sourceFps} fps`;
};

const sender = pc.getSenders().find((s) => s.track?.kind === 'video');
console.log(await diagnoseFps(sender));
Encoder drosselt: 30 → 15 fps

Bildrate laufend überwachen

const monitor = (sender, intervalMs = 1000) => {
  const id = setInterval(async () => {
    const report = await sender.getStats();
    for (const stat of report.values()) {
      if (stat.type === 'media-source' && stat.kind === 'video') {
        document.querySelector('#fps').textContent =
          stat.framesPerSecond !== undefined ? `${Math.round(stat.framesPerSecond)} fps` : '–';
      }
    }
  }, intervalMs);
  return () => clearInterval(id); // Funktion zum Beenden
};

const stop = monitor(pc.getSenders()[0]);
// später: stop();

// Wichtig · Fallstricke

  • Browser-Unterstützung: Chromium-Browser und Safari unterstützen die Eigenschaft. Firefox liefert zwar media-source-Einträge, aber derzeit ohne framesPerSecond. Prüfe den Wert deshalb immer auf undefined, zum Beispiel mit ??.
  • Der Wert gilt nur für lokale Quellen, also gesendete Spuren. Für empfangenes Video nutzt du framesPerSecond aus RTCInboundRtpStreamStats.
  • Verwechslungsgefahr: RTCOutboundRtpStreamStats.framesPerSecond misst die kodierten, tatsächlich gesendeten Frames. Dieser Wert kann durch Bandbreitenanpassung deutlich niedriger sein als die Bildrate der Quelle.
  • Direkt nach addTrack() fehlt der Wert oft noch. Außerdem schwankt er naturgemäß; für die Anzeige lohnt sich eine Glättung, etwa ein gleitender Mittelwert.
  • Bei track.enabled = false oder einer stummgeschalteten Kamera kann der Wert auf 0 fallen oder fehlen.