基于软件的TS流多画面合成器的实现

2015-11-07 08:42弓小影
中国科技信息 2015年21期
关键词:线程像素点解码

弓小影 张 超

基于软件的TS流多画面合成器的实现

弓小影 张 超

为了在有限的网络带宽环境下同时进行多路TS视频流远程实时传输,并能在VLC播放器中以单一TS流的形式播放,达到电视墙的效果,提出了基于软件设计的TS流多画面合成的设计方法,该软件使用VS2005(Visual Studio 2005)在Windows平台下开发,但很容易移植到Linux平台,主要从UDP数据接受、TS流过滤、FFMPEG编解码、画面缩放、YUV画面合成、UDP组播、并发处理等多方面系统的论述了设计思想。软件最终经过严格测试,完全符合预期目的,实现了TS流的多源合一和远程实时传输。

多画面合成从视频源的角度分为模拟视频源多画面合成和数字视频源多画面合成,从实现方法角度又可分为硬件多画面合成器和软件多画面合成器。硬件多画面合成器多以模拟视频源为主,主要用于安防和模拟电视监控领域,软件多画面合成多是基于H.323协议的网络IP数字视频源为主,主要在视频会议中应用。目前,在国家大力推动三网融合的政策支持下,数字电视、IPTV业务得到飞速发展,而又由于视频源的限制,传统的多画面合成技术无法应用到数字电视、IPTV监控领域中。为了解决三网融合背景下的信源监控问题,本文提出了基于软件的TS流多画面合成技术,最终通过软件编程完成了产品试制。

本文所指的TS流多画面合成是将通过UDP协议传输的多个TS流视频源合成为一个统一的TS流视频源,再经组播输出,最终在VLC播放器中以多画面形式播放,合成以后形成电视墙的效果,属于用软件方法实现的多源合一数字多画面合成的一种,主要用于数字电视、IPTV、视频会议、视频监控等信源监控领域,由于合成后的画面只占用一个TS流带宽,相当于原流的1/n(n为画面个数),特别适合远程实时传输。输入的TS流信号源可以是SPTS,也可以是MPTS,为了支持两种情况,需要对信号源进行解复用,设置PID过滤器,来实现对单节目的解码。合成以后的TS流只需保留视频部分,音频是不需要的。对信源的解码,画面缩放,以及视频压缩,使用跨平台的多媒体开发库FFMPEG SDK来实现。

系统设计

画面合成技术要求待合成源各帧率相同,在合成过程中,从每个解码后的源各取一幅图像,进行画面合并,因此不同帧率的源是无法合成在一起的。

设计目标

支持单播,组播接收;

支持SPTS和MPTS两种TS流,根据PID列表进行节目过滤;

支持MPEG2,H264的视频解码;

支持H264格式视频编码,并且可调整码率与分辨率;

支持2x2,3x3,4x4等拼接模式的选择;

支持动态源切换,系统启动后,可以随时将某个源替换为别的节目源;

支持编码后的数据组播发送,使VLC正常播放,因为UDP流有最高的实时性;

高可靠性,信号不稳定的源不影响正常的画面合成。

组件设计

画面合成系统主要由UDP接收,视频解码,缩放,画面拼接,视频压缩,UDP发送等主要部分组成(如图1所示)。

FFMPEG本身支持UDP源,但不支持从MPTS中选择一路进行解码,因此需要设计实现UDP接收部分,进行PID过滤,通过FFMPEG的IO回调函数传递进行解码。类似的,UDP发送在FFMPEG也是支持的,但FFMPEG的UDP发送没有流量控制,输出TS流PCR抖动过大,而VLC在播放UDP源时对输入流精度要求很高,PCR抖动过大的TS流在播放时会造成缓冲的上溢或下溢,导致播放卡顿等问题,因此需要设计实现UDP发送来精确控制发送速度。

输入

从单播/组播接收TS数据,根据设置的PID列表进行过滤,输出单节目TS流,FFMPEG正常解码需包含PAT、PMT、PCR、VIDEO四个PID的数据。包含这些PID的TS包都应送入FFMPEG解码器。

FFMPEG编解码

使用FFMPEG SDK进行视频解码,通常TS流

中可能包含MPEG2与H264两种视频类型,FFMPEG对两种视频的解码都支持,并且在代码实现过程中不需要在代码上加以区分,相当于不必关心视频类型,将解复用,视频类型识别,视频解码封装在一个黑盒中,解码完毕后原始图像被输出到YUV缓冲,极大的方便了多媒体开发。

将多个画面进行合成后的原始图像需要进行

压缩编码,合成TS流后进行网络发送。使用FFMPEG进行压缩可以在压缩完毕后直接打包为TS,不需要编码进行容器封装。因此输入FFMPEG编码器的数据为YUV,从编码器输出的数据为TS。在视频类型的选择上,我们使用“高级视频编码”AVC类型。进行AVC视频压缩较MPEG2耗费更多的CPU资源,但有着更高的压缩率。当今CPU的发展,性能已不是限制使用AVC的瓶颈。

画面缩放

由于将多个源视频画面最终合并到一个屏幕

输出,因此需要将解码后的源视频缩放,例如,输出画面大小为704x576,画面拼接模式为2x2,那么每个源画面都要缩放为宽:720/2 = 352,高:576/2=288。YUV缩放通过FFMPEG携带的libswscale库实现。

基于YUV的画面拼接

FFMPEG解码缩放以后的原始图像为YUV数据,因此为了避免多余的数据转换,我们在YUV层进行画面拼接。为了将源图像每像素放置到目标图像的对应位置,我们需要了解YUV图像格式。

数字图像原理

数字图像由三原色:红、绿、蓝组成,即:RGB。每个像素由这三原色的不同取值确定,再由一定数量的像素组成完整图像。以真彩色(24位)为例,每个像素由三个字节表示,三原色各占一个字节,这是RGB格式图像在数据上的表示方式。由于人类对亮度信息更敏感,因此舍弃部分色度信息,在不明显影响图像效果的前提下,极大的降低了占用空间。YUV因此而生,YUV分为三个分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V” 表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。

YUV采样方式

YUV码流的存储格式其实与其采样的方式密切相关,主流的采样方式有三种,YUV4∶4∶4,YUV4∶2∶2,YUV4∶2∶0,FFMPEG解码后的属于YUV4∶2∶0,这里我们需要关注的是如何根据其采样格式来从码流中还原每个像素点的YUV值,正确地还原每个像素点的YUV值。

用三个图来直观地表示采集的方式(如图2所示),以黑点表示采样该像素点的Y分量,以空心圆圈表示采用该像素点的UV分量。

YUV 4∶4∶4采样,每一个Y对应一组UV分量。

图2 YUV采样方式

图3 YV12,YU12格式存储方式

YUV 4∶2∶2采样,每两个Y共用一组UV分量。

YUV 4∶2∶0采样,每四个Y共用一组UV分量。

存储方式

不同格式的YUV存储方式不同,由于我们只用到YUV4∶2∶0格式,下面只给出这种格式的存储方式,并在存储方式后面附有取样每个像素点的YUV数据的方法,其中,Cb、Cr的含义等同于U、V。

(1)YV12,YU12格式(属于YUV420)如图3所示。

YU12和YV12属于YUV420格式,它是一种Plane模式,即打包模式,并不是将YUV数据交错存储,而是先存放所有的Y分量,然后存储所有的U(Cb)分量,最后存储所有的V(Cr)分量,如图3所示。将Y、U、V分量分别打包,依次存储。其每一个像素点的YUV数据提取遵循YUV420格式的提取方式,即4个Y分量共用一组UV。注意,上图中,Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00,其他依次类推。

(2)NV12、NV21(属于YUV420)

NV12和NV21属于YUV420格式,是一种twoplane模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个plane。其提取方式与上一种类似,即Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00(如图4所示)。

FFMPEG解码后的属于第一种Plane模式,这也是最常用的模式。

画面拼接

基于Plane模式,画面拼接时应先由源画面大小、拼接模式确定输出画面大小,然后计算YUV各分量在源、目标画面的位置,最后,将源YUV数据分别拷贝到目标图像的对应行和列。图5表示拼接后各画面关系。

其中,计算画面所占字节数方式为:

画面大小 = ((宽*高*3)>>1)

计算YUV各分量宽高信息:

Y_Width= ImageWidth;

Y_Height= ImageHeight;

U_Width= ImageWidth>>1;

U_Height= ImageHeight>>1;;

计算YUV各分量在画面中的偏移:

图4 NV12、NV21格式存储方式

图5 拼接后画面关系

根据每个源画面所在字画面的位置(所在行与列)计算各分量在目标画面中的偏移:

iYStartDest=Dst_Y_Width*SrcImageHeight*row + Src_Y_Width*col;

iUStartDest=Dst_U_Offset+Dst_U_Width*Src_ U_Height*row + Src_U_Width*col;

iVStartDest = Dst_V_Offset + Dst_V_Width * Src_V_Height*row + Src_V_Width*col;

最后将各分量数据拷贝到目标画面对应偏移地址。

拼接完毕后各YUV各分量间关系,如图6所示。

输出

FFMPEG输出UDP精度问题

FFMPEG的UDP输出没有足够的精度使VLC正常播放。可以使用TS分析工具EasyICE测量FFMPEG输出UDP的PCR精度情况:

使用命令启动FFMPEG进行转码:

ffmpeg -i udp∶//239.0.0.1∶1234 -c∶v h264 -f mpegts udp∶//239.0.0.2∶1234

上面的命令将使FFMPEG从239.0.0.1∶1234接收组播数据,进行转码后发送到239.0.0.2:1234,启动EacyICE从239.0.0.2∶1234接收数据进行分析,可以看出PCR抖动比较大(如图7所示)。

发送速度控制

为了进行精确的UDP推流,需要对发送速度进行控制。避免PCR抖动的关键在于根据TS流中的PCR时间计算出推流时间,使每个TS包都在精确的时刻到达。根据两个PCR包的间隔,可计算出两个PCR之间每个TS包的PCR间隔值:

PCR_Per_Packet = (PCR_Second - PCR_First) / TS_Packet_len

进一步可计算出某个TS包的PCR时间:

PCR=PCR_First+PCR_Per_Packet*Ts_ Packet_Counter

图6 拼接完毕后各YUV各分量间关系

图7 PCR抖动图形

现在我们已经得出每个TS包应该在哪个时刻进行发送,如果时间没到就进行等待。按照这种进行推流,可以得到高精度的推流质量。

在实际的应用过程中,每个TS包并不是单独发送的,为了提高网络利用率,每个UDP包携带若干个TS包,而避免网络包分片,UDP包的大小应小于网卡的MTU大小。在linux,windows,osx等PC、服务器操作系统平台,MTU值默认为1500,嵌入式设备可能较小。我们需要将数据发送到PC或服务器,因此面对的MTU为1500。除去IP头:20字节,UDP头:8字节,剩余1472字节,TS包大小为188,存放完整的TS包可以放7个。即,使用1316字节。剩余156字节不使用。

UDP发送时以7个TS包为单位,按照计算出的PCR时间与系统时间同步后控制发送时机,最终得到满意的效果,VLC播放流畅,日志不再报告丢弃缓冲等错误。使用EasyICE测量输出抖动情况,已经在很小的范围:

整体抖动在10毫秒之内,已经是VLC等解码器能够接受的误差。受网络条件如路由选择,系统条件如计算机时钟精度,网卡延迟等影响,没有误差是不可能的。

并发处理

视频解码,视频压缩等都是比较耗费CPU资源的操作,而我们的系统需要实时处理,必须开展并行计算才能完成。在当今多核或多CPU的系统中,繁忙线程会被分配到空闲CPU核心去完成,充分的利用CPU资源。为此,将各模块依据各自特性及依赖关系,分为多线程进行处理。

UDP源接收,解码,缩放线程

每个解码器有单独的线程,FFMPEG解码器通过读取回调函数接收UDP,因此UDP接收需要采用异步模式。当一幅图像解码出来时,再进行YUV缩放,本线程最终输出的是缩放以后的YUV画面,他将这些画面放入线程安全的缓冲中,以便进行下面的处理

画面拼接,视频压缩线程

从缓冲获取缩放后的YUV画面,送入FFMPEG进行编码。编码产生的数据存入发送缓冲等待发送

图8 合成效果图

图9 cpu占用情况

图10 某个源失效后的合成图

数据发送、流控线程

从缓冲获取待发送数据,根据流控算法进行发送。

核心管理器

为实现动态源切换,适应不稳定的网络源,需要设计核心管理器协调各组件间关系。核心管理器类似Directshow中Grahp的概念,而各组件相当于Filter。

核心管理器主要有以下功能:

协调各组件之间数据传递

协调各组件之间状态的改变,从而支持不稳定的源以及源切换

提供动态源切换接口

由于各解码线程不会在同一时间输出画面,一定有快有慢,为此需要等待YUV缓冲有输出,而考虑到源不一定有效,例如某个源信号异常消失,又不能一直等待。因此需要有条件的等待,检查数据可读条件,有以下两种情况可以进行读取:

(1)YUV缓冲使用量超过门限,例如80%

(2)源可用,并且YUV缓冲不为空。

无论在任何情况下 ,如果某个源YUV缓冲已使用超过80%,则不再等待其他源,此时应到各路源中取画面进行拼接、编码。这种机制保障正常的源输出一定不会延误。第二种机制,如果某个正常解码器还没有画面输出,则进行等待。这种机制保障每个源的画面都不会丢失。

当需要动态切换源时,先将新源准备就绪,然后替换指定源,销毁被替换源解码器,释放资源。

等待新的源解码成功需要一定时间,而且源不一定可用,可能收不到数据,或者其他异常导致无法解码,因此等待新源准备就绪需设置超时时间,不能一直等待。

测试合成效果

以2x2拼接模式为例,使用同一个源模拟四个不同源,首先测试四个源正常情况下的合成效果(如图8所示)。

输入视频类型MPEG2,输出画面大小720x576情况下,Intel i7 CPU占用情况(如图9所示)。

四路MPEG2解码,一路H264实时压缩,整体CPU使用率在30%以下。普通PC机就可以正常部署。

测试某个源失效的情况(如图10所示)。

可以看出正常的源没有受影响,正确输

结束语

本文系统地论述了基于软件实现的TS流多画面合成的技术架构及关键流程,各个组件经过白盒测试工作正常。长时间运行测试及长时间频繁进行动态源切换测试,程序没有内存泄露。为了节省计算量,直接在YUV层进行画面拼接,提高了运行效率,使用并发的开发模式,充分利用CPU资源。对输出TS流根据PCR进行流控,提高了推流精度,弥补了FFMPEG输出UDP抖动过大问题。最终实现了高效率,高可用性,高可靠性的TS流多画面合成系统,可以广泛应用于数字电视、IPTV、视频会议、视频监控,信号源检测等领域。

10.3969/j.issn.1001-8972.2015.21.027

猜你喜欢
线程像素点解码
《解码万吨站》
基于C#线程实验探究
基于局部相似性的特征匹配筛选算法
基于国产化环境的线程池模型研究与实现
解码eUCP2.0
线程池调度对服务器性能影响的研究*
基于像素点筛选的舰船湍流尾迹检测算法
NAD C368解码/放大器一体机
Quad(国都)Vena解码/放大器一体机
基于canvas的前端数据加密