AI写的投屏代码 导致花屏一路排查的心路历程

5 阅读3分钟

背景

Hub 已切到新协议(601–609)+ KMFUTranLib DataBridge 投屏。链路大致是:

MirrorCaptureCoordinator → ScreenCaptureEncoder → MirrorSenderController → MirrorVideoSendPump → USB/asyncWriteData → Win 解码回显

表面现象都是「Win 端花屏」,但根因并不止一种。早期容易把「采集没对齐 Line」「USB 坏了」「解码器问题」混在一起。


第一阶段:先对齐 Line,再谈花屏

最初方向是:Hub 自研采集是否该更像 Line。

  • 结论是:协议不动;真正差在采集策略,不是 protocol 包。
  • 做法是把硬编码 LINE_MATCH_ENCODER 做成调试开关(HubSettings + Debug 页),默认开,方便 A/B。
  • 同时明确:不整段移植 Line RecordService,帧出口仍走 Hub 新协议。

这一步解决的是「行为可控可比」,还没直接钉死花屏根因。


第二阶段:用 dump 分层,先排除「传输损坏」

花屏出现后,没有先改代码,而是把链路切成可回放的切片:

落盘含义
*_encoder_out.h264MediaCodec 刚读出
*_android_h264.h264入队发往 Win 成功
*_pre/post_chunk.h264USB 切片前/后
Win 侧 *_win_h264.h264对端收到

对照后先排除了两类误判:

  1. USB 分包损坏 — 切片前后一致、USB_WRITE_FAIL 基本为 0
  2. DataBridge sync/async 写模式本身 — 不是主因

也澄清了几个「假象」:

  • encoder_out 单独播可能缺 SPS,看起来「坏」,不等于编码出口真坏
  • PotPlayer 竖窗横条,有时是多分辨率拼进同一文件 + 转屏 mid-stream SPS,属于播放假象,不等于当场花屏机制

方法论上的转折点:花屏要对齐「同一会话、同一时间窗」的多层 dump + 日志,而不是只看 Win 画面。


第三阶段:发现其实是两类花屏

A. 结构性花屏(缺 SPS / 过小首 I)

样本 20260914_135559 一带:

  • 前 2MB 没有 SPS/PPS
  • 首枚 IDR 只有约 2KB(正常常是几十~上百 KB)
  • 随后一串极小 P 帧

关键认知纠正:

  • Line 也是「编码器吐什么发什么」,不会手动拼 SPS/PPS
  • Hub 在 LINE_MATCH=开 时其实已经从 MediaFormat 缓存了 csd,但故意不拼到 I 帧前
  • 一旦编码器先吐出「无参数集 + 过小 KEY」,就会把坏参考直送 Win,花到下一枚正常 IDR

对应修复思路(已合入 LINE_MATCH 补丁方向):

  • 首 KEY 前 prepend csd(SPS/PPS)
  • 挡住过小首 I(如 <4KB)

B. 丢帧型花屏(巨 P / 中途静默丢 P)

样本 _blur_1612 一带更关键:

  • encoder_out 清晰
  • android_h264 花
  • 对帧发现少了若干 P,日志里 paceDrop 次数对得上

根因不是编码坏了,而是发送侧 shouldPaceDrop 静默丢掉中途 P(不断 I):

  • 参考链断了 → 解码器宏块 conceal → 看起来像花屏
  • 表现很像「传输花了」,但 dump 证明:坏在 Android 入队前就被策略丢掉了

对应修复:

  • ENABLE_USB_WRITE_PACE_DROP = false
  • 真积压仍走「清队 + 催 I」,不再静默丢中途 P

另:转屏曾试验过严格 hold(ORIENTATION_STRICT_HOLD),后为对齐 Line 又改回 false(简单开推)。


第四阶段:收口成可提测版本

调试手段(多层 dump、AgentDebugNdjson、KMFU debug、巨 P/USB_WRITE 刷屏日志)在定位阶段很有用,但会干扰提测:

  • 全部默认关掉
  • 默认仍 lineMatch=true
  • 打出 1.0.32 release 包给同事测稳态花屏 + 横竖屏切换

心路历程一句话

先以为是「没对齐 Line / USB 坏了」→ dump 证明传输大体健康 → 再拆成「参数集/首 I 结构问题」和「策略静默丢 P」两条线 → 用 encoder vs android_h264 对帧把后者坐实 → 关掉 paceDrop,并给 LINE_MATCH 补上必要的 SPS/小 I 防护 → 清调试后出提测包。


经验沉淀(以后再遇花屏可直接用)

  1. 先分层 dump,再改策略;不要一上来调码率/协议。
  2. encoder 清晰、android_h264 花 → 优先查发送队列丢帧(尤其 paceDrop)。
  3. 本机播 android_h264 就花/解不开 → 优先查 SPS/PPS 与首 KEY 体积。
  4. Win 独花、Android dump 正常 → 再对 Win dump / 解码侧。
  5. 转屏花屏要单独看:mid-stream SPS + 分辨率切换,别和稳态丢 P 混为一谈。