目录linux
时间转瞬即逝,转眼间19年已通过去了,人越来越来老,却不见人心和物质的提高,指望2020年能有一个崭新的本身。git
今年由于发展缘由,从嵌入式跳槽作互联网后端了,干了一年忽然转行,本身也很纠结这么作对不对,但归根结底我只是选择了作本身想作的事情,从事本身想作的工做罢了。github
虽然过来后发现也不并算真正意义上的后端工做,用到的后端技术并很少,主要时间挣扎在了流媒体的开发,音视频的编解码,滤波、硬件加速、rtp、音视频格式(aac、pcm、h264)、另外主管选择了开源的ffmpeg库、这些七七八八的东西够你折磨了。。golang
基于公司项目需求设计流媒体服务器,考虑到扩展性,采用了主流的多进程模型便于后期作分布式,同时解耦业务层与音视频处理层,便于更替音视频处理方案。docker
基于公共协议栈,管理用户登陆、链接音视频服务、用户数据缓存、用户出入音视频服务动态等、迎合docker特色、单独用户数据缓存存储用户数据。windows
主要包括音视频相关内容的开发,也是开发投入时间最长的服务,主要经历了如下过程。后端
1)、最初基于ffmpeg的h264软解实现服务demo.api
2)、而后尝试基于英特尔vaapi硬件加速驱动作h264硬解,对解码视频帧作软件overlay滤波进行音视频合成,再作vaapi硬编码。
优势是此流程软件实现上会更为简洁快速,也比较稳定。
可是后面发现系统会时不时crash。从系统日志上没有找到相关日志,因而进行了长期的软件模块排除法检查问题缘由,作了解码、解码+滤波、滤波+编码等单元模块组挂机测试,仍然没法找到系统crash问题缘由。
同时也在微软的github仓库提交了bug/issue,可是回复较慢。缓存
3)、起初怀疑是vaapi驱动问题,因而尝试使用英特尔qsv硬件加速驱动硬解,对解码视频帧作硬件overlay_qsv滤波进行音视频合成,再作qsv硬编码。
优势是音视频处理全交付于gpu处理,省下大片cpu时间。缺点是硬件帧上下文关系密切,作视频自动切换上,须要作更多软件处理,编码上略微复杂。
惋惜系统crash问题依然存在。服务器
4)、ffmpeg原生工具命令行测试系统crash问题,发现确实有这个问题,并且更换不少个ffmpeg版本都会出现,只是几率可能会有浮动:快的几分钟到几小时crash、慢的一星期可能不会出现,可是不改任何参数再次尝试依然可能crash.
5)、移植音视频服务从linux到windows系统下、通过长期测试windows下运行intel加速方案确实没有系统宕机问题了、同时由于登陆服基于muduo库实现,移植复杂,改将登陆服打包进docker容器运行。
6)、完善及优化音视频服务框架及功能。包括:添加适当rtp缓存解决公网环境udp包波动问题、添加音视频同步机制、增长相应业务功能接口。
7)、移植到微服务框架,进一步加强程序扩展性。
一、建立房间:单机能建立的房间数量是有限的,可是要控制画质流畅不丢帧,瓶颈在于视频合成流数量和硬件性能(核心数越多能够适当下降丢帧率,intel驱动性能瓶颈)、
能够堆音视频服务机器解决这个问题,可是体感性价比并不高。
二、直播房间的增、删、改、查。
三、多路流输入下、可指定流合成数量、或者、自动根据流数量合成。
四、 去除音频回音、单条流的音频开关。
五、 配置视频profile level、 获取帧率、丢包率等。
六、其余。
rtp彻底是本身解的,没有用ffmpeg的avformat库,这样我更便于管理网络处理部分。
须要注意的是udp在公网上可能存在网络抖动问题,服务端接收到的udp包不必定能按序到达,也可能存在丢包等问题,你须要开一块rtp缓存,按seq作最小堆。我直接用的golang的heap包实现的。
而后实际上也能够按相对时间戳来heap的compare,这样也方便你作音视频同步,记录第一个到达的rtp包时间戳、后续rtp的时间戳按timestamp的增量作时钟的换算,换算成一个浮点时间来排序。
例如 h264 90000的时钟 、 30的帧率 、 : 那么 3000时间戳增量 表明 3000 / 90000 = 33.33333ms
而后就是rtp时间的同步 : av_rtp_handler全部rtp包都带了我一个换算出来的相对时间戳的、 我只须要将音视频的包作一次最小堆插入、每次去取堆顶时间戳最小的rtp包便可、 是音频包就丢进音频解码器、视频包就丢进视频解码器。
我想了好久音视频进行合成结构后发现有一个很重要的东西、那就是音视频帧的缓冲区、并且这个缓冲区真的很重要、它能作到如下效果:
一、控制帧率
二、解决多路流的音视频帧抖动问题
一、 经过一个定时器、你能很方便的控制帧率、例如隔33ms往合成器发送一组音视频帧进行合成便可。修改帧率你只须要更改定时器的种子值。
二、消抖、每路流到达的时间确定是不稳定的、可能通道3一会儿除了了5包数据、一会儿来了10帧数据、而其余路还只有1到2帧或者没有、可是你要保持实时性确定不能把全部帧所有保存下来、因此你必须控制每路的缓冲大小得把挤出来的非I帧删掉、注意是非I帧
否则可能会花屏。
而后就是音视频合成、音频用amix、视频用overlay、
视频帧合成麻烦在qsv有一个硬件帧上下文、qsvframecontext
每次作屏幕的自动切换
、或者屏幕位置交换
、须要从新生成filter、而你就须要费工夫去更新这个qsvframecontext
极为麻烦、后面想到的方法是设计一张ffmpeg filter输入的映射
就是在不应ffmpeg滤波器描述符的状况下、而是直接交换filter的输入位置。
一个草图将就下: 至关于 就是打乱正当的输入顺序、作一张映射、这样子不用更改filter的描述符便可作滤波器的切换,要便利极多!
音频合成没什么好说的、就是每路的输出可能不能包含本身的通道声音、否则可能存在回音、你只须要弄个set记录须要合成的流输入id的集合、合成的时候把本身的id去掉再合成就好了。
编码好像没什么重点东西、打包的时候打上个合适的时间戳便可。
今年其实挺累的、第一次一我的从零写了一整套流媒体服务、以及整个系统框架的搭建、最后也学习了主流后端框架、移植到了微服务框架上。虽然作了不少事可是收获也多多。但愿将来能有更好的发展。