一种基于多通道视频同步采集的多投影环幕显示系统

2020-10-15 11:01程梦龙姜忠鼎
计算机应用与软件 2020年10期
关键词:缓冲区线程解码

程梦龙 姜忠鼎

(复旦大学上海市数据科学重点实验室 上海 201203) (复旦大学软件学院 上海 201203)

0 引 言

近年来,随着科技水平的提高以及图形技术的进步,虚拟现实得到了快速的发展。虚拟现实使用计算机模拟生成可交互式的虚拟三维场景,向用户提供沉浸式的环境,给人身临其境的感觉[1]。相比于头戴式的虚拟现实头盔,使用多投影或多显示器拼接而成的环幕系统能够支持多人同时交互,并且往往具有更大尺寸、更高分辨率的显示表面,在教育、娱乐和虚拟仿真等领域具有重要的应用价值[2]。

传统环幕系统的画面源与显示环境耦合度较高,外部应用需要修改自身代码才能实现在环幕的显示,环幕系统不具有通用性。本文提出一种基于多通道视频同步采集的多投影环幕显示系统,系统使用视频采集卡对画面源内容进行采集,通过网络传输画面内容到多投影环幕呈现。渲染与显示的分离降低了画面源与环幕的耦合度,提高系统的通用性。

关于使用渲染显示分离的方法降低系统耦合度的思想,目前已有许多相关的研究与应用。Lamberti等[3]在2007年提出基于视频流实现复杂3D图形在移动设备中呈现的方案,使用集群主机渲染复杂3D模型,将渲染画面以MPEG视频流的形式发送给呈现客户端,解决移动端图形处理能力不足的问题。文献[4-5]提出使用远程渲染的方式来实现3D视频在移动设备的呈现,提出基于代理的框架,3D视频流在代理中渲染,然后将渲染画面通过无线网络发送给移动设备显示。文献[6]提出使用远程渲染的方式来保护画面源不被篡改。文献[18]提出使用渲染显示分离的方法实现3D地图在移动设备的呈现。云技术的发展也使得云游戏逐渐变为现实[7],国内外也已有一些云游戏系统,如GamingAnywhere[8]、UBCGaming[9]和文献[10]提出的游戏云等。云游戏的基本思想为:在云端远程运行游戏应用,将渲染画面压缩,以像素流的形式传输给客户端,如手机等;客户端对画面数据进行解码呈现,客户端的交互指令通过网络发送给云端主机,从而模拟本地场景交互。云游戏能够大大降低对客户端的设备性能要求,使得玩家能够随时随地享受高质量的游戏体验[11]。文献[19]提出一种使用分布式渲染的方式来降低系统交互延迟的方案,通过服务器提供的背景图和客户端GPU加速技术对画面进行变形与插值,降低交互延迟,提高云游戏的用户体验。随着5G时代的来临,远端渲染传输的方式会得到更一步的发展与推广。

在本文系统中,画面源以像素流的形式传输至环幕呈现,内容类型与呈现流程无关,因而支持多种类型的画面源,例如视频播放应用、游戏、可视化和VR仿真等。画面源只需提供符合环幕显示规范的输出画面,即可实现在多投影环幕显示系统中的呈现。

本文系统的设计与实现可分为两个模块:多通道视频采集模块与集群显示模块。多通道视频采集模块负责画面采集、压缩与传输;集群显示模块负责画面接收、解码与显示。将一款使用Unity游戏引擎开发的第一人称射击游戏使用本系统进行实验,结果表明本文系统具有可行性与实用性,并且画面延迟较低。

1 多通道视频采集

多通道视频采集包含多通道视频同步采集、视频帧压缩与重组、视频帧传输三个部分。

为了充分利用多核主机的计算性能,降低画面延迟,提高系统的运行效率和数据吞吐量,采集服务器使用多线程来完成多通道视频采集工作。相比于单线程方法,多线程的流水线架构能够提高并发性,降低视频画面从采集到传输的总耗时,从而降低整个系统的画面延迟。

系统启动后,采集模块创建采集线程、压缩线程、重组线程、网络传输线程四种类型的线程,并初始化采集缓冲区、压缩缓冲区、发送缓冲区三种类型的数据缓冲区。多线程之间使用数据缓冲区进行数据的共享,数据缓冲区通过加锁的方式保证多线程访问的互斥性。多线程流程图如图1所示。

图1 多线程流程图

1.1 多通道视频同步采集

多通道视频同步采集包含两个关键步骤:通道视频帧数据的正确读取,多通道视频帧的采集同步。本文系统使用Magewell Pro Capture Quad HDMI Video Capture Card视频采集卡,每个采集卡支持4通道高清视频采集[12],以及Magewell提供的采集卡SDK(MWCaptureSDK 3.3.1.1004)来完成视频帧的读取与同步。为了减少视频帧大小,提高视频帧压缩速度,本文系统使用I420颜色格式采集视频帧。

采集模块启动后创建一个采集线程,采集线程额外创建信号监听线程与视频帧读取线程两个线程,分别负责监听通道状态和从通道读取视频帧数据。

信号监听线程包含以下三个基本步骤:

步骤1使用MWRegisterNotify函数为每个通道注册通知事件hNotifyEvent。当通道状态发生改变时,hNotifyEvent变为Signal状态。

步骤2在线程主循环内使用WaitForMultipleObjects函数等待所有通道的通知事件hNotifyEvent。当某个通道状态发生变化时,使用MWGetNotifyStatus函数获取通知事件的具体类型。

步骤3当通知事件类型包含MWCAP_NOTIFY_VIDEO_FRAME_BUFFERED,即有新的视频帧数据时,设置本通道的待读取状态为True。当所有通道的待读取状态为True时,设置m_dwCapMask为True,表示所有通道数据已准备好。

视频帧读取线程包含以下三个基本步骤:

步骤1使用MWRegisterTimer函数注册定时事件hTimerEvent。每隔一段时间,hTimerEvent变为Signal状态。

步骤2在线程主循环内使用WaitForMultipleObjects函数等待定时事件hTimerEvent。然后判断m_dwCapMask是否为True,即是否所有通道的数据均已准备完成。

步骤3当m_dwCapMask为False时,不执行数据读取等操作,直接等待下一个定时事件。当m_dwCapMask为True时,使用MWCaptureVideoFrameToVirtualAddress函数依次从所有通道读取视频帧数据至指定的内存区域。视频帧读取完成后,为所有通道视频帧赋予相同的帧号,然后将所有通道采集到的视频帧数据放入采集缓冲区等待压缩,最后将m_dwCapMask设置为False。

1.2 视频帧压缩与重组

采集的原始视频帧数据量较大,直接传输会占用较多的带宽。为了减少网络带宽占用,提高视频帧传输效率,对采集的视频帧进行压缩,减少视频帧数据大小。本文系统使用LibJpegTurbo插件[13]对视频帧进行JPEG压缩。

采集模块启动后,创建压缩线程池,压缩线程池中包含与通道数量相同个数的压缩线程。在压缩线程主循环中,从采集缓冲区获取一帧视频帧,对视频帧数据进行压缩得到压缩视频帧,将压缩视频帧数据放入压缩缓冲区等待重组,然后进入下一个获取数据、压缩数据、放入压缩缓冲区循环。压缩视频帧帧号与压缩前的视频帧帧号相同。

为了保证多通道画面显示的同步性,在压缩视频帧传输前需要将多个通道的压缩视频帧重组。重组线程根据帧号将所有通道同一帧号的压缩视频帧打包为重组视频帧,具体重组过程包含以下三个步骤:

步骤1根据采集线程记录的帧号序列,获取下一个等待重组的帧号,称为目标帧号。

步骤2依次从压缩缓冲区中获取各个通道的压缩视频帧队列中对应目标帧号的压缩视频帧。若某个通道的视频帧还未压缩完成,则等待直至收集齐所有通道目标帧号的压缩视频帧。

步骤3将所有通道的压缩视频帧数据拷贝至重组视频帧,重组视频帧的帧号被赋值为目标帧号。将重组视频帧放入重组缓冲区中,等待网络传输线程使用。

图2给出三个通道时的压缩视频帧重组示例,采集线程记录采集的视频帧帧号序列为1、2、3、4等。重组线程首先重组1号帧:从压缩缓冲区中的三个通道的压缩视频帧队列取出帧号为1的压缩视频帧,重组为重组视频帧,然后放入重组缓冲区。2号帧的重组过程与1号帧相同。在重组3号帧时,通道1的压缩视频帧队列没有3号帧,说明通道1的3号帧还未压缩完成,等待直至通道1的3号帧压缩完成,然后对3号帧进行重组。

图2 重组示例

1.3 视频帧传输

若要实现画面在环幕的显示,须将重组视频帧数据发送至集群显示模块,集群显示模块渲染显示画面。为了保证重组视频帧数据的可靠到达,防止丢包带来的异常行为,采集模块与集群显示模块使用TCP完成重组视频帧数据的传输。

网络传输线程负责将重组视频帧发送至集群主节点。网络线程与集群主节点建立TCP连接,在线程主循环内,每次从重组缓冲区取出一帧重组视频帧,发送至集群主节点;若重组缓冲区内无重组视频帧,则线程休眠5秒后再次尝试。采集模块与显示模块传输的数据格式如图3所示。

图3 数据包格式

数据包头部数据包含帧号、宽度、高度和通道数量共四个字段,每个字段均为整数类型,占用4个字节长度。接下来为通道数据列表,每个通道数据项包含通道ID、压缩视频帧数据长度和压缩视频帧内容三个字段。通道ID和压缩视频帧数据长度为整数类型,占用4个字段。压缩视频帧内容为字节数组,占用长度不固定,接收方根据压缩视频帧数据长度字段来确定字节数组的边界。

1.4 数据缓冲区

为了降低线程之间的耦合度,提高数据处理的并发性,采集模块使用生产者-消费者模式[14],多线程之间使用数据缓冲区实现数据的传递。生产者-消费者模式如图4所示,生产者向数据缓冲区存入数据,消费者从数据缓冲区读取数据,数据的存入与读取使用加锁的方式保证同步性与互斥性。

图4 生产者-消费者模式

采集模块中,数据缓冲区包含采集缓冲区、压缩缓冲区和重组缓冲区三种。

对于采集缓冲区,采集线程充当生产者的角色,将所有通道的视频帧放入同一视频帧队列。压缩线程充当消费者的角色,从视频帧队列获取视频帧,对视频帧进行压缩。

对于压缩缓冲区,压缩线程充当生产者的角色,对视频帧进行压缩后,根据视频帧的通道号,将其放入对应的压缩视频帧队列。压缩缓冲区为每个通道分配一个压缩视频帧队列。重组线程充当消费者的角色,从压缩缓冲区的压缩视频帧队列获取所有对应序号的压缩视频帧进行重组。

对于重组缓冲区,重组线程充当生产者角色,对压缩视频帧进行重组后,将重组视频帧数据放入重组视频帧队列。网络传输线程充当消费者的角色,从重组视频帧队列获取重组视频帧,然后发送至集群主节点。

对于采集缓冲区和压缩缓冲区,本文系统能够确保消费者取数据的频率大于等于生产者存数据的频率,因此两者均无容量限制。对于重组缓冲区,其与集群主节点间的网络状况不确定,将其缓存队列容量设为10。当网络传输速率低于重组速率时,需要对部分重组视频帧进行主动丢弃,防止队列溢出。

缓冲区丢弃数据的策略有两种。一是在放入队列前进行检测,若队列已满,则将队列中的已有的数据全部丢弃,放入最新的数据;二是根据消费者反馈选择性丢帧,如每三帧丢弃一帧。第一种方式画面延迟较小,但是可能会出现画面变化幅度较大,画面偶尔不连贯的现象;第二种方式画面看起来比较连贯,但是相对第一种画面延迟会比较高。为了保证较低的画面延迟以及多线程之间的低耦合度,本文选用第一种丢弃策略。

2 集群显示

集群显示模块包包含视频帧接收与转发、解码与显示两个部分。

由于单台主机的输出分辨率有限且不具有扩展性,本文使用集群来搭建多投影环幕显示系统。集群包含一个集群主节点与多个集群从节点,主节点负责保证所有节点状态的同步,每个从节点都是显示节点,负责渲染一块显示区域,所有节点画面通过拼接组成完整的画面。

2.1 视频帧接收与转发

视频帧数据的接收由集群主节点负责。集群主节点创建单独的网络线程,网络线程与采集模块建立TCP网络连接,从采集模块接收重组视频帧数据,两者之间的网络状况影响重组视频帧的接收速率。

集群主节点使用生产者消费者模式,网络线程接收到重组视频帧后,将其放入接收缓冲区。在每帧的Unity主线程的LateUpdate阶段,从接收缓冲区取一帧重组视频帧,然后发送至集群从节点。重组缓冲区的接收队列容量为10,当缓冲区将要溢出时,使用直接丢弃缓冲区内已有数据的丢弃策略,保证具有较低的画面延迟。重组视频帧在集群主节点内部的流向如图5所示。

图5 集群主节点数据流向

集群主节点接收到重组视频帧数据后,需要将数据通过网络转发给所有集群从节点。

TCP为点对点的可靠网络传输协议,能够保证数据的按序可靠到达,TCP传输如图6所示。在数据量为M,从节点数量为N的情况下,主节点需要传输的数据量为M×N。在节点较多时,使用TCP不仅耗时较且多占用很高的网络带宽,系统运行效率较低且不具有可扩展性。

图6 TCP点对点传输

本文使用复旦大学交互式图形学实验室开发的基于可靠多播的集群同步协议,UDP多播传输如图7所示。在数据量为M,从节点为N的情况下,主节点只需传输M的数据量。相比于TCP的点对点,使用集群同步协议能够减少网络带宽占用,提高系统运行效率与可扩展性。

图7 UDP多播传输

2.2 解码与显示

集群从节点应用中包含与通道数量相同的纹理,将接收到的多个通道的画面数据上传至纹理显示。

纹理上传可使用Unity提供的Texture2D.LoadImage函数[15]或者Texture2D.LoadRawTextureData函数[16]将各个通道的画面数据上传至对应的纹理,然而这种方法的纹理数据加载与上传过程均在主线程执行。在上传纹理数量较多或者纹理数据较大时,主线程耗时过多,严重影响系统运行帧率。

本文系统使用Unity提供的多线程渲染技术[17],开发渲染插件NativeRenderingPlugin.dll,在Unity渲染线程中实现纹理上传,从而提高系统帧率。渲染线程中执行纹理上传的操作需要对各个通道的压缩视频帧进行解码操作,并且纹理上传的起始指令只能在Unity主线程中调用。为了提高系统效率以及保证多通道画面显示的同步性,集群从节点额外创建解码线程与纹理上传线程,多线程的流程图如图8所示。

图8 集群从节点多线程流程图

集群从节点的基本行为可分为如下三部分:

1)Unity主线程在LateUpdate阶段,从主节点接收重组视频帧数据,然后将数据放入接收缓冲区。接收缓冲区容量为10,使用前文提到的第一种丢弃策略:在队列已满时将队列清空。

2)从节点在启动后,创建一个解码管理线程和与通道数量相同个数的解码线程,每个解码线程负责一个通道的压缩视频帧解码。主线程每次在LateUpdate阶段接收到重组视频帧数据后,使用信号通知解码管理线程。解码管理线程从接收缓冲区获取一帧重组视频帧,使用信号通知所有解码线程开始解码。解码线程使用LibJpegTurbo插件将其负责的通道压缩视频帧数据解码为RGBA格式的原始视频帧数据,解码完成后使用信号通知解码管理线程。解码管理线程接收到所有解码线程的信号后,表示所有通道的视频帧均已解码完成,使用信号通知纹理上传线程。

3)纹理上传线程接收到信号后,在下一个LateUpdate阶段调用GL.IssuePluginEvent函数开始上传纹理数据。每个通道的数据被用于解码单独的原始视频帧数据,执行独立的纹理上传动作。在Unity中,渲染线程的纹理上传只能够保证在下一帧的相机渲染之前完成,在本帧的相机渲染阶段纹理上传的完成状态难以确保。在一个从节点上,多个通道的原始视频帧同时开始执行纹理上传动作,但不同纹理上传的速度可能不同:在本帧渲染阶段之前上传完成的纹理能够在本帧显示;在本帧渲染阶段之后上传完成的纹理只能够在下一帧显示。因此一个节点内多通道的画面显示可能会有一帧的差异。对于多个从节点,由于纹理上传的开始只发生在LateUpdate阶段,因此在解码能力足够,即解码速率快于接收速率时,从节点之间的显示画面可能会有一至两帧的差异。

经过之前的解码和纹理上传步骤,集群从节点的多幅纹理能够正确显示多个通道的画面。多幅纹理根据画面显示区域排列,根据当前从节点的显示区域配置,使用Unity正交相机获取节点显示画面至RenderTexture,根据投影仪的矫正文件对该RenderTexture进行矫正,最终通过多台投影呈现在环幕表面。图9给出六通道画面显示实例,六幅纹理排列成一排,呈现六个通道的画面数据。在六个通道的画面数据为360度场景且投影有融合区域的情况下,在第六幅纹理后面复制一幅第一幅纹理画面,从而实现首尾的画面相连。然后根据从配置文件读取当前节点的显示区域信息,包含起始位置与显示范围,使用正交相机渲染显示画面至渲染纹理。最后对渲染纹理进行校正,校正后的画面如图10所示。

图9 可视区域画面截取

图10 画面校正结果

3 实 验

3.1 实验系统

本文基于上文描述实现系统并设计两个实验,以验证本文系统的可用性,两个实验的画面源主机与采集服务器配置相同。

画面源主机使用两台NVIDIA Quadro P620显卡,输出六个通道的画面。在画面源主机全屏运行FPS游戏《泰坦英雄》,在六个通道输出360度的画面,每个通道负责60度的画面。画面源主机多通道输出的360度画面如图11所示。

图11 画面源多通道画面

采集服务器使用两台Magewell Pro Capture Quad HDMI Video Capture Card视频采集卡,通过HDMI连接线采集画面源主机输出的六个通道的画面。每个通道的采集分辨率均为1 920×1 080,共11 520×1 080的分辨率,采集目标帧率为60,采集画面格式为I420格式。在对采集到的画面进行JPEG压缩时,压缩质量为85。

3.2 实验一

为了验证本文系统的有效性,实验在复旦大学交互式图形学实验室的环幕环境中运行,该环幕提供120度视角。集群显示模块使用三台主机,包括一台主节点与两台集群从节点,所有主机之间使用千兆网络相连。每台集群从节点连接三台投影仪,显示从30度至150度的输出画面,运行效果如图12所示。

图12 环幕运行效果

表1给出了实验运行过程中各阶段速率的统计数据。

表1 各阶段速率统计表

可以看出,多通道同步采集每秒采集53帧的视频帧数据,压缩、重组和发送速率都能够达到采集速率,说明在采集模块不会发生数据包的丢弃,采集端以每秒53帧的速率向集群模块发送多通道画面数据。在集群模块,集群主节点发送、集群从节点接收和解码的速率与采集模块的速率一致,说明所有的画面数据都被集群从节点接收并解码显示。图13为系统运行过程中的带宽占用变化曲线,图14为系统运行过程中集群画面刷新率变化曲线,系统平均带宽占用为554 Mbit/s,平均画面刷新率为53帧/s。

图13 带宽变化曲线

图14 集群画面刷新率变化曲线

除了画面刷新速率外,画面的延迟也是系统非常重要的评价指标。本文系统中,各个阶段的耗时统计如表2所示。

表2 各阶段耗时统计表

可以看出,系统各个模块的耗时都较短,三个阶段耗时总计47.3 ms,加上采集模块到集群主节点的网络延迟和纹理从上传到显示的平均一帧的延迟,本实验画面平均延迟在80 ms左右。

3.3 实验二

实验使用更多的集群主机数量来模拟本文系统在360度环幕下的运行状况。集群显示模块使用五台主机,包含一台集群主节点与四台集群从节点,所有主机通过千兆网络相连。每台集群从节点连接四个高清显示屏,负责180度的画面渲染,四台从节点共显示两个360度的画面,模拟360度的被动立体环幕。系统运行效果如图15所示。

图15 模拟360度环幕运行效果

表3给出了实验运行过程中各阶段速率的统计数据。

表3 各阶段速率统计表

可以看出,多通道同步采集每秒采集57.4帧的视频帧数据,压缩、合并和发送速率都能够达到采集速率,说明在采集模块不会发生数据包的丢弃,采集端以每秒57.4帧的速率向集群模块发送多通道画面数据。在集群模块,集群主节点发送、集群从节点接收和解码的速率都只为每秒51.2帧,即在集群模块每秒钟转发51.2帧画面的数据,这是由于集群节点间的网络出现波动,导致集群主节点转发重组视频帧的速率低于网络线程接收重组视频帧的速率,从而在集群主节点的接收缓冲区中主动丢弃部分重组视频帧。图16为系统运行过程中的带宽占用变化曲线,图17为系统运行过程中集群画面刷新率变化曲线。系统平均带宽占用为500 Mbit/s,平均画面刷新率为51.2帧/s。

图16 带宽变化曲线

图17 集群画面刷新率变化曲线

除了画面刷新速率外,画面的延迟也是系统非常重要的评价指标。本文系统中,各个阶段的耗时统计如表4所示。

表4 各阶段耗时统计表

可以看出,多通道同步采集到发送、集群从节点接收到上传的耗时与实验一相近,耗时都较短,两个阶段共耗时总计45.1 ms。集群主节点接收到发送的耗时多的原因为集群主节点转发的速率低于网络线程接收重组视频帧的速率,部分视频帧在接收缓冲区中等待了一段时间才被转发,从而导致从接收到发送的平均耗时变长。三个阶段的总耗时为127.0 ms,加上采集模块到集群主节点的网络延迟和纹理从上传到显示的平均1帧的延迟,本实验画面平均延迟在160 ms左右。

4 结 语

本文提出一种基于多通道视频同步采集的多投影环幕显示系统。使用视频采集卡多通道同步采集画面源画面,将画面数据压缩,通过网络传输给集群显示模块。集群主节点接收到画面数据后,使用可靠多播协议将画面数据转发至集群显示节点。显示节点对画面数据进行解码,上传至纹理显示,然后根据显示区域配置,对视角内纹理画面进行变形与矫正,最终通过多台投影机呈现在环幕显示表面。本文系统通过多通道采集的方法降低了画面源与显示环境的耦合度,具有较好的通用性。实验结果表明,本文系统具有很好的通用性,并且系统画面延迟较低。

猜你喜欢
缓冲区线程解码
5G终端模拟系统随机接入过程的设计与实现
实时操作系统mbedOS 互斥量调度机制剖析
浅析体育赛事售票系统错票问题的对策研究
文化解码
解码eUCP2.0
文化 解码
文明 解码
缓冲区溢出漏洞攻击及其对策探析
初涉缓冲区
本期导读