Start · Sprachen · JavaScript · Referenz · RTCInboundRtpStreamStats.framesDecoded

RTCInboundRtpStreamStats.framesDecoded

Eigenschaft

Gibt die Gesamtzahl der Videoframes an, die für einen eingehenden RTP-Videostrom bisher erfolgreich decodiert wurden.

seit JavaScript Baseline: Chrome, Edge, Firefox, Safari (WebRTC-St Kategorie: webapi

Signatur

RTCInboundRtpStreamStats.framesDecoded

Beschreibung

Die Eigenschaft framesDecoded des Wörterbuchs RTCInboundRtpStreamStats ist ein Zähler, der angibt, wie viele Videoframes der Empfänger für diese Medienquelle bereits korrekt decodiert hat. Frames, die verworfen wurden oder nicht decodiert werden konnten, zählen nicht dazu. Der Wert steigt monoton an, solange der Strom läuft.

Du bekommst die Statistiken über RTCPeerConnection.getStats() oder RTCRtpReceiver.getStats(). Im zurückgegebenen RTCStatsReport suchst du nach Einträgen mit type === "inbound-rtp" und kind === "video". Bei Audio-Strömen ist die Eigenschaft nicht vorhanden.

In der Praxis vergleichst du zwei Messungen: Aus der Differenz von framesDecoded und der Differenz der timestamp-Werte ergibt sich die tatsächliche Decodier-Bildrate. Zusammen mit framesReceived, framesDropped und totalDecodeTime kannst du erkennen, ob Paketverlust, Überlastung der CPU oder ein zu langsamer Decoder die Videoqualität beeinträchtigt.

Beispiele

Decodierte Frames eines Video-Empfängers auslesen

// pc ist eine bestehende, verbundene RTCPeerConnection
const logDecodedFrames = async (pc) => {
  const report = await pc.getStats();
  report.forEach((stats) => {
    if (stats.type === 'inbound-rtp' && stats.kind === 'video') {
      console.log(`SSRC ${stats.ssrc}: ${stats.framesDecoded} Frames decodiert`);
    }
  });
};

await logDecodedFrames(pc);
SSRC 1234567890: 4512 Frames decodiert

Tatsächliche Decodier-Bildrate berechnen

const getVideoInbound = async (receiver) => {
  const report = await receiver.getStats();
  return [...report.values()].find((s) => s.type === 'inbound-rtp' && s.kind === 'video');
};

const receiver = pc.getReceivers().find((r) => r.track?.kind === 'video');
let previous = await getVideoInbound(receiver);

setInterval(async () => {
  const current = await getVideoInbound(receiver);
  if (!current || !previous) return;
  const frames = current.framesDecoded - previous.framesDecoded;
  const seconds = (current.timestamp - previous.timestamp) / 1000;
  console.log(`Decodier-FPS: ${(frames / seconds).toFixed(1)}`);
  previous = current;
}, 2000);
Decodier-FPS: 29.8

Decoder-Probleme erkennen

const checkDecoderHealth = async (pc) => {
  const report = await pc.getStats();
  for (const s of report.values()) {
    if (s.type !== 'inbound-rtp' || s.kind !== 'video') continue;
    const received = s.framesReceived ?? 0;
    const decoded = s.framesDecoded ?? 0;
    const ratio = received > 0 ? decoded / received : 1;
    const avgDecodeMs = decoded > 0 ? (s.totalDecodeTime / decoded) * 1000 : 0;
    console.log(`Decodiert: ${(ratio * 100).toFixed(1)} % der empfangenen Frames`);
    console.log(`Ø Decodierzeit: ${avgDecodeMs.toFixed(2)} ms`);
    if (ratio < 0.95) console.warn('Viele Frames konnten nicht decodiert werden!');
  }
};

await checkDecoderHealth(pc);
Decodiert: 99.2 % der empfangenen Frames Ø Decodierzeit: 3.41 ms

// Wichtig · Fallstricke

  • Nur für Video: Bei kind === "audio" fehlt die Eigenschaft. Prüfe vor Berechnungen immer auf undefined, z. B. mit ?? 0.
  • Kumulativer Zähler: Der Wert ist eine Gesamtsumme seit Beginn des Stroms. Für Raten brauchst du zwei Messungen und die Differenz der timestamp-Werte (Millisekunden).
  • Neustart/SSRC-Wechsel: Ändert sich die SSRC (z. B. durch Neuverhandlung oder Simulcast-Wechsel), taucht ein neues Statistik-Objekt auf und der Zähler beginnt wieder bei 0. Ordne die Messungen daher über id oder ssrc zu.
  • Decodiert ≠ angezeigt: Decodierte Frames können trotzdem verworfen werden, bevor sie dargestellt werden. Für angezeigte Frames ist framesRendered bzw. framesDropped aussagekräftiger.
  • Kompatibilität: Wird von allen modernen Browsern unterstützt. Ältere Browserversionen lieferten den Wert teils nur im veralteten Statistik-Typ "track", der aus der Spezifikation entfernt wurde.
  • Performance: getStats() ist asynchron und nicht ganz kostenlos. Fragen im Abstand von 1–2 Sekunden reicht für Monitoring meistens aus.