Signatur
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
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 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));
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 ohneframesPerSecond. Prüfe den Wert deshalb immer aufundefined, zum Beispiel mit??. - Der Wert gilt nur für lokale Quellen, also gesendete Spuren. Für empfangenes Video nutzt du
framesPerSecondausRTCInboundRtpStreamStats. - Verwechslungsgefahr:
RTCOutboundRtpStreamStats.framesPerSecondmisst 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 = falseoder einer stummgeschalteten Kamera kann der Wert auf 0 fallen oder fehlen.