[stats] encoded_fps 被人工钳制在 ~30,与目标 60 不符且不能反映真实质量 #20

Closed
opened 2026-06-13 23:04:57 +08:00 by dailz · 1 comment
Owner

现象

39 个 stats 行中 encoded_fps 集中在 23–32 区间(多数为 31.x),几乎不随 capture_fps 变化

capture_fps encoded_fps 备注
12.6 29.7 启动
3.9 31.8
2.2 23.9
0.3 9.3 极端低 capture
47.9 31.9 高 capture
55.8 31.9

即便 capture 跌到 0.3,encoded 仍能维持 8–31;高 capture(55.8)时 encoded 反而只有 31.9。

根因(怀疑)

  1. input channel 容量 = 1src/state_portal.rs:231

    let (input_tx, input_rx) = crossbeam_channel::bounded::<CpuNv12Frame>(1);
    

    bounded(1) 在饱和时 try_send 失败(filler)/ 真实帧阻塞,形成天然节流。

  2. filler 帧固定 ~30fps 节奏maybe_send_filler_frameframe_interval = 1/fpsnext_filler_at,与停滞期叠加导致 encoded_fps 稳定在 ~30。

  3. dedup 命中率高:见 #18,filler 多数被 dedup 跳过——但 record_encode_thread()src/stats.rs:140)只看进入编码的字节,dedup 跳过的帧不算 encoded_frame。这意味着 encoded_fps 应当低于 filler 频率,但日志显示是 ~30——说明还是有相当部分 filler 进入实际编码。

影响

  • encoded_fps 这个指标不能反映真实产出质量
  • 调试时看到 encoded_fps=31.7 会误以为"管线基本健康",但实际 capture_fps=0.3 是冻结画面
  • 掩盖 #15、#18 的严重性

期望

encoded_fps 应当反映"实际给到对端可看的独特帧"数量。建议新增:

  • unique_encoded_fps:去重后实际编码的帧率
  • delivered_fps:成功 write_h264 且非 "skipping non-IDR" 的帧率

修复方向

  • 把 dedup 命中数也作为 stats 输出(duplicate_frames_skipped
  • encoded_fps 区分为"含 filler"和"不含 filler"
  • 排查 bounded(1) 是否是节流源(实验改为 bounded(3))

关联

  • #18 filler 浪费的根因之一
  • #17 stats 失真让本指标更难诊断
## 现象 39 个 stats 行中 `encoded_fps` 集中在 23–32 区间(多数为 31.x),**几乎不随 `capture_fps` 变化**: | capture_fps | encoded_fps | 备注 | |---|---|---| | 12.6 | 29.7 | 启动 | | 3.9 | 31.8 | | | 2.2 | 23.9 | | | 0.3 | 9.3 | 极端低 capture | | 47.9 | 31.9 | 高 capture | | 55.8 | 31.9 | | 即便 capture 跌到 0.3,encoded 仍能维持 8–31;高 capture(55.8)时 encoded 反而只有 31.9。 ## 根因(怀疑) 1. **input channel 容量 = 1**:`src/state_portal.rs:231` ```rust let (input_tx, input_rx) = crossbeam_channel::bounded::<CpuNv12Frame>(1); ``` bounded(1) 在饱和时 try_send 失败(filler)/ 真实帧阻塞,形成天然节流。 2. **filler 帧固定 ~30fps 节奏**:`maybe_send_filler_frame` 用 `frame_interval = 1/fps` 推 `next_filler_at`,与停滞期叠加导致 encoded_fps 稳定在 ~30。 3. **dedup 命中率高**:见 #18,filler 多数被 dedup 跳过——但 `record_encode_thread()`(`src/stats.rs:140`)只看进入编码的字节,**dedup 跳过的帧不算 encoded_frame**。这意味着 encoded_fps 应当低于 filler 频率,但日志显示是 ~30——说明还是有相当部分 filler 进入实际编码。 ## 影响 - `encoded_fps` 这个**指标不能反映真实产出质量** - 调试时看到 `encoded_fps=31.7` 会误以为"管线基本健康",但实际 `capture_fps=0.3` 是冻结画面 - 掩盖 #15、#18 的严重性 ## 期望 `encoded_fps` 应当反映"实际给到对端可看的独特帧"数量。建议新增: - `unique_encoded_fps`:去重后实际编码的帧率 - `delivered_fps`:成功 write_h264 且非 "skipping non-IDR" 的帧率 ## 修复方向 - 把 dedup 命中数也作为 stats 输出(`duplicate_frames_skipped`) - encoded_fps 区分为"含 filler"和"不含 filler" - 排查 bounded(1) 是否是节流源(实验改为 bounded(3)) ## 关联 - #18 filler 浪费的根因之一 - #17 stats 失真让本指标更难诊断
dailz added the priority/mediumarea/observabilityarea/pipelinetype/bug labels 2026-06-13 23:04:57 +08:00
Author
Owner

Dependencies

Blocked by: #17 — encoded_fps 钳制诊断需要 stats 数据(frame_bytes_max / output_bps

## Dependencies **Blocked by:** #17 — encoded_fps 钳制诊断需要 stats 数据(`frame_bytes_max` / `output_bps`)
dailz closed this issue 2026-06-21 10:04:42 +08:00
Sign in to join this conversation.