前言
有个客户在开发教学白板系统时遇到了一个问题,就是采用wifi的方式同屏至少60个学生端时,自己开发的同屏无法满足教学同屏最基本的要求,比如视频画质质量、播放流畅性、马赛克问题等,因此决定将这部分外包给我们开发,本文主要记录了开发该同屏模块的过程。
评估
根据现场实际情况及经验分析,主要存在以下两个问题:
- AP+AC是否能够满足负载60台终端,因为一般的AP+AC是无法负载这么多客户端的,特别是同屏一般采用多播的方式实现,很多AP+AC的设备对多播的配置是有性能限制的
- 无线传输都要遇到的问题,带宽、丢包率高(特别是打算采用多播方式开发时)、延时大、抖动厉害
问题1需要通过调试来确定问题是否确实存在,这个是找华为的工程师现场后台登陆,查看当前运行状态来确定的,命令:display radio all,输出如下:
从上图可以看出,2.4G和5G的CU占用率已经很高了,要么换更高配置的AP+AC,要么针对性的优化该AP+AC(这个得找华为的工程师来专门优化了_)
最终和客户讨论确定,问题1由客户自己找华为来优化。
问题2是无线传输都可能遇到的问题,我们可以针对特定场景做特定的优化。
比如对于同屏系统,一般满足帧率15帧的同屏就可以了,不需要网络电影播放要求的25fps或者30fps,针对这一个现象,我们决定采用基于jpeg的同屏,它相对于通过h264方式的同屏有很多优势:
- 不存在马赛克问题,h264传输如果出现丢包就很容易出现马赛克问题,当然通过增加一些机制也能够基本避免马赛克,不过最终的播放的效果仍然不够理想(画面可能静止)
- 对教师端和学生终端的主机配置性能要求极低,几乎不会占用什么cpu和内存,而如果通过h264方式,对两端的cpu和内存都会有一定的要求,这多少会干扰主程序的资源使用
再比如客户的wifi环境只是单个教师里面的,通过分析发现,主要的无线问题出现在丢包率高上,带宽、延时、抖动通过问题1对应的解决方案可以很大程度上优化掉,几乎对最终的同屏效果不会有什么影响。丢包的问题采用FEC前向纠错可以得到很好的解决。
下面主要对jpeg传送实现以及FEC前向纠错实现进行详细描述。
jpeg传输
jpeg的编码解码采用的是开源的jpeglib库,我们采用的是jpeg-9c,下载下来后,用vs编译即可。使用的时候要特别注意,运行时可能会报版本不匹配的错误,出现这个问题是因为系统可能已经存在jpeg.dll了,而我们编译采用的jpeg头文件和链接dll(链接到系统自带的dll了)的版本不一致。
另外,我们还可以采用libjpeg-turbo库来替换jpeglib,该库是基于jpeglib,内部采用了cpu并行指令对jpeg编解码进行了优化,现在的cpu一般都支持这些并行指令,因此替换后的cpu的使用率会有所降低,jpeg编解码时间也会有所较低。
FEC前向纠错
FEC的方案我们同时测试了几套,比如基于一个朋友开发的fec,该fec库是经过了市场检验的,在各方面都有不错的表现,采用clumsy.exe测试抗丢包能力时,可以很轻松的抵抗30%的丢包。除了基于该朋友的fec库,我们还摸索了开源的fec库,用开源的方案可以为我们省下一笔费用支出_ 因此值得一试。最终我们测试了以下几个fec库:
- feclib
- libcorrect
- openfec
通过测试发现,feclib优点是接口用起来比较方便,缺点是效果很差,只能抗2%的丢包,因此放弃了它。libcorrect没编译过_,放弃了。下面重点说说openfec,虽然它的整体性能比不上朋友的fec,但是却满足了客户的基本需求。
openfec支持以下四种算法:
- LDPC-Staircase codec
- Reed-Solomon GF(256) codec
- 2D parity codec
- LDPC from file codec
其中LDPC-Staircase 和 Reed-Solomon是适合我们jpeg传输的,但是通过测试发现了几个问题,比如Reed-Solomon有2的8次方最大分包限制,LDPC-Staircase虽然没有这个限制,但是存在一定的数据恢复出错情况,也就是在不丢包的时候,本身解码后也会存在部分数据错误(暂时没有去跟踪是什么原因导致的,用自带的demo测试也是一样的结果),因此只能采用Reed-Solomon算法了,得想办法绕过2的8次方限制这个问题,不然当某一帧编码后的数据稍微长一点就可能超过这个限制,这会导致接收端解码直接崩溃。
我们采用绕过的方法是自动拆分编码后的jpeg帧,使每个拆分后的包满足不超过2的8次方限制,这样做降低一点点解码恢复能力,但是因为绝大部分帧是不需要拆分的(大部分帧没有超过2的8次方限制),也就是可以直接单帧传送的,因此对解码恢复没有造成影响。
最后,针对客户的场景,我们还对openfec做了适当的微调,这里就不再详说了。
总结
这个项目的开发虽然只耗时两周,但是这两周积累了不少经验,觉得非常值得!因为很少在windows下开发,在开发前特意研究了vs对项目的布局规划,最终有了如下布局(我觉得比较满意,布局清晰)
├── bin 编译生成文件的位置
│ ├── debug
│ │ ├── 32
│ │ └── 64
│ └── release
│ ├── 32
│ └── 64
├── cli 客户端库源文件路径
├── cliDemo 控制台版本客户端测试程序
├── combianWidthCTest
│ ├── Client c#版本客户端测试程序
│ └── Server c#版本服务端测试程序
├── dependsDLL 额外依赖的dll库路径
├── external 额外依赖的模块路径
│ ├── jpeg-9c
│ ├── libjpeg-turbo
│ └── openfec_v1.4.2
├── lib 编译库生成的文件路径
│ ├── win32
│ └── win64
├── svr 服务端库源文件路径
├── svrDemo 控制台版本服务端测试程序
├── syncScreenSDK 该文件夹是执行pack.bat生成的打包文件夹
│ ├── win32
│ │ ├── bin
│ │ ├── cli
│ │ └── svr
│ └── win64
│ ├── bin
│ ├── cli
│ └── svr
├── temp 编译链接的临时路径
│ ├── compile
│ │ ├── cli
│ │ ├── cliDemo
│ │ ├── svr
│ │ ├── svrDemo
│ │ └── upgrade
│ └── link
│ ├── cli
│ ├── cliDemo
│ ├── svr
│ ├── svrDemo
│ └── upgrade