安防行业视频播放器的设计

背景

在安防行业工作了n年,基本都是在做播放器相关开发,从公司最初的一代架构,后来的二代架构,再后来的轻量2.5代架构都是核心负责人员,对于安防行业播放器的架构设计有很深的了解。
安防播放器并不需要追求最新的架构和最新的技术,适合自己行业、自己公司特点的才是优秀的。笔者的开发团队长期维持在4~5人,却承载着大量第三方厂商对接、标准测试、多种码流分析、多种私有文件格式解析、高稳定性、各种系统平台支持、正常需求、奇葩需求、新技术预研、奇奇怪怪bug定位等等,有一个易接入、插件式、高稳定、小而精的播放组件是多么的重要。

架构

如下是在二代开始设计时架构图,分为UI和播放库,其中除了UI的桌面客户端、decode filer中的解码插件由其他团队完成,其他都是本组负责。

演变过程

在一代架构开发过程时,公司还是已接入自己公司设备为主,所以架构比较随便,能用就行,但是随之时间发展,公司平台需要接入大量第三方厂商,一代架构有几个致命的缺点:
1、播放库和UI层结合太精密。一代是已ActiveX形式提供的,那么就无法在非windows平台下使用;第三方公司接入也非常不方便。
2、代码耦合高。每次接入一个厂商设备,新增加代码修改必然影响之前流程。每次出版本都冒着影响主流程的风险,测试、开发风险很大。

基于此,开发了二代架构。

二代架构参考了windows的directshow的方式,使用插件式进行接入。每次接入一个厂商,只需要开发对应厂商的source filter、parse filter、decode filter、render filter,然后通过配置可以选择用哪些filter进行连接。

举例1

渲染模式从一开始的ddraw方式,演变出了d3d, 主要原因是在控制云台相机转动时画面在ddraw渲染下会出现锯齿现象。所以新开发了一个d3d_filter.dll ,那么只要在显示设置上选择“d3d模式”,就自动切换为d3d渲染。

举例2

解码自适应。比如播放一些标准视频文件如 avi、mp4等等,我们可以编写一个ffmpeg filter,就自动支持很多文件格式、流格式了。只是性能稍微差一些。

所以只要套上一个漂亮的UI外壳,就可以成为一个万能播放器,即可以播放主流公司、主流格式的码流文件,也可以播放一些小众公司的码流文件。

设计的关键点

1、已dll、so 的形式提供。
2、使用C++98。兼容一些嵌入式设备。
3、能用自研模块,就用自研模块。比如跨平台日志、跨平台多线程、锁、套接字、rtsp、http、mp4解析封装、渲染……
4、能小则小,不依赖第三方库。比如公司设备web客户端插件,使用activex、npapi技术,包括解码等所有组件压缩后不到800K。
5、跨平台。基本支持所有平台。
6、提供32位、64位版本

涉及到的一些知识

信令: 国标、onvif、sip
媒体控制: rtsp、rtmp
流媒体传输协议: rfc3984、 ps over rtp、ts over rtp、es over rtp
本地文件格式: mp4(音频mp3、mp2、aac)
音视频编码格式: mpeg2、mpeg4、h264、h265、g711、g722
解码库: 264、intel media sdk、h265
视频渲染: ddraw、d3d、opengl、sdl、x11
音频渲染: waveout、directsound

新技术

智能
播放器的decode 和 render模块之间增加一个IA filter 就可以变成一个智能播放器了,加入伴线、车牌识别等等智能库。

GPU解码

CPU性能的提升遇到了瓶颈,GPU成了现在的热门。早期2011年左右我在尝试gpu解码,采用的是n卡的cuda库和微软的dxva2,购买了当时最强的桌面显卡GTX470,但实际测试h264的hw解码性能却非常低下。
后来查找了资料了解其实虽然使用了cuda算子,但h264本身的并发性并不强,所以在性能上勉强只能支持4路1080p的hw解码。
接着就是研究intel quick sync video,intel的技术和n卡原理不同,intel的芯片中单独解码单元负责h264的解码,所以性能非常强劲,当时测试16路1080P h264解码,cpu占用率15%左右,但需要消耗2G多的内存。
GPU解码存在一个缺点:显存数据copy到内存性能是非常低下的。

h5播放

1、推模式:flash的rtmp协议模式。无延时,falsh可能被抛弃
2、拉模式:hls 。有延时,兼容性强。
3、webrtc:解码库h264支持不够完美、h265还不支持。

chrome、edge

早期IE 统治下,activeX无疑是首选,后来chrome、firefox崛起,使用npapi,再后来chrome放弃npapi,不知道chrome下如何实现低延时播放?

客户端

web(IPC自带)
C#(国内行业项目首选开发语言)
QT(海外项目)
手机

NAT穿越

1、turn、stun。4种NAT类型
2、端口合一。信令、媒体流都使用一个端口。rtp over http,rtp over rtsp

常见问题

播放卡顿
使用wireshark 抓包分析I、B、P帧间隔。

rtp包乱序
缓存排序

rtp丢包
tcp
kcp
Qos

包分片
rtp 包大小控制在mtu字节以内
tcp 注意tcp粘包,使用’$’同步位

花屏
1、是否存在丢包
2、保存es码流使用elecard 播放,确定是码流问题还是解码库问题

播放锯齿、撕裂
使用d3d模式

ddraw死锁(低概率)
ddraw老bug, ddraw所有函数调用都放置在一个线程中。

资源泄漏、死锁、崩溃、踩内存……
windbg 分析
IDA pro 反汇编,定位第三库bug

性能差
80% cpu是解码、15%是yuv内存copy………..

1、优化解码性能。语言层的优化、算法层的优化
2、优化yuv 内存copy次数。 解码后到渲染表面只进行一次内存复制;多窗口播放1080p视频时可以先缩放再copy。

疑难问题
有几个疑难问题属于三界之外:
1、windows 7 系统下主题更换导致ddraw存在gdi泄漏(超低概率)
2、web端ddraw 低概率出现死锁(超低概率)
3、某些多显卡情况下,播放视频不流畅(某台机器)
4、vista系统长时间播放存在系统性丢包(某个版本操作系统)
5、轮切过程中如果锁屏,会出现黑屏(超低概率)
6、第三方小公司库质量差(大坑),最后变成我们帮他们定位、修改库代码。

总之,wireshark、elecard、模拟发包器(自己写的)、vlc、ffmpeg 、cool edit、windbg这几个神器在手,问题基本都能解决。

衍生出的产品
万能播放器
前面提到过,套上一个UI壳,就是一个漂亮的播放器

SDC(软dc)
soft decode 软dc。 客户端不当只有pc、手机,其实还有电视墙。一般做法是配一个公司的ipc配置一个dc设备用户解码输出信号dvi、vga到电视墙,但是由于安防厂商众多,有的公司不提供linux解码方式,只有windows解码库,所以在这种场景需要SDC。
SDC实际是一台PC主机,安装windows系统,并有3块A卡(A卡支持1卡3输出),所以实际上有9通道输出,输出口为DVi+VGA+DP,安装上万能播放器,再带一个sip协议库,就可以介入公司平台,可以上电视墙。并且支持图像拼接、画中画、漫游、多图层等类似拼接器功能。

IA智能服务器
类似架构开发,将filter更名为engine,支持算法库插件式。

转码服务器
1、使用hw解码库进行转码,从高分辨率转为低分辨率
2、使用第三方sdk解码,然后hw重编码为标准码流

参考的源码
vlc
ffmpeg
sdl
intel media sdk
webrtc

总结
安防的播放器需要满足:
高兼容
跨平台
高稳定
低延时
流畅播放
多通道
高性能
低带宽
足够小
元数据叠加