实战排查|为何遮挡推流摄像头,会致使播放绿屏?

前言:作音视频的小伙伴们多少都遇到过奇怪的BUG(如:卡顿、花屏、绿屏、变声等),表象上矛盾点颇多,推理得出的结论都是:“不该该啊!”,最终你抽丝剥茧,发现真相只有一个:“事出反常必有妖”!git

做者:安果,阿里云高级技术专家,从事阿里云 RTC 服务器研发算法

奇怪现象

背景:RTC 互动中增长对 RTMP 的支持,实现 RTC 与 RTMP 相互订阅。服务器

遇到一个奇怪的 BUG,遮挡住 RTC 端的摄像头,有的 RTMP 播放端(iPad air 2,iPad mini 2/4)会偶发绿屏。ide

file

要不先发版?

初步分析问题后,咱们认为这是:一个偶发的终端兼容性问题,有很大几率须要修改 RTC 端的编码来适配,耗时很差评估。工具

“距离发版本的时间不到 2 周,要不就先发版本吧?” 这个请求被产品无情的拒绝了(此次真的感谢大家的坚持),测试也反馈了新的状况:iPhone 6 也出现了绿屏,关闭 RTC 端的摄像头也可能绿屏,Mac 摄像头对着白色墙面也可能绿屏(测试的同窗们也太能折腾了),同时确认了 RTMP 编码 RTMP 播放时相同场景不绿屏。测试

编码仍是封装的坑?

疑难杂症先会诊,同编解码的同窗一块儿讨论完后确认两个可能的点:ui

1.编码的 264 码流不兼容。 2.封装发送的 RTMP 数据不兼容。阿里云

咱们制定了后续的排查方案:编码

1.录制 RTMP 编码和 RTC 编码的码流作对比。 2.使用 FFmpeg 发送 RTC 编码的码流确认是否绿屏。code

1.码流对比

咱们录制了一个完整测试过程当中的码流供编解码同窗分析,经过粗略的对比发现一个重要的区别 vui 中色域相关信息不一致,色域会影响 yuv->rgb 的转换。下图是不绿屏码流的 vui

file

经过这个线索,咱们作了两个验证测试:

1.咱们的 vui 是否会形成黑色显示异常,经过摄像头采集一个黑色手机,在图像中造成大面积黑色。验证结果:正常显示。

2.按照正常码流修改 vui。验证结果:偶发绿屏。

算法的同窗接着作更深刻的分析。

2.封装对比

FFmpeg 发布 RTMP 的示例: ffmpeg -re -i green.h264 -c copy -f flv rtmp://localhost/live/livestream

测试结果:正常显示测试中绿屏的场景。

封装对比结论:封装层问题,编解码的同窗能够休息了(感谢大家一块儿填坑)。

封装填坑记

1.怀疑一切

对于这种黑盒问题,咱们只能抱着怀疑一切的态度,开始各类猜想。

Metadata 排查

背景描述:咱们没有发 Metadata(不是咱们懒,RTC 场景音视频不必定都存在,没有准确的 Metadata),是否是 Metadata 形成的(虽然咱们有本身的答案,Metadata 就算影响也是全局的,怎么会是特定场景,还偶发)。

验证方法:先用 FFmpeg 确认下,不发 Metadata 是否正常,若是正常再加 Metadata。(为何不先加 Metadata?此次是真懒)

ffmpeg -re -i green.h264 -c copy -flvflags no_metadata -f flv rtmp://localhost/live/livestream

验证结果:没有绿屏,一切正常,Metadata 是无辜的。

SPS、PPS 排查

背景描述:RTC 场景 SPS、PPS 是可能变化的(屏幕共享,横竖屏切换等),因此咱们将 SPS、PPS 经过 Sequence Header 和 IDR 帧进行了发送,FFmpeg 在这块多是有区别的。

验证方法:Wireshark 抓包,确认 FFmpeg 只发送了一次 Sequence Header, SPS、PPS 也随 IDR 帧发送(录制码流中 IDR 前都有 SPS、PPS)。按 FFmpeg 的修改进行测试。

验证结果:仍是绿屏,不过几率有所降低。

验证外延:SPS、PPS 全用 Sequence Header 发送,再也不随 IDR 帧发送。

验证结果:仍是绿屏,几率比前一方案更低。

警告:SPS、PPS 全用 Sequence Header 发送,兼容性差,FFplay 有几率播放失败,vlc 没法成功播放。咱们保留了 FFmpeg 相同的作法,继续排查。

2.蛛丝马迹

各类猜想验证都失败了,只好跟测试同窗不断沟通,但愿能够寻找到些许线索,屡次沟通和锁定一个比较有价值的线索:Mac 在关闭摄像头时,RTMP 端播放绿屏几率较高。

定点排查

排查所有转移到 Mac 关闭摄像头这个场景,从埋点数据中确认:Mac 关闭摄像头后, RTMP 发送的视频数量再也不增长。

用 Wireshark 抓包确认关闭摄像头时 Mac 端是否有发送视频包,意外发现不只有视频包,还有一些 seq 不变的视频 Padding 包(有效内容为 0),忽然感受黎明就在前方了,Review 完代码确认 Padding 包影响了组帧逻辑,受 Padding 包影响大部分视频帧被丢弃了,满怀信心的修改完代码。

file

所谓但愿越大,失望越大。绿屏依旧存在,并且严重了不少,屡次测试下来,它成了必现问题,虽然很失望,可是从偶发问题到必现问题也是一个很大的“进步”。

3.黎明以前

最黑暗的时刻,问题终于毕现了,却没了有效的排查手段。

因为 TCP 粘包问题,Wireshark 并不能彻底正确的解析出每个 RTMP 包,没有一个高效的办法查看 RTC 转换的 RTMP 包。

在忘篱同窗的帮助下,经过 SRS 的 srs_rtmp_dump, 将 RTMP 数据保存为了 FLV 文件,具体用法:

#编译
git checkout 3.0release && ./configure --osx --with-librtmp --with-research && make -j8
#保存flv
./objs/research/librtmp/srs_rtmp_dump -r rtmp://127.0.0.1:1935/live/livestream -o output.flv > t.log

经过 FFmpeg 发布 FLV 文件,绿屏问题重现了,莫名的兴奋。

ffmpeg -re -i green.flv -c copy -flvflags no_metadata -f flv rtmp://localhost/live/livestream

虽然知道了 FLV 有问题,但是接下来对于 FLV 的分析却犯难了,首先 FLV 格式分析的结果并无任何问题,用 FFmpeg 抽取出 FLV 中的 264,再发布时也正常。这个 FLV 文件用 FFplay 播放也是有错误信息的。

file

4.完美解决

当你机关用尽,看着代码发呆的时候,休息一下多是个解决问题的好办法。上班的地铁上,终于有了头绪:mark bit、stap,组帧逻辑判断条件,致使了两帧放到了一个 FLV 的 frame 中,形成部分终端不兼容。最终测试经过,版本正常发布,感谢这个过程当中每一位同窗的支持与配合。

总结

  1. 即便 IDR 帧,也能够很小,小到都填不满一个 UDP 包。
  2. SPS、PPS 和很小的 IDR 能够打到一个 STAP 的 RTP 包。
  3. 纯 Padding 包必定认真对待,没有实际数据的枷锁,它们能够作一些灵活的应用。
  4. 多帧封装到一块儿,有兼容性问题。
  5. “事出反常必有妖”,代码没有玄学。
  6. 认真考虑数据的准确性,优先排查两端的数据。
  7. 工具能够显著的提高效率。

福利

SRS 的 srs_flv_parser 中增长了 h264 video frame 中每一个 nalu 的信息打印,但愿对你们之后填坑有所帮助,提早发布预览效果,看看绿屏妖的原形。

file

「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

相关文章
相关标签/搜索