经过一段时间尝试,暂时放弃FFMPEG WHIP,过段时间再回来看吧,它目前阶段有几大致命问题:
- ICE协商机制非常弱,无法正确解析流媒体服务器返回的TURN/STUN服务器信息,如果服务器或客户端在NAT后面,无法正确建立连接。
- 编码只支持H264和OPUS,虽然可以使用Android MediaCodec、Linux VAAPi、Mac VideoToolbox进行硬件编码,但无法支持H265,AV1,VP9就丢失了许多复杂网络自适应性的优势。
- 最大的问题:目前只是一个基础模式,NACK和RTX只是搭了框架还没有实现,在局域网下表现良好,但在5G移动网络下,由于高清视频的大吞吐量导致的丢包和RTP乱序问题,会被流媒体服务器大量丢弃包(否则花屏),几乎不可用。
以下为使用Google WebRTC在5G手机网络下进行WHIP推流一段时间的日志,可见大量丢包和重传:
1 | 2025-11-12 15:36:11.696 16075-16124 MeCastSRV cn.mbstudio.nativewhip D 📡 上传带宽: 2236.78 kbps | 流量:261.55 MB | 丢包=3048 | 重传包=8337 | 平均延时=35.5ms | 分辨率=1280x720 @28.0fps |
作为对比,Google开源的WebRTC实现,在同类硬件、OS和网络条件下,几乎不存在任何质量问题,可以说,WebRTC虽然一直以来没有信令层的标准实现(WHIP算第一个被接受的标准信令层协议)一直被诟病,但其媒体处理和传输设计的确优秀:无论是跨平台的硬件编解码实现的性能(另一个VoIP领域权威的SIP协议,其开源实现例如PJSIP最大问题就是硬件编解码支持的薄弱),提供的行业内最优秀的网络质量保障机制等,这些白手起家撸一套还是很有挑战性的。
而另一个比较早就实现了WHIP的开源MetaRTC,可能研发重心不在移动端,GITHUB仓库里最新的官方android demo直接就存在绿边、变色的问题一直没修复,基于QT的demo也由于代码较老几乎无法编译。
并且metartc开源的代码在Android平台只有C库,官方android demo里用的JNI库的源码直接没找到……可能这也是许多国内开源的一个普遍问题,放出来的开源总会留点尾巴、文档不全,有问题加群、找作者……
这种现象能理解,生态不好剽窃太多作者要恰饭……但也解释了为什么大家不愿意用国产,总是优先用国外开源的原因。
以下为ChatGPT总结的Google WEBRTC相关的理论知识供参考:
🧩 一、WebRTC 的网络质量保障总体架构
WebRTC 的媒体传输协议是 RTP + RTCP + SRTP。
为了应对网络抖动、丢包、延迟,它内置了一套自适应系统:
| 机制 | 功能 | 工作层 | 简述 |
|---|---|---|---|
| NACK | 丢包重传 | RTP 层 | 发现丢包后,向发送端请求重发特定包 |
| PLI / FIR | 关键帧请求 | RTP 控制层 | 解码器无法恢复画面时,请求关键帧 |
| FEC / ULPFEC | 前向纠错 | RTP 层 | 发送额外冗余包用于恢复丢包 |
| BWE(Bandwidth Estimation) | 带宽估计 | RTCP 层 | 动态调整码率、帧率、分辨率 |
| RTX(Retransmission) | 重传通道 | RTP 层 | 与 NACK 配合,用单独的 SSRC 发送重传数据 |
📦 二、NACK(Negative ACKnowledgement)
📘 原理
- 接收端通过 RTP sequence number 检测丢包。
- 一旦检测到缺失包(例如收到 101、102、104 → 缺 103),
它通过 RTCP Generic NACK 包告诉发送端:“我缺第 103 包”。 - 发送端从 缓存的帧缓冲区(RtpPacketHistory)中找到对应 RTP 包,重发一次。
⚙️ 机制特性
- 通常只缓存最近 500ms 的 RTP 包。
- NACK 主要针对视频(关键性强),音频一般不使用。
- 重传过多可能导致 延迟增加或带宽浪费。
✅ 优点
- 在轻微丢包(<10%)的网络中能快速恢复画面。
- 对短时抖动非常有效。
⚠️ 缺点
- 丢包率高或 RTT 大时(>200ms),NACK 恢复延迟明显,甚至无效。
- 需要额外带宽。
🎞 三、PLI(Picture Loss Indication)与 FIR(Full Intra Request)
📘 原理
- 如果解码器检测到无法恢复视频帧(如丢失关键帧),
它会通过 RTCP 发送一个 PLI(Picture Loss Indication)或 FIR(Full Intra Request)。 - 发送端在收到 PLI 后,会立即发送一个关键帧(I-frame)。
⚙️ 区别
- PLI:轻量级,只提示“请发关键帧”。
- FIR:更强制性,用于初始同步或极端错误恢复。
🧮 四、FEC(Forward Error Correction)
📘 原理
发送端为每 N 个媒体包生成冗余包(比如 XOR 码),
即使丢失一个包也能通过 FEC 恢复。WebRTC 支持两种:
- RED (Redundant RTP):冗余包封装
- ULPFEC (Unequal Loss Protection FEC):基于前向纠错算法
✅ 优点
- 能在 无重传情况下 恢复丢包(低延迟)
- 适合 高丢包 / 高 RTT 场景(如移动网络)
⚠️ 缺点
- 增加带宽开销(通常 +15~25%)
- 算法复杂度高
📡 五、RTX(RTP Retransmission)
📘 原理
- 为了防止重传包和正常流混乱,WebRTC 可使用 独立 SSRC 专门发重传包。
- 当接收端发送 NACK 时,发送端从缓存中找出对应 RTP 包,通过 RTX 通道重发。
⚙️ 特征
- 通过
a=ssrc-group:FIDSDP 字段描述。 - 每个轨道(video/audio)都有主流 SSRC 和 RTX SSRC。
- 比直接重传更安全,不会干扰正常帧序列。
📊 六、BWE(Bandwidth Estimation)
📘 原理
WebRTC 通过 RTCP Receiver Report (RR) 中的:
- 丢包率
- RTT(往返时延)
- 抖动值(jitter)
- ACK 间隔时间
来动态估算网络可用带宽。
再通过 Sender Side Bandwidth Estimation (Send Side BWE) 算法调整:
- 视频码率
- 编码质量
- 分辨率(通过 SVC 或 simulcast 降级)
⚙️ 算法模型
主要有:
- Google Congestion Control (GCC)
- Transport-wide Congestion Control (TWCC)
- Delay-based BWE (基于时间延迟推测)
🧰 七、WebRTC 实际应用配置点
| 功能 | 控制方法 |
|---|---|
| 启用 NACK | SDP 中添加 a=rtcp-fb:96 nack |
| 启用 PLI | SDP 中添加 a=rtcp-fb:96 nack pli |
| 启用 FEC | a=rtpmap:116 red/90000、a=rtpmap:117 ulpfec/90000 |
| 启用 RTX | a=rtpmap:98 rtx/90000 和 a=fmtp:98 apt=96 |
| 启用 TWCC | a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 |
✅ 八、总结对比表
| 机制 | 功能 | 优点 | 缺点 |
|---|---|---|---|
| NACK | 丢包重传 | 恢复轻微丢包 | 高 RTT 时无效 |
| PLI/FIR | 请求关键帧 | 快速恢复画面 | 增加瞬时带宽 |
| FEC/ULPFEC | 前向纠错 | 无需重传,实时性好 | 带宽开销大 |
| RTX | 重传通道 | 避免混流 | 增加流数量 |
| BWE/TWCC | 动态带宽控制 | 自适应码率 | 算法复杂 |

