• 教学同屏系统开发


    前言

    有个客户在开发教学白板系统时遇到了一个问题,就是采用wifi的方式同屏至少60个学生端时,自己开发的同屏无法满足教学同屏最基本的要求,比如视频画质质量、播放流畅性、马赛克问题等,因此决定将这部分外包给我们开发,本文主要记录了开发该同屏模块的过程。

    评估

    根据现场实际情况及经验分析,主要存在以下两个问题:

    • AP+AC是否能够满足负载60台终端,因为一般的AP+AC是无法负载这么多客户端的,特别是同屏一般采用多播的方式实现,很多AP+AC的设备对多播的配置是有性能限制的
    • 无线传输都要遇到的问题,带宽、丢包率高(特别是打算采用多播方式开发时)、延时大、抖动厉害

    问题1需要通过调试来确定问题是否确实存在,这个是找华为的工程师现场后台登陆,查看当前运行状态来确定的,命令:display radio all,输出如下:
    AC后台运行状态图

    从上图可以看出,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优点是接口用起来比较方便,缺点是效果很差,只能抗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

  • 相关阅读:
    UML类关系:依赖、关联、聚合、组合(收藏)
    java常用设计模式八:代理模式
    java常用设计模式三:原型模式
    java常用设计模式总览
    java常用设计模式七:装饰模式
    java常用设计模式六:适配器模式
    Sword C语言原子操作
    C语言 宽字符串
    C语言 字符串切割
    C语言 sscanf函数补充
  • 原文地址:https://www.cnblogs.com/rongpmcu/p/10350702.html
Copyright © 2020-2023  润新知