云计算环境中通过混合使用RFB和H.264编码提高虚拟桌面显示质量的方法
技术领域
本发明涉及云计算应用领域,尤其是一种云计算环境中通过混合使用RFB和H.264编码提高虚拟桌面显示质量的方法,其显著特点是服务端根据屏幕内容的更新率动态切换使用RFB或H.264编码方案,将屏幕内容流化发送到客户端,以提高客户端虚拟桌面的屏幕显示质量。
背景技术
虚拟桌面是云计算的一种应用,其特点是应用程序都在服务器上运行,而屏幕显示却在远程的客户端机器上。
在计算机技术中,屏幕所显示的内容来自一个“帧缓冲区(Frame Buffer)”,也可以称作“画面缓冲区”,缩写为FB。在计算机上运行的程序将需要显示的内容写入帧缓冲区,显示器则按每秒25次或30次、即每秒25帧或30帧的速率将帧缓冲区的内容逐个像素地显示在屏幕上。之所以是每秒25帧或30帧,是因为人的视觉在这么高的速率下才能感到画面上显示的动作连贯平滑而且不闪烁。注意屏幕内容的更新速率与帧的速率不是同一回事,即使内容长时间保持不变,显示器仍是按每秒25帧或30帧的速率刷新。
在云计算环境中的虚拟桌面应用中,服务器上运行着多个虚拟机,每个虚拟机对应着一个客户端,运行客户端用户的程序,因此每个虚拟机、也即每个用户都有一个独立的FB。但是具体用户的客户端及其显示器却在远地,所以在远地的客户端上也需要有一个“远地FB”、即RFB,这个RFB中的内容应该从服务端FB复制过来并频繁加以刷新,与服务端FB保持一致。这样,如果在服务器上为用户运行桌面系统,例如Windows,那么用户在远地的客户端上看到的就是一个桌面,好像所面对和操作的客户端就是一个桌面系统一样,所以叫虚拟桌面。但是,对于客户端计算能力的要求却可以比真正的桌面系统大大降低,成为一个很“瘦”的客户端,其成本连同所占用的服务端虚拟机也可以比一台真正的桌面系统低。
但是,要把服务端FB的内容复制到客户端FB中却非易事,倘若按每秒25帧的速率每秒复制25次,屏幕的分辨率为1024x1024,每个象素24位,则所需的带宽为:
25x1024x1024x24=600Mbps=75MB/s
这样的带宽要求,对于现今的网络显然是不现实的,所以必须加以压缩。压缩的方法主要有两类。一类特别适合一般的计算机应用,就是那种屏幕内容相对稳定、较少变化,但是对所显示内容的保真度却要求很高的应用,例如文档的编辑,文字性网页和图表的显示等等。另一类则特别适合“活动画面”的显示,例如电影、电视等等的播放,人类对于活动画面的保真度要求相对较低。
上述的第一类方法就称为RFB,其基本的方法已经标准化成为RFC-6143。其思路是:服务端FB与客户端FB之间的复制必须是高保真的,但是只需要在内容有变化的时候才需要,而且每次都只需要传送所变化的那一部分,不妨称之为Δ复制。进一步,对于变化了的那部分画面内容还可以进行基于像素“跨度(Run-Length)”等方法的无损压缩。这样,尽管客户端的显示器还是按每秒25或30帧的频率刷新屏幕,但是对于客户端FB的内容复制更新的频率却可以很低,占用带宽也可以很小。特别是对于办公一类的应用,人们在屏幕上阅读时很可能好几秒钟才需要变更一下画面的内容,而且每次变更的幅度一般都很小。但是,如果是高清播放电影和视频,情况就不同了,活动图像的更新一般比较频繁,变更的幅度也往往比较大。市面上有许多基于RFC-6143的产品,其牌号名称各不相同,但是所采用的基本技术都是一样的,只是有些产品(如开源软件VNC)采用RFC-6143中所述的CopyRect方法,即每次都通过比对找出画面上那些内容有变化的大小不一的矩形块;有些产品则采用RFC-6143中所述的TRLE方法,把整个画面固定划分成许多矩形的“瓦片(Tile)”,每次刷新那些有变化的瓦片。
在实用中,RFB方法对于屏幕内容相对静止而较少变化的应用效果很好,但是对于电影、电视、动画等活动图像的高清播放就效果不好,因为这些画面的内容变化很快、而且很可能是几乎所有的“瓦片”都在变化,这样一方面可能每一帧都需要传送,另一方面每一帧的传输量都可能很大,这就使得传输过程中实际上必然发生丢包,使显示效果大大下降。因此,RFB不适合电影、电视节目的播放,这对于现下计算机使用者的普遍要求当然很不适应。不仅如此,实际上RFB对于办公类的应用也未必都合适,例如一个网页上有许多图片,如果观看时要在屏幕上左右或上下平移(Pan)画面,这些图片就在一定程度上变成了活动图像,此时的带宽要求也会陡然上升,使效果变差。
上述的第二类方法则是专门用来传送“活动图像(Moving Pictures)”的压缩技术,现下效果最好、压缩比最高的是H.264,所以就以H.264为代表。H.264所能达到的压缩效果很好,但这是利用了人眼对于活动图像的视觉特性而达到的,所以特别适合电影、电视、动画等节目的播放,可是反过来对于静止的图像特别是文字材料的显示就效果不是很好了。这主要表现在两个方面的失真,一是文字的清晰度,二是颜色的保真度。从实际的显示效果看,采用H.264压缩的产品(如VLC)在显示相对静止的图像时常常可以观察到这两种失真,而且这两种失真是紧密相联的。文字清晰度的失真主要在于:大号字体的笔画边沿变得模糊并且往往伴有色调的失真,小号字体的笔画则整体带有色调的失真,这使阅读者的眼睛容易疲劳。在一些以曲线表示的图表上,例如股票走势图上,这种色调的失真就显得尤为突出,也尤为令人不快。
所以,这两类方法的优缺点是互斥互补的,RFB适合阅读文本图表但不适合观看电影电视,而H.264则适合观看电影电视但不适阅读文本图表。目前的虚拟终端、虚拟桌面产品非此即彼,大多采用RFB技术,也有些采用H.264技术,但是总体上都有缺陷,都不能真正使普通用户满意,因为用户难免有时候要观看视频节目,有时候又有办公类的应用。
发明内容
针对现有技术的缺陷,本发明提供了一种云计算环境中通过混合使用RFB和H.264编码提高虚拟桌面显示质量的方法,通过混合使用RFB和H.264编码并根据所显示内容的更新率在两种模式之间动态切换,使屏幕显示的质量和效果得到显著提高。这样,在云计算环境中的虚拟桌面用户就可以像在实体的桌面系统上那样,无论办公或播放高清视频都能得到满意的效果。
本发明解决其技术问题采用的技术方案:这种云计算环境中通过混合使用RFB和H.264编码提高虚拟桌面显示质量的方法,该方法具体步骤如下:
1.1)服务端设有RFB编码器和H.264编码器,分别实现RFB和H.264两种编码方法;
1.2)客户端设有RFB解码器和H.264解码器,分别实现RFB和H.264两种解码方法;
1.3)服务端可任意选择以RFB或H.264编码作为初始的默认编码方法;
1.4)服务端在每一帧的时间里从画面缓冲区FB读取内容,与缓存着的上一帧内容相比对,并计算变动部分的面积在整个画面中所占的比例K;
1.5)如果这个比例K大于某个预定的数值K1,就递增一个计数器N;
1.6)如果这个比例K小于某个预定的小于K1的数值K2,就递减计数器N,但是减到0之后就不再递减;
1.7)服务端按下列规则动态决定当前帧采用何种编码方法:
1.7.1)如果当前编码方法为H.264,则:
1.7.1.1)如果N大于0,就继续按H.264方法编码,将H.264编码器的输出打包发送给客户端,在发送的IP包中带上表示H.264编码的标志;
1.7.1.2)如果N等于0,就切换到按RFB方法编码,切换前先将缓存着的上一帧内容清0,然后将RFB编码器的输出打包发送给客户端,在发送的IP包中带上表示RFB编码的标志;
1.7.2)如果当前编码方法为RFB,则;
1.7.2.1)如果N小于某个预定的值M,就继续按RFB方法编码,包括将变动部分的画面内容复制到缓存的上一帧内容中,并将RFB编码器的输出打包发送给客户端,在发送的IP包中带上表示RFB编码的标志;
1.7.2.2)如果N大于等于M,就切换到按H.264编码,并将当前帧的类型设置成IDR,如果H.264编码器因不能在一帧的时间内完成H.264编码而暂无输出,就暂停打包发送,等到H.264编码器有输出时才恢复打包发送,在发送的IP包中带上表示H.264编码的标志;
1.8)客户端按下列规则根据所接收IP包中的标志确定当前帧的解码方法:
1.8.1)如果所接收IP包中带有表示RFB编码的标志,就按RFB方法解码,并将RFB解码器输出写入本地的画面缓冲区FB;
1.8.2)如果所接收IP包中带有表示H.264编码的标志,就按H.264方法解码,并将H.264解码器输出写入本地的画面缓冲区FB,如果暂无输出就不写。
上述服务端对于动态选用编码方法的决策和切换过程可以归纳成下表所示:
按照上述的方法,如果在一个帧的时间(例如40毫秒)中屏幕内容的更新规模较小,就像在编辑一个文档的时候屏幕更新一般都比较小,就采用RFB,以提高文字的清晰度和颜色的保真度。这里的K就反映着当前帧的更新规模。如果接连出现大规模的内容刷新,就切换到H.264模式,以提高压缩比,避免因为带宽太大而引起的丢包,因为人眼对变动中的图像会降低对于清晰度和颜色保真度的要求,所以感觉不会很明显。这里的计数值N表示连续大规模更新的帧数,当N大于某个预定的值M时,RFB编码方式由于网上丢包而质量明显下降,所以要切换到H.264编码,M的合适数值可以通过实验确定。反之,如果只是偶发的大规模内容刷新,则仍可留在RFB模式,因为这些偶发的超额流量在后面几个帧的时间中可以被吸收,此时N的计数值不会达到M。另一方面,如果已经切换到了H.264模式,而画面内容的更新降了下来甚至停滞了下来,则因计数值N下降到0而又会返回到RFB模式,以提高静止画面的显示质量。
需要说明的是,从RFB编码切换到H.264编码时,H.264编码器可能不会立即就有输出,因为H.264的编码往往不是在一个帧的时间里就能完成。以每秒25帧为例,一个帧的时间是40毫秒,但是按H.264编码一个帧所需的时间可能得要100毫秒以上才行。这就好像一根水管,一开始需要经过一段时间τ才能把这水管灌满,一旦灌满之后只要不断有输入就可不断有水流出,但是从输出端流出的水是时间τ之前就进入这水管输入端的。这样,假定从RFB编码到H.264编码的切换发生在时间T,H.264编码器要经过时间τ、即到了(T+τ)时才有输出,在这段时间中继续发送RFB编码的图像不仅没有意义而且反倒有害,因为那样用户会先看到一些晚于时间T的(质量下降了的)画面,一直到(T+τ),然后往回跳到时间T的画面,这个感觉是很不好的。所以,这时候服务端应该暂停发送,让用户端的屏幕暂时冻结,到了时间(T+τ),H.264编码器有了输出才恢复发送。服务端的编码是这样,客户端的解码也是这样。
相比之下,从H.264编/解码切换到RFB编/解码就没有这个问题,因为RFB编/解码不像H.264那样复杂,所以都比较快,都是在一帧的时间之内就能完成。假定这样的切换发生在时间T,那么虽然H.264编码器的输入在时间T就已被切断,但是此时从H.264编码器输出的其实还是(T-τ)时候的画面,在时间段τ之内H.264编码器仍有输出,那都是在时间T之前就进入了编码器的,所以需要丢弃这些输出,不能让其干扰RFB编码器的输出。
客户端的解码器选择就比较简单,因为选择的依据不同,客户端是根据IP包中所带标志进行选择和切换的。
通过采用这样的方法,本发明的有益效果是:使云计算环境中虚拟桌面的显示质量得以显著提高、并且办公类应用和高清视频播放都能取得满意的效果。
附图说明
图1是本发明的方框示意图。
图中的粗黑虚线表示服务端与客户端之间的网络连接。
服务端有H.264和RFB两个编码器。编码器可以是硬件芯片,也可以是软件模块,还可以是通过DSP、GPU等协处理器实现的模块。一般RFB的算法比较简单,运算量也较小,所以通常采用软件编码,但也不排除采用别的手段。而H.264,则算法比较复杂,运算量相当大,所以采用硬件、DSP、GPU的实现比较常见。但是编码器的实现方式与本发明的实质无关。同样,客户端也有H.264和RFB两个解码器,同样其中H.264解码可以是软件模块,也可以是硬件或DSP、GPU实现。
服务端FB的内容可以用作H.264编码器的输入,也可以用作RFB编码器的输入,图中的选择开关SE1和SE2是联动的,控制着采用哪一个编码器,以及打包发送哪一个编码器的输出。这些开关可以是软件实现的,也可以是硬件的,都受图中“编码方式控制模块”的控制。而编码方式控制模块,则按前述的第1.7条规则进行选择和动态切换。
与此相似,客户端也有联动的选择开关SD1和SD2,控制着采用哪一个解码器、并把哪一个解码器的输出写入客户端FB。这个联动开关受“解码方式控制模块”的控制,根据所接收IP包中所带的标志,按前述的第1.8条规则进行选择。
具体实施方式
下面结合附图和实施例对本发明作进一步说明:
目前采用RFB的虚拟桌面软件和采用H.264的视频播放软件都有不少,作为本发明所述方法的实施用例这里采用开源软件VNC和Ffmpeg。
VNC意为“虚拟网络计算(Virtual Network Computing)”,其实就是虚拟桌面的意思,是采用RFB编解码的。由于RFB编解码比较简单,所以一般都用软件实现。VNC有许多具体实现上略有不同的版本,例如TigerVNC、TightVNC、UltraVNC等等,这里采用基本的VNC版本。基本的VNC又分Unix/Linux和Windows两种版本,这里采用的是vnc-4_1_3-unixsrc。
Ffmpeg其实是个视频播放系统框架,可以采用很多种不同的编/解码方案,具体的编码器/解码器可以是软件的,也可以是硬件的,或者是通过DSP、GPU实现的模块。如果采用H.264编码,并且是软件实现,那么Ffmpeg须与另一个开源软件x264连用,后者的作用相当于一个H.264编码函数库。不管是软件实现还是硬件实现,原理和流程都是一样的,只是这里采用软件方法说明本发明的实施。
VNC和Ffmpeg都是可执行程序,二者都有main()函数。现在要将二者整合在一起,就要有个统一的main()函数,这是容易实现的,例如只要把VNC的main()函数改名为vnc_main(),把Ffmpeg的main()函数改名为ffmpeg_main(),再在统一的main()函数中加以调用,就可以了。当然,如果二者有同名的全局量也要用类似的方法加以区分,二者的命令行界面则要加以合并,这里面也有一定的工作量,但是这些都是从事虚拟桌面和视频播放系统研发的工程师们可以轻松对付的。
VNC和Ffmpeg的编码器都是定时器驱动的,所以各有一个定时器,定时器的周期就是一个帧的时间、即40毫秒。整合以后当然只要一个定时器,所以要去掉其中的一个。此外,二者各自都有网络接口,整合以后也只要一个。这些,当然也是很容易的事。
显然,重要的是各自的编/解码器,即编/解码模块,以及前述编码方式控制和解码方式控制两个模块的实现,这都是在下述服务端实施例和客户端实施例中要用到的。
●VNC的RFB编码模块入口是writeFramebufferUpdate()。
●VNC的RFB解码模块入口是cc.processMsg(),这里的cc是一个CConn对象,代表着客户端与服务端的一个TCP连接,其程序代码在vnc-4_1_3-unixsrc下面的源文件common\rfb\CConnection.cxx中。
●Ffmpeg编码模块的入口是avcodec_encode_video2(),具体的h.264编码器入口则是由x264提供的x264_encoder_encode()。
●Ffmpeg解码模块的入口是avcodec_decode_video2(),具体的h.264解码并不需要由x264提供。
●VNC的代码中有个ComparingUpdateTracker类的对象comparer,这个对象里面的函数compare(),就是用来比对FB内容是否改变的。调用完这个函数之后,再调用其get_changed(),就可以获取一个已改变矩形区域列表。只有这些矩形区域的内容才需要进行RFB编码并打包发送到客户端,另一方面这也可用于计算更新比例K,因为K就是这些矩形区域面积之和与整个FB面积之比。
●VNC的代码中有个抽象类OutStream,就是用来实现网络打包发送模块的,调用其函数setptr()可以设置缓冲区位置,调用其writeBytes()等等函数可以把内容写入缓冲区,调用其函数fluch()
就可以发送。
服务端实施例
在实际应用中,服务端是开在x86架构服务器上的虚拟机,一台虚拟机为一个客户端提供虚拟桌面服务。根据实际需要,虚拟机上可以安装Windows操作系统,也可安装Linux操作系统。实现了本方法所述方法的服务端可以是个Linux应用,也可以是个Windows应用。
如前所述,服务端的运转是定时器驱动的,定时器的周期是一个帧的时间,即40毫秒。每当定时器到点的时候,都会调用一个定时器处理函数,本发明所述方法的服务端部分,包括编码方式控制模块和编码方式的切换,可以一起实现在这个处理函数中,下面是这个函数的伪代码。
这里嵌套的两层if-else语句控制着编码方式的确定和切换,这就构成了示意图中的编码方式控制模块。
伪代码中所调用的H.264编码模块可以是软件,也可以是硬件编码器。如果使用硬件编码器,则从事嵌入式系统研发的硬件/软件工程师应该懂得怎样在ffmpeg中嵌入相应的设备驱动,这是采用硬件编码的系统本来就需要解决的问题,与是否采用本发明所述的方法无关。
注意在将编码方式从RFB切换到H.264时要将当前帧的类型设置成IDR,因为在此之前H.264编码器中是空的,这是开始H.264编码的第一个帧。
与此相对应,在将编码方式从H.264切换到RFB时则要先将用作刷新比较的基准帧、即“先前帧”清成全0,使切换到RFB后的第一个帧为全屏(整个FB)。这是因为,这个帧将成为随后逐次RFB局部刷新的基准和起点,而如果用客户端H.264解码所留下的屏幕内容作为基准和起点,则免不了会有失真,而且这些失真将一直得不到纠正。不过,在VNC中实际上并不需要逐个像素去清0,只要把comparer中的控制变量firstCompare设置成true就可以了,那样在比较的时候就会将整个FB都认定为一个已经改变的矩形区域。
还要注意,如果打包发送模块是从H.264编码模块获取输入,则有可能碰上H.264编码模块没有输出,这就是前面所比喻的水管中还没有灌满水的情况,这种情况下就不打包发送,让客户端的屏幕暂时冻结。函数avcodec_encode_video2()的调用界面为:
int avcodec_encode_video2(AVCodecContext*avctx,AVPacket*avpkt,
const AVFrame*frame,int*got_packet_ptr)
调用时应使这里的指针got_packet_ptr指向调用者提供的一个变量,如果函数返回时这个变量为0,就说明H.264编码模块没有输出。
至于如何在编码所成的IP包头部加上表示编码方式的标志,那对于有能力实施本发明的工程师而言是轻而易举的事。例如,可以定义一种综合的报文(Message)格式,其头部为4个字节,其中一个字节的数值为1表示报文的载荷为RFB编码的数据,为2表示报文的载荷为H.264编码的数据。
客户端实施例
客户端一般是像机顶盒一类的嵌入式系统,客户端采用什么操作系统与服务端无关,一般都是采用开源的Linux操作系统。对于虚拟桌面应用,操作系统上无须安装任何别的应用软件,唯一必须的应用就是虚拟桌面客户端,那就是上述将VNC和ffmpeg整合在一起后所形成的软件,这里面包含了采用RFB和H.264解码的模块,其中的H.264解码也可以是H.264解码过程的硬件或DSP、GPU实现。至于VNC和ffmpeg中有关编码的部分,则可以裁剪掉。
与服务端不同,客户端不是由定时器驱动,而是由网络驱动的,其算法可以描述如下:
这里的if-else语句控制着解码方式的确定和切换,这就构成了示意图中的解码方式控制模块。
这里的“帧”是指服务端打包发送过来的一个显示帧经编码后的内容,实际上是一个传输层的“消息(Message)”,而不是链路层的例如以太网帧。
具体实现的时候,可以采用VNC所提供的TCP网络连接。VNC客户端vncviewer的源码中,在main()函数中有这么几行代码:
while(true){
cc.getInStream()->check(1);
cc.processMsg();
}
这里的cc是一个CConn对象,代表着客户端与服务端的一个TCP连接,cc.getInStream()则代表着这个TCP连接所形成的输入流FdInStream。而check()的作用,则是检查接收缓冲区中是否有数据,如果没有就通过系统调用select()加以等待。这样,当程序从cc.getInStream()->check(1)返回的时候,缓冲区中已经有数据了,下面的cc.processMsg()就是VNC的解码与显示模块。
现在,由于两种编码方式的混用和动态切换,缓冲区中来自服务端的数据不再必定是RFB编码的数据,所以要先检查一下数据的头部,如果是H.264编码的数据就调用由ffmpeg提供的avcodec_decode_video2(),如果是RFB编码的数据才调用VNC自身的cc.processMsg(),所以此时的while循环的伪代码应该是:
变形和推广
作为上述方法的一种变形和推广,也可以把RFB和H.264之间的自动切换改成人工干预切换。方法是:在客户端的键盘上定义两组复合按键,例如‘Fn+F9’表示RFB,‘Fn+F10’表示H.264;用户在阅读文字材料时,如果感到字迹有些模糊,或颜色有点失真,就可以按一下‘Fn+F9’,由客户端向服务端发一个切换到RFB的请求,服务端则根据请求进行切换。反之,用户在观看影视节目时如果感到不流畅,或者屏幕闪烁,就可以按一下‘Fn+F10’,由客户端向服务端发一个切换到H.264的请求,服务端则根据请求进行切换。之所以要分开定义两组复合按键,是因为从按下按键到完成切换会有延迟,分开两组按键,用户才能确信自己所请求的是什么。
此外,这里实施例中用的RFB编解码是原版的VNC,实际上当然也可以用TigerVNC、TightVNC、UltraVNC等等、或者也可以是微软的RDP或其它公司的类似协议和产品;而H.264编解码,当然也不必一定是ffmpeg,而可以是其它的软件包,例如JM18,或者硬件编解码。这些实施细节上的差异并不改变本发明混用RFB和H.264两种编解码方式并根据画面内容更新率动态加以切换的实质。