# 解码与丢包恢复 · 花屏了怎么办

> 帧到点解码、渲染；但丢包会让参考链断裂、画面花屏。这一章讲清 VideoDecoder 解码、关键帧作为恢复锚点、PLI 请求关键帧的时机，以及「冻结等关键帧」还是「显示花屏」的取舍。收尾第 6 部分。

- 作者：David（道雾轩）
- 专栏：音视频与 WebRTC 详解（https://daiw.org/manual/webrtc.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/webrtc/video-decode-recovery
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# 解码与丢包恢复 · 花屏了怎么办

接收管线的终点：[到点的帧](https://daiw.org/manual/webrtc/video-timing)交给**解码器**还原成[像素](https://daiw.org/manual/webrtc/video-frame)，渲染到屏幕。顺利时波澜不惊，但网络[丢包](https://daiw.org/manual/webrtc/nack-rtx)会让[参考链断裂](https://daiw.org/manual/webrtc/frame-reference-finder)、画面花屏——**怎么恢复**才是接收侧真正的考验。这一章收尾第 6 部分。

## 解码：压缩帧 → 像素

解码是[编码](https://daiw.org/manual/webrtc/video-encoder-abstraction)的逆，由 **`VideoDecoder`**（和 `VideoEncoder` 对称的抽象）完成：吃一个压缩帧，吐一个 [`VideoFrame`](https://daiw.org/manual/webrtc/video-frame)（I420 像素），交给[渲染](https://daiw.org/manual/webrtc/video-timing)。解码器同样由**工厂**创建、可用**硬件解码**（手机的解码芯片），同样[统一接口、多编解码器实现](https://daiw.org/manual/webrtc/video-encoder-abstraction)。正常流程平淡：[组好的帧](https://daiw.org/manual/webrtc/video-jitter-buffer)→ 解码 → 渲染。真正复杂的是**出了岔子怎么办**。

## 花屏的成因：参考链断了

[帧引用那章](https://daiw.org/manual/webrtc/frame-reference-finder)讲过：[预测帧依赖参考帧](https://daiw.org/manual/webrtc/frame-reference-finder)。丢包毁掉某帧后：

- 依赖它的后续帧**解出来是错的**——参考的内容不对，解码器基于错误的基础“预测”，得到的是**花屏 / 拖影 / 马赛克**。
- 而且**会传染**：错误的帧又被后续帧参考，花屏**一直蔓延**，直到出现一个不依赖任何历史的[关键帧](https://daiw.org/manual/webrtc/frame-reference-finder)“重启”。

所以视频丢包的典型症状，是“**花屏一片，持续一两秒，然后突然一下清晰**”——那“突然清晰”的一刻，就是收到了新[关键帧](https://daiw.org/manual/webrtc/frame-reference-finder)。

## 恢复：请求关键帧

<Callout type="info">
  **丢包让[参考链断裂、无可挽回时，接收端发 [PLI](https://daiw.org/manual/webrtc/rtcp-feedback)（Picture Loss Indication）请求一个[关键帧](https://daiw.org/manual/webrtc/frame-reference-finder)——关键帧自包含、不依赖历史，是重建画面的“锚点”。** 发送端收到 [PLI](https://daiw.org/manual/webrtc/rtcp-feedback)，让[编码器](https://daiw.org/manual/webrtc/video-encoder-abstraction)**立即产一个关键帧**发过来；接收端解出这个关键帧，画面就“接上”了，花屏结束。

  但关键帧的代价不小：它[自包含、编码整幅画面](https://daiw.org/manual/webrtc/video-encoder-abstraction)，**比预测帧大好几倍**——发一个关键帧是一次带宽冲击，还要[切成很多包](https://daiw.org/manual/webrtc/video-packetization)。所以不能一丢包就狂发 PLI：那会导致关键帧满天飞、带宽被吃光、[拥塞](https://daiw.org/manual/webrtc/rate-control)加剧，恶性循环。接收端要**权衡**：能靠[重传](https://daiw.org/manual/webrtc/nack-rtx)补回缺帧就别请求关键帧（重传一个小包，远比一个关键帧便宜）；只有[重传也救不回、参考链彻底断了](https://daiw.org/manual/webrtc/frame-reference-finder)，才发 PLI。这个“能修就修、修不了才重来”的判断，靠[帧引用查找](https://daiw.org/manual/webrtc/frame-reference-finder)提供的依赖信息。
</Callout>

## 更精细的：丢包通知 LNTF

除了“请求整个关键帧”这种重手段，还有更精细的机制 **LNTF（Loss Notification）**：接收端告诉发送端“我具体丢了哪一帧”，发送端可以选择**从一个仍可用的旧帧预测**新帧（而非发昂贵的关键帧），让损失更小地恢复。这是“介于[重传](https://daiw.org/manual/webrtc/nack-rtx)和关键帧之间”的中间手段，在支持的[编解码器](https://daiw.org/manual/webrtc/video-encoder-abstraction)上能更省带宽地恢复。

## 取舍：冻结还是花屏

丢包恢复期间，接收端还有个**显示策略**的取舍：

<Callout type="warn">
  **参考链断了、新帧解出来是花的，该显示“花屏”还是“冻住上一个好帧”？** 两种选择：

  - **显示花屏** —— 忠实显示解码结果，但花屏很难看、甚至引起不适。
  - **冻结（freeze）** —— 停在最后一个正确的帧，等[关键帧](https://daiw.org/manual/webrtc/frame-reference-finder)来了再更新。画面“卡住”一下，但**比花屏观感好**。

  WebRTC 通常选**冻结**——宁可短暂卡住，也不显示花屏。用户对“卡一下再恢复”的容忍度，远高于“满屏马赛克”。所以你视频通话时看到的“画面卡住几百毫秒然后恢复”，正是接收端在**冻结等关键帧**。这又是一个[实时媒体“两害相权取其轻”](https://daiw.org/manual/webrtc/video-jitter-buffer)的工程决策：完美不可得时，选那个**用户最不反感**的降级方式。
</Callout>

## 小结与第 6 部分回顾

**解码**由 [`VideoDecoder`](https://daiw.org/manual/webrtc/video-encoder-abstraction)（可硬件）把压缩帧还原成[像素](https://daiw.org/manual/webrtc/video-frame)渲染。[丢包毁掉参考帧](https://daiw.org/manual/webrtc/frame-reference-finder)会导致**花屏蔓延**，恢复靠**请求[关键帧](https://daiw.org/manual/webrtc/frame-reference-finder)**（[PLI](https://daiw.org/manual/webrtc/rtcp-feedback)，自包含锚点，但大而贵，故[能重传就别请求](https://daiw.org/manual/webrtc/nack-rtx)）或更精细的 **LNTF**。显示策略上，WebRTC 通常**冻结**（卡一下）而非显示花屏——观感更好。

**第 6 部分「视频管线」到此完整**：发送侧[总览](https://daiw.org/manual/webrtc/video-pipeline-overview)→[帧](https://daiw.org/manual/webrtc/video-frame)→[采集编码入口](https://daiw.org/manual/webrtc/video-source-encoder)→[编码器](https://daiw.org/manual/webrtc/video-encoder-abstraction)→[自适应](https://daiw.org/manual/webrtc/video-adaptation)→[联播SVC](https://daiw.org/manual/webrtc/simulcast-svc)→[码率分配](https://daiw.org/manual/webrtc/video-bitrate-allocation)→[打包](https://daiw.org/manual/webrtc/video-packetization)；接收侧[抖动缓冲组帧](https://daiw.org/manual/webrtc/video-jitter-buffer)→[帧引用](https://daiw.org/manual/webrtc/frame-reference-finder)→[渲染时机](https://daiw.org/manual/webrtc/video-timing)→解码恢复。视频从摄像头到屏幕的全程，已经拆透。

视频讲完，**音频**是另一片天地——它有自己独特的挑战（丢包隐藏、回声消除）。第 7 部分进入音频管线，尤其 **NetEq** 和 **AEC3**，是 WebRTC 音频的两颗明珠。👉 第 7 部分即将展开。

## 参考资料

- [1] libwebrtc 源码.`api/video_codecs/video_decoder.h`、`video/`（解码调度）、`modules/video_coding/`（loss notification）。
- [2] libwebrtc 源码.`modules/rtp_rtcp/source/rtcp_packet/pli.h`（PLI）、loss notification 相关。
- [3] 关联[帧引用](https://daiw.org/manual/webrtc/frame-reference-finder)、[NACK 重传](https://daiw.org/manual/webrtc/nack-rtx)。
