共计 2961 个字符,预计需要花费 8 分钟才能阅读完成。
前言:做音视频的小伙伴们多少都遇到过奇怪的 BUG(如:卡顿、花屏、绿屏、变声等),表象上矛盾点颇多,推理得出的论断都是:“不应该啊!”,最终你抽丝剥茧,发现假相只有一个:“事出反常必有妖”!
作者:安果,阿里云高级技术专家,从事阿里云 RTC 服务器研发
奇怪景象
背景:RTC 互动中减少对 RTMP 的反对,实现 RTC 与 RTMP 互相订阅。
遇到一个奇怪的 BUG,遮挡住 RTC 端的摄像头,有的 RTMP 播放端(iPad air 2,iPad mini 2/4)会偶发绿屏。
要不先发版?
初步剖析问题后,咱们认为这是:一个偶发的终端兼容性问题,有很大概率须要批改 RTC 端的编码来适配,耗时不好评估。
“间隔发版本的工夫不到 2 周,要不就先发版本吧?”这个申请被产品有情的回绝了(这次真的感激你们的保持),测试也反馈了新的状况:iPhone 6 也呈现了绿屏,敞开 RTC 端的摄像头也可能绿屏,Mac 摄像头对着红色墙面也可能绿屏(测试的同学们也太能折腾了),同时确认了 RTMP 编码 RTMP 播放时雷同场景不绿屏。
编码还是封装的坑?
疑难杂症先会诊,同编解码的同学一起探讨完后确认两个可能的点:
1. 编码的 264 码流不兼容。
2. 封装发送的 RTMP 数据不兼容。
咱们制订了后续的排查计划:
1. 录制 RTMP 编码和 RTC 编码的码流做比照。
2. 应用 FFmpeg 发送 RTC 编码的码流确认是否绿屏。
1. 码流比照
咱们录制了一个残缺测试过程中的码流供编解码同学剖析,通过粗略的比照发现一个重要的区别 vui 中色域相干信息不统一,色域会影响 yuv->rgb 的转换。下图是不绿屏码流的 vui
通过这个线索,咱们做了两个验证测试:
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 包影响大部分视频帧被抛弃了,满怀信心的批改完代码。
所谓心愿越大,悲观越大。绿屏仍旧存在,而且重大了很多,屡次测试下来,它成了必现问题,尽管很悲观,然而从偶发问题到必现问题也是一个很大的“提高”。
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 播放也是有错误信息的。
4. 完满解决
当你机关用尽,看着代码发愣的时候,劳动一下可能是个解决问题的好方法。下班的地铁上,终于有了脉络:mark bit、stap,组帧逻辑判断条件,导致了两帧放到了一个 FLV 的 frame 中,造成局部终端不兼容。最终测试通过,版本失常公布,感激这个过程中每一位同学的反对与配合。
总结
- 即便 IDR 帧,也能够很小,小到都填不满一个 UDP 包。
- SPS、PPS 和很小的 IDR 能够打到一个 STAP 的 RTP 包。
- 纯 Padding 包肯定认真对待,没有理论数据的桎梏,它们能够做一些灵便的利用。
- 多帧封装到一起,有兼容性问题。
- “事出反常必有妖”,代码没有玄学。
- 认真思考数据的准确性,优先排查两端的数据。
- 工具能够显著的晋升效率。
福利
SRS 的 srs_flv_parser 中减少了 h264 video frame 中每个 nalu 的信息打印,心愿对大家当前填坑有所帮忙,提前公布预览成果,看看绿屏妖的原形。
「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实际技术文章,在这里与音视频畛域一流工程师交换切磋。