39 个 stats 行中 encoded_fps 集中在 23–32 区间(多数为 31.x),几乎不随 capture_fps 变化:
encoded_fps
capture_fps
即便 capture 跌到 0.3,encoded 仍能维持 8–31;高 capture(55.8)时 encoded 反而只有 31.9。
input channel 容量 = 1:src/state_portal.rs:231
src/state_portal.rs:231
let (input_tx, input_rx) = crossbeam_channel::bounded::<CpuNv12Frame>(1);
bounded(1) 在饱和时 try_send 失败(filler)/ 真实帧阻塞,形成天然节流。
filler 帧固定 ~30fps 节奏:maybe_send_filler_frame 用 frame_interval = 1/fps 推 next_filler_at,与停滞期叠加导致 encoded_fps 稳定在 ~30。
maybe_send_filler_frame
frame_interval = 1/fps
next_filler_at
dedup 命中率高:见 #18,filler 多数被 dedup 跳过——但 record_encode_thread()(src/stats.rs:140)只看进入编码的字节,dedup 跳过的帧不算 encoded_frame。这意味着 encoded_fps 应当低于 filler 频率,但日志显示是 ~30——说明还是有相当部分 filler 进入实际编码。
record_encode_thread()
src/stats.rs:140
encoded_fps=31.7
capture_fps=0.3
encoded_fps 应当反映"实际给到对端可看的独特帧"数量。建议新增:
unique_encoded_fps
delivered_fps
duplicate_frames_skipped
Blocked by: #17 — encoded_fps 钳制诊断需要 stats 数据(frame_bytes_max / output_bps)
frame_bytes_max
output_bps
No dependencies set.
The note is not visible to the blocked user.
现象
39 个 stats 行中
encoded_fps集中在 23–32 区间(多数为 31.x),几乎不随capture_fps变化:即便 capture 跌到 0.3,encoded 仍能维持 8–31;高 capture(55.8)时 encoded 反而只有 31.9。
根因(怀疑)
input channel 容量 = 1:
src/state_portal.rs:231bounded(1) 在饱和时 try_send 失败(filler)/ 真实帧阻塞,形成天然节流。
filler 帧固定 ~30fps 节奏:
maybe_send_filler_frame用frame_interval = 1/fps推next_filler_at,与停滞期叠加导致 encoded_fps 稳定在 ~30。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是冻结画面期望
encoded_fps应当反映"实际给到对端可看的独特帧"数量。建议新增:unique_encoded_fps:去重后实际编码的帧率delivered_fps:成功 write_h264 且非 "skipping non-IDR" 的帧率修复方向
duplicate_frames_skipped)关联
Dependencies
Blocked by: #17 — encoded_fps 钳制诊断需要 stats 数据(
frame_bytes_max/output_bps)