国产化系统中遇到的视频花屏、卡顿以及延迟问题的记录与总结 |主赛道
1、国产化系统概述
本文中的问题出在国产化 PC 上,所以先来给大家详细介绍一下国产化系统相关的内容。提到国产化系统,一般主要涉及两大块,一块是国产化操作系统,一块是国产化 CPU,这两大块均取得了较大的进展,并涌现了一批国产化厂商。
1.1、国产化操作系统与国产化 CPU
目前主流的国产化操作系统主要有麒麟公司的中标麒麟与银河麒麟系统、统信软件的 UOS 系统等。这些系统厂商均提供了桌面版本和服务器版本的操作系统。这些国产化操作系统均是从 Linux 系统发展而来,本质上均是 Linux 系统。
1.1.1、当前国际上主流的 CPU 架构
当前业界主流的 CPU 架构有 AMD 和 Intel 的 X86 架构、华为海思广泛采用的 ARM 架构、MIPS 架构、开源 RISC-V 架构、还有国产的龙芯 LoogArch 架构等,如下所示:
其中,X86 架构主要占据全球 PC 桌面和服务器领域大部分市场,PC 桌面领域被 Intel 和 AMD 的 CPU 瓜分,服务器领域则大规模使用 Intel 的 i 系列高性能 CPU 和至强服务器专用 CPU。
ARM 公司的 ARM 架构则牢牢称霸移动处理器市场,主流的手机 CPU 厂商高通、华为、三星、联发科等均使用 ARM 架构。
已经终止开源的 MIPS 架构,已不复当年之勇,越来越多厂商都选择拥抱更加开放的开源 RISC-V 架构,甚至连 X86 架构巨头 Intel 和 AMD 都有介入。
龙芯中科(中科院)的国产龙芯 LoogArch 架构,具有完全自主产权,采用龙芯架构的龙芯 CPU 取得了长足的进步,逐步缩短与顶级厂商 Intel 和 AMD 的差距。纯国产龙芯 CPU 的研制成功,实现了复兴号高铁 100%国产化,让国产重型歼击机歼 20 的雷达和北斗导航卫星都装上了中国芯!
1.1.2、当前主流的国产 CPU
当前主流的国产 CPU 有龙芯 CPU(基于国产自研的 LoogArch 架构)、飞腾 CPU(基于 ARM 架构)、兆芯 CPU(基于授权的 X86 架构)以及华为鲲鹏 CPU(基于 ARM 架构)等,这些 CPU 厂商也提供了桌面版本和服务器版本的 CPU。下面给出几个主流国产化 CPU 的信息:
1)龙芯 CPU:早期采用 MIPS 架构,后来自研了 LoogArch 架构,目前最强的一款是龙芯 3A5000 系列,12nm 工艺,早期由意法半导体代工,后来 12nm 的交给台积电代工。
2)飞腾 CPU:采用 ARM 架构,有桌面版,也有服务器版,最新桌面版型号是 D2000 系列,采用 16nm 工艺,由台积电代工。
3)华为鲲鹏 CPU:采用 ARM 架构,主要也用于服务器方面,最新型号是鲲鹏 920,7nm 工艺,由台积电代工。
4)兆芯 CPU:采用 X86 架构,目前最强的是 KX-U6780A 处理器,16nm 工艺,由台积电代工。
5)海光 CPU:采用 X86 架构,主要用于服务器方面,最新的是海光 7000 系列,14nm 工艺,代工方是三星、格芯。
6)申威 CPU:采用 Alpha 架构,后面又自研了 SW 指令集,目前最新的是申威 SW26010 系列,采用 28nm 工艺,主要用于超级计算机,由中芯国际代工。
1.2、国产化服务器操作系统
对于国产化服务器的部署,主要使用内置国产化系统和国产化 CPU 的长城服务器。华为也提供了支持国产化的泰山服务器,该系列服务器主要使用华为自研的欧拉(Eular)服务器操作系统以及华为鲲鹏 CPU(鲲鹏 920)。对于国产化服务器系统,除了麒麟、统信 UOS 和华为欧拉(Eular)系统之外,还可以选择使用腾讯的 TencentOS 系统以及阿里的龙蜥(Annolis)系统。
多年来,大多数 IT 厂商的服务器操作系统都会选择开源免费的 CentOS 系统,但红帽公司之前宣布停止维护 CentOS,这就意味着 CentOS 不再迭代更新,在使用 CentOS 时遇到系统及内核方面的问题时,也不再有团队去维护和解决了。
为了应对 CentOS 停止维护带来的窘境,国内的三大 IT 厂商华为、腾讯和阿里站了出来,相继推出了从开源 Linux 与开源 CentOS 演进而来的国产免费开源的服务器操作系统:华为欧拉(Eular)系统、腾讯 TencentOS 系统和阿里龙蜥(Annolis)系统。这些服务器操作系统在原有的开源系统代码的基础上做了大量的优化与改进,并成立了开源社区,与国内产商一起合作将系统生态发展壮大起来。目前很多 IT 厂商已经将服务器操作系统迁移到这些国产的系统上,比如不少厂商现在都在用华为的欧拉服务器系统。
此外,腾讯牵头,联合国内多家操作系统厂商,成立了 OpenCloudOS 社区,致力于推动国产开源操作系统的发展。
OpenCloudOS 是于成立的 2021 年 12 月 22 日开源操作系统社区开源操作系统社区。该社区由腾讯与合作伙伴共同倡议发起,是完全中立、全面开放、安全稳定、高性能的操作系统及生态。
OpenCloudOS 沉淀了多家厂商在软件和开源生态的优势,继承了腾讯在操作系统和内核层面超过 10 年的技术积累,在云原生、稳定性、性能、硬件支持等方面均有坚实支撑,可以平等全面地支持所有硬件平台。
在国外,为了应对 CentOS 停服,相继推出了两个版本的 Linux 服务器操作系统,一个是 Rocky Linux,一个是 AlmaLinux:
1)Rocky Linux
CentOS 的最初创始人格雷戈里·库尔泽(Gregory Kurtzer),为了实现 CentOS 的最初目标,创立了企业级开源系统 Rocky Linux,同时也是为了向早期 CentOS 的联合创始人洛基·麦高(Rocky McGaugh) 致敬。目前,Rocky Linux 的代码库已经成为 GitHub 上最热门的代码库之一。
2)AlmaLinux
在红帽突然宣布不再维护 CentOS 后,CloudLinux 公司宣布启动替代 CentOS 的 Linux 项目,并随后改名为 AlmaLinux。AlmaLinux 也是一个免费开源的企业级系统,由开源社区维护并管理。
如果大家对这两个系统感兴趣,可以到网上去详细了解一下!
1.3、当前国产化系统的主流配置
当前主流的国产化桌面 PC 主要使用中标麒麟/银河麒麟/UOS 桌面操作系统 + 飞腾 CPU/龙芯 CPU 的方案。
主流的国产化服务器则使用中标麒麟/银河麒麟/UOS/欧拉服务器系统 + 龙芯 CPU/飞腾 CPU/鲲鹏 CPU 的组合方式。其中,鲲鹏 CPU(鲲鹏 920)是华为专用的,不对外开放使用的(只用在华为的产品中),是和华为泰山服务器绑定在一起的。要使用鲲鹏 CPU,则需要购买华为的泰山服务器,服务器中使用的是华为欧拉系统。
对于国产服务器 CPU 而言,通过实测,华为鲲鹏 CPU 的性能要高一些,在一些对性能要求较高的项目中,会选用华为内置鲲鹏 CPU 和欧拉系统的泰山服务器。
其实对于国产化服务器,除了服务器操作系统和 CPU,还有一个基础设施软件,就是数据库。为了更好的自主可控,我们弃用了之前使用最多的 MySQL(虽然 MySQL 免费开源,但受商业公司 Oracle 甲骨文控制,有一定的风险),选用了更加开放的高性能免费开源数据库 PostgreSQL!
2、视频解码花屏与卡顿问题
在国产化桌面 PC 上测试客户端软件时,发现视频解码播放时有明显的花屏问题,这个问题比较严重。当前出问题的国产化桌面 PC 的主要配置为:银河麒麟系统+ 飞腾 CPU + 国产景嘉微显卡(后续问题主要与这个国产景嘉微显卡有关系)。
当前的国产化软件运行在国产化系统中,主要使用开源的 SDL2 去实现视频的绘制渲染,在 Linux 国产化系统平台上,SDL2 内部使用 opengl 去进行渲染。
2.1、视频解码花屏
通过查看打印日志发现,USB 摄像头采集出来的视频图像有明显的丢帧问题,对视频进行解码播放时默认使用强解模式(视频丢帧时不等待 I 帧直接解码播放),因为采集出来的图像有丢帧,所以出现了花屏问题。将当前使用的 USB 摄像头插到 Windows PC 上,使用 amcap 工具查看该摄像头的视频采集参数,发现该摄像头内部采集到图像后会对图像数据进行编码压缩,支持 MJPG 和 H264 两种编码格式,如下所示:
出问题的场景下,使用的是默认的 H264 编码格式,这种编码格式下输出的视频数据有丢帧的问题。
2.2、视频解码卡顿
为了解决这个由视频丢帧引起的花屏问题,将强解模式改成等待 I 帧播放模式。在等 I 帧播放模式中,如果发现视频有丢帧,则不会解码绘制,直到收到新的 I 帧时才会绘制。改成等待 I 帧模式后,虽然没有花屏问题了,但有严重的视频卡顿问题。因为视频有丢帧时,视频图像不再解码显示,直到收到新的 I 帧才会绘制,在这个时间段内始终显示的是之前的图像,收到新的 I 帧才会绘制新的图像,所以导致了该时间段的视频卡顿问题。远端在接收本端发出去的视频数据时发现丢帧,会主动向本端请求 I 帧,但这个请求 I 帧只是临时补救手段,在频繁丢帧时还是会有明显的卡顿问题。
导致视频花屏和卡顿的根本原因,是 USB 摄像头输出的视频有频繁的丢帧导致的,所以要解决这两个问题,还是要从源头(摄像头)上找解决办法。于是尝试将摄像头的视频编码格式改成 MJPG,重新运行后发现该编码格式下输出的图像质量比较好,没有丢帧问题,这样解码播放视频时就不再有花屏、卡顿的问题了。
2.3、关于 I 帧和 P 帧的说明
I 帧是帧内编码,一个 I 帧就是一张完整的图像;P 帧是帧间编码,P 帧中存放的是相对上一帧变化的内容,在绘制每一帧图像时需要将当前的 P 帧和上一次叠加后的完整的图像再叠加,才能形成当前完整的一帧图像(叠加获取完整的视频图像后再去绘制)。每次叠加后的完整图像要保存在内存中,以便收到下一个 P 帧时能叠加出完整的图像。
如果中间有 P 帧丢了,收到下一个 P 帧后可能就无法叠加出完整的图像了,在强制解码的模式下,可能就会出现花屏的问题。对于等待 I 帧模式,视频帧数据接收端发现有丢帧,则停止绘制图像,等收到新的 I 帧才进行绘制。并且视频接收端在发现有视频丢帧时,会主动像视频发送端请求 I 帧,以便能尽快收到 I 帧,尽快将新的图像绘制上去,保持图像播放的连续性。
3、国产显卡处理速度慢导致图像卡顿问题
本来以为上述问题到此就结束了,结果后来经过观察发现,视频图像还是有卡顿问题,而且有明显的延时。
3.1、视频延时和卡顿原因分析
通过打印得知,从接收到视频数据(接收到的是远端编码压缩后的视频数据),到解码绘制完成大概需要好几秒钟,这个延时有点夸张了(对着摄像头挥手就能看出来视频有明显的延时)!通过分析代码发现,延时可能是因为显卡性能不足导致解码绘制速度慢导致的,而视频卡顿可能是由视频丢帧导致的。
那为什么会出现视频帧数据丢失呢?进一步分析代码找到了答案,视频数据处理模块开启了两个线程,一个线程用于接收视频数据帧,收到后放到一个缓冲队列中,另一个线程从缓冲队列中取出视频数据帧(编码压缩后的视频数据),对数据先进行解码,然后将解出的视频数据绘制到视频窗口中(在视频窗口中显示视频),两个线程操作数据队列的效果图如下所示:
因为显卡性能有限,影响到了解码显示的速度(绘制视频图像时底层会用到显卡去渲染绘制),导致处理解码显示的线程速度很慢,同时视频帧接收线程一直在不断地接收数据,而队列长度是有限的(比如存放帧数据的个数上限为 100 多帧,或者缓冲队列的内存是有限的),导致队列中的视频帧数据来不及被处理就被丢弃掉了(丢弃老的视频帧数据,为新的视频帧数据腾出存放空间)。因为有视频帧丢失,当前使用的是等待 I 帧解码模式,导致一小段时间内不再解码播放,直到收到下一帧才播放绘制,所以产生了视频卡顿。
此处是如何知道解码播放线程处理速度慢的呢?其实很简单,添加时间相关打印日志即可看出来。在日志打印系统中,一般每条打印中都会携带时间信息的,方便分析问题,比如方便查看代码执行时长和速度的、快速查看发生异常时间点附近的打印日志等。
3.2、SDL2 库跑在景嘉微国产显卡上效率很低
之前在一个国产项目中也遇到视频解码播放有明显卡顿延迟的问题,当时问题排查了很久,最后怀疑是显卡性能不足导致的。当时的场景是,客户环境中几乎所有的国产化电脑都没问题,但有一台国产化电脑会有这个视频卡顿延时问题。后来客户的国产化电脑提供商主动给客户更换了显卡,就不再有问题的。这台出问题的国产化电脑,之前使用的景嘉微公司的国产显卡,后来换成 AMD 的显卡就没问题了,看来国产的显卡和顶级的 AMD 显卡在性能上还是有明显的差距的!
对于这个视频播放延时卡顿的问题,如果好复现,在公司的测试环境中应该早就暴露出来了(测试人员在测试过程中应该会复现出来),但之前一直没有出过这个问题。通过客户的这个问题案例,我们知道为啥在公司测试环境没有暴露这个问题的原因了,因为我们公司测试环境中之前用的国产化电脑中的显卡都是 AMD 的。而此次我们测试环境中遇到的视频播放延时卡顿问题,是因为这次使用的国产化设备比较特殊,使用的是景嘉微的国产 JM7200 显卡,所以出现了和项目客户一样的问题。
在 Terminal 命令行中使用 lshw 命令即可查看当前国产化机器上使用的显卡信息,具体的命令格式为:Ishw -c display,比如 AMD 的显卡信息如下:
description: VGA compatible controlproduct: Caicos [Radeon HD 6450/7450/8450R5 230 0EM] [1002:6779]vendor: Advanced Micro Devices, Inc. [AMD/ATI] [1002]
景嘉微的显卡信息如下:
description: VGA compatible controllerproduct: JM7200 [731:7200]vendor: JingJla Micro, Inc. [JJM] [731]
对应的景嘉微显卡型号为 JM7200,出问题的这台电脑用的就是景嘉微的显卡,结合之前项目中遇到的类似的情况,基本可以断定是当前用于视频绘制渲染的 SDL2 开源库在景嘉微显卡上运行效率低导致的。
从运行现象上看,应该是开源的 SDL2 在景嘉微国产显卡上运行效率低导致的,可能是景嘉微对 Linux 上的 OpenGL 框架支持不好,或者景嘉微显卡驱动存在问题,或者是景嘉微显卡性能不够,亦或是 SDL2 开源库对国产化显卡的支持不够,具体是哪种原因,后面需要花时间进行研究。也可以将这个问题反馈给景嘉微公司,让他们给分析一下原因!
3.3、采用抽帧播放的方式来解决这类问题
当前的问题是因为解码播放线程处理速度明显慢于视频数据接收线程(慢很多),导致视频帧数据缓冲队列满,导致部分较早收到的、还未来得及处理的视频帧数据从队列中踢出丢弃了:
解码播放线程执行速度慢,是因为景嘉微国产显卡的性能不足导致的。
为了解决当前的视频卡顿延时问题,讨论后决定采用抽帧播放的办法,如果视频帧数据缓冲队列达到某个上限(设定一个阈值,比如 10)时,就开启抽帧播放模式,每收到两帧数据,只播放一帧,降低对显卡处理能力的占用。可以根据测试的效果的去调整这个队列上限阈值,以达到一个比较好的播放效果。但目前这种处理方法只是一种规避的方法,不是根本的解决办法,但对于这类特殊的国产化机器,让他们将显卡更换成非国产的 AMD 显卡似乎也不太现实,也只能使用这种折中的办法。
此外,抽帧播放视频也会有一定的问题,比如视频帧率较低(可能是网络不好导致的)时,比如帧率只有 10 帧,只播放 5 帧视频,也会出现图像不连续卡顿的问题。但这也是没办法的事情,抽帧播放是为了保证视频播放的实时性,实时性比视频卡顿更重要。
3.4、关于音视频播放中的唇音不同步问题
其实还存在另一个问题,即唇音不同步的问题,因为视频播放线程执行的比较慢,音频播放线程执行的很快,导致视频播放速度明显慢于音频播放速度,如果不对音频和视频做同步播放的控制,就可能会出现唇音不同步的问题。
这个唇音同步的问题,在不同的应用场景中关注度是不一样的。比如在视频播放器和直播领域,比较会关注视频和声音,如果出现唇音不同步的问题,看着会很难受,体验会很差,比如我们在看电影视频时,如果唇音不同步,看着会很痛苦。但在视频会议中,更注重的是各个参会方的语音交流,视频关注度不是非常高,即使出现唇音不同步的问题,也是可以忍受的。但如果将会议中的视频录制成视频文件,如果录制的视频中出现唇音不同步,则看着会很难受。
所以在很多播放器中会根据时间戳进行严格的唇音同步控制(开源 FFmpeg 中的 ffplay 播放器就做了唇音同步控制),而在一些音视频软件中不做唇音同步控制,音频和视频来了,就解码播放,一般视频解码播放速度要明显慢于音频解码播放(视频编解码算法及视频播放比音频复杂很多,处理时间要长很多),一般较容易出现唇音不同步的问题。
3.5、国产化芯片的问题
这个问题也显现了国产化显卡芯片(景嘉微显卡)和国外顶级显卡芯片(AMD 显卡)的差距,无论是性能,还是稳定性,亦或是成熟度,应该都有一定的差距。所以,国产化芯片的路还很长!国内目前在芯片领域做的最好的还是华为海思,无论是功能完备性,还是性能,亦或是成熟度,都是国内顶级的存在。
以前音视频应用领域基本都在用华为海思的主控芯片,后来因为被制裁导致华为海思芯片无法生产无法供货,只能转投国内二线厂商,比如寒武纪和瑞芯微,但这些厂商限于技术水平和行业经验,在多个方面和华为海思有着明显的差距,比如稳定性比较差、性能不足、功能完备性不够、处理问题的速度缓慢等,这些我们深有感触。
没办法,没法用到华为海思的芯片,只能和这些二三流厂商一起去优化和改进他们的芯片,这个过程是痛苦的,但从长远来看,对国产芯片的发展是有很大好处的,国产芯片需要大家来支持使用,这样才能持续地进行优化、改进和完善。
4、最后
本文从一个非音视频编解码开发者的角度记录了国产化项目中遇到的视频播放问题,旨在把这些内容作为音视频基础知识和常识来了解,难免会出现不严谨或用词不准确的问题,欢迎大家在评论区批评指正,也欢迎大家在评论区对相关细节进行补充。
我们开发的是音视频相关的业务软件,经常和音视频编解码开发人员打交道,时常和他们一起排查各种与音视频相关的问题及软件崩溃问题,对音视频领域的基础知识和业务流程比较感兴趣,也希望通过与音视频编解码开发同事协同排查问题去接触学习一些音视频相关的知识。
评论