Signatur
Beschreibung
Die Eigenschaft qpSum des Wörterbuchs RTCOutboundRtpStreamStats enthält eine vorzeichenlose Ganzzahl. Sie ist die Summe der Quantisierungsparameter (QP) aller Frames, die der Encoder für diesen ausgehenden RTP-Videostream bisher erzeugt hat. Je höher der QP, desto stärker komprimiert der Encoder, und desto schlechter ist die Bildqualität meist.
Ein einzelner Wert von qpSum hilft allein wenig. Aussagekräftig wird er erst, wenn man ihn durch framesEncoded teilt. So erhält man den durchschnittlichen QP pro Frame. Noch genauer wird es, wenn man die Differenz zwischen zwei Messungen bildet: ΔqpSum / ΔframesEncoded. Das ergibt den mittleren QP im Messintervall, und damit lassen sich Qualitätseinbrüche in Echtzeit erkennen, etwa bei knapper Bandbreite oder hoher CPU-Last.
Die Werte lassen sich nur innerhalb desselben Codecs vergleichen. Welcher QP-Bereich gilt, hängt vom Codec ab: VP8 und VP9 nutzen 0–127, H.264 nutzt 0–51, AV1 nutzt 0–255. Welcher Codec aktiv ist, erfährt man über codecId und den zugehörigen RTCCodecStats-Eintrag. Die Eigenschaft gibt es nur bei Video-Streams (kind === "video").
Rückgabewert
undefined), ebenso wenn der Browser ihn nicht meldet.Beispiele
Durchschnittlichen QP pro Frame auslesen
// pc ist eine bestehende RTCPeerConnection mit gesendetem Video
const logAverageQp = async (pc) => {
const stats = await pc.getStats();
stats.forEach((report) => {
if (report.type === 'outbound-rtp' && report.kind === 'video' && report.qpSum !== undefined) {
const avgQp = report.framesEncoded > 0 ? report.qpSum / report.framesEncoded : 0;
console.log(`SSRC ${report.ssrc}: Ø QP = ${avgQp.toFixed(1)}`);
}
});
};
await logAverageQp(pc);
QP im Intervall überwachen (Delta-Berechnung)
const previous = new Map();
const monitorQp = async (sender) => {
const stats = await sender.getStats();
for (const report of stats.values()) {
if (report.type !== 'outbound-rtp' || report.kind !== 'video') continue;
const prev = previous.get(report.id);
if (prev) {
const frames = report.framesEncoded - prev.framesEncoded;
const qp = report.qpSum - prev.qpSum;
if (frames > 0) {
const intervalQp = qp / frames;
console.log(`Intervall-QP (${report.rid ?? 'default'}): ${intervalQp.toFixed(1)}`);
if (intervalQp > 40) console.warn('Qualität sinkt – Bandbreite oder CPU prüfen');
}
}
previous.set(report.id, { qpSum: report.qpSum, framesEncoded: report.framesEncoded });
}
};
const [videoSender] = pc.getSenders().filter((s) => s.track?.kind === 'video');
setInterval(() => monitorQp(videoSender), 2000);
QP zusammen mit dem Codec ausgeben
const qpWithCodec = async (pc) => {
const stats = await pc.getStats();
for (const r of stats.values()) {
if (r.type === 'outbound-rtp' && r.kind === 'video' && r.framesEncoded) {
const codec = stats.get(r.codecId);
console.log(codec?.mimeType, (r.qpSum / r.framesEncoded).toFixed(1));
}
}
};
await qpWithCodec(pc);
// Wichtig · Fallstricke
- Codec-abhängig: QP-Werte lassen sich nicht zwischen Codecs vergleichen, weil VP8/VP9 (0–127), H.264 (0–51) und AV1 (0–255) unterschiedliche Skalen haben. Wechselt der Codec mitten in der Sitzung, verliert die Delta-Berechnung ihre Aussagekraft.
- Kumulativ:
qpSumwächst nur. Für aktuelle Qualitätswerte bildet man immer Differenzen zwischen zweigetStats()-Aufrufen. - Simulcast: Jede Schicht (
rid) hat einen eigenenoutbound-rtp-Eintrag mit eigenemqpSum. - Kompatibilität: Ob und wie der Wert gemeldet wird, unterscheidet sich zwischen Browsern und Encodern, zum Beispiel bei Hardware-Encodern. Vor der Nutzung auf
undefinedprüfen. Bei Audio-Streams fehlt die Eigenschaft immer. - Ein hoher QP ist nur ein Hinweis auf schlechte Qualität. Er misst die Qualität nicht direkt, denn auch der Bildinhalt beeinflusst ihn (z. B. viel Bewegung).