庞赫
【摘要】 计算机屏幕图像的截取在屏幕录制、计算机远程控制以及多媒体教学软件中都是关键术。研究的重点集中在如何快速有效的截取DIB(Device-Independent Bitmap)格式的屏幕图形数据。本文采用一种高性能屏幕截取技术,实现了基于Windows图形驱动截图的远程控制系统。
【关键词】 屏幕录制 远程控制 屏幕截取
一、远程控制系统的系统设计
1.1 系统分析
在视频会议系统中,共享桌面的客户端,获取本地屏幕或者其中特定窗口以及固定区域的图像变化数据,编码压缩,传输到服务器端,由服务器端将该数据分发到个个接收端。接收端解码图像数据,即可观看到共享桌面。图像的数据量很大,为了达到发送获取压缩,接收解压播放的高性能,该部分的编码采用非托管实现。整个视频会议系统是.NET平台下,所以该部分代码采用组件开发模型[1],方便系统的调用也符合软件开发的N层构架的要求[2]。
1.2系统结构设计
图1 客户端与服务器的C/S构架模型
在C/S模式构架的程序中,客户端的所有交互都是通过服务器的中转完成。共享桌面的客户端在开启共享之后。桌面的图像数据经过编码压缩会发送到服务器端,经过服务器的分发,图像数据会被分发到N-1个客户端,这就要求服务器有足够的上行和下行带宽。客户端接收到屏幕图像数据,经过解码解压播放图像数据,根据实际的网络状况可能会有不同程度的延时。共享桌面的客户端(一般为教师机器),可以指定一个控制端,开启远程控制。被授权的客户端会把包括鼠标坐标,鼠标键的点击弹起,键盘按键的点击和弹起消息进行封装,经服务器传送到共享桌面的客户端。该客户端接收到远程控制信息,模拟本地的输入操作,达到远程控制的效果,构架模型如图1所示。
图2 共享桌面客户端发送屏幕图像数据
所有客户端在程序启动的时候,启动MirrorDriver,MirrorDriver会把屏幕的镜像位图数据和屏幕变化记录填充到缓冲区内,如果共享桌面的客户端开启共享。为了程序的执行效率,以多线程的形式启动桌面数据压缩线程(在主程序运行之外的另外一个线程)。图像编码的过程是比较消耗CPU资源的,但是高效率的编码可以很大程度上节省网络资源,所以编码线程在另外一个线程中执行,可以保障主程序的流畅运行。编码的过程中需要两个缓冲区,输入缓冲和输出缓冲区。MSScreen的DMO压缩需要手动填充输入缓冲区。从屏幕镜像缓冲区中取出图像数据,把输入缓冲区的地址指针给DMO,编码后的数据会被填充到输出缓冲区内,并返回输出数据的字节大小,这个过程是自动完成的。编码正确完成之后,从输出缓冲区取出数据,递交给网络线程就可以发送了。发送的过程和主程序的其他数据发送模式一致,所以屏幕共享模块可以很容易的集成到主项目中,而不需要单独的发送和接收,如图2所示。其他客户端(一般是学生机器客户端),接收到教室机器的共享屏幕数据之后。数据从网络线程接收,同样是多线程的处理方式。解码的过程类似与编码的逆过程。输入缓冲区存放接收到的数据。输出缓冲区存放的是图像数据。因为视频的压缩需要关键帧,如果客户端刚好接收到的第一帧不是关键帧,解压出来的位图为全黑色,直到接收到关键帧之后可以正确解码出图像,如图3所示。
二、远程控制系统的系统实现
2.1获取屏幕最小变化部分
在处理屏幕发送当中,第一次请求或在以后需要发送整屏数据(例如:监视区域发生变化,或在一次发送周期中的变化数据总和大于整屏数据量或客户终端主动请求发送整屏数据的情况)。为了处理上述情况,使用两个临时数据full_rgn、incr_rgn。如遇到上述情况,例如第一次连接时,程序在处理过程中使变量!full_rgn.IsEmpty()返回值>0。所以发送之前只要检查m_full_rgn既可,如果遇到需要发送全屏的情况,incr_rgn.Clear()(在此周期中的更新数据区域清空)。驱动返回的更新记录是即时的,没有必要即时发送数据。因为系统资源的占用消耗,捕捉到更新区域既可,远程没有必要即时发送。其次就是数据量的原因,对于远程发送,较少的数据量可以有效的节省网络带宽资源。
图4 屏幕变化部分 图5 屏幕变化部分
如图4所示,两次连续的变化(在极短时间周期内,即在一次获取变化数据周期内),两次更新的区域有重叠,而这种情况在屏幕变化时是经常发生的。而驱动只会记录下变化的区域而已。如果适当的采用优化算法,不仅可以有效的减小冗余数据,而且可以降低对资源的消耗。在实际应用过程当中是非常实用的。如果采用相应的算法,就不会出现一个周期内的变化数据总和大于整屏幕数据,如图5所示。
对第一种的解释是驱动的在共享数据中的标识,标识该区域是在屏幕内是移动的,由上一区域和当前区域可以计算出位移向量(例如窗口的拖动,该标记由驱动完成,应用程序只负责处理该情况)。为了节省数据发送量可以假定只发送更新矩形,和源矩形的左上坐标。把该消息发送客户端,由客户端完成虚拟屏幕的拖动,只需要完成数据内部的拷贝。这样可以节省大量数据的发送,(因为变化的数据只是在已有数据中位置的变化)。但是存在一种特殊情况,位移的矩形很小的时候,程序中假定的大小是矩形的长宽都小于一个16(int),如果矩形很小,还是采用上述方法相对来讲效率不会比不考虑其特殊性高,甚至效率更低。
2.2屏幕图像多线程压缩及解压实现
如图6所示,在程序启动之后,进行资源的初始化。如果允许共享,初始化桌面压缩线程。压缩和发送数据都是多线程的,不是在同一个线程,但是线程同步的,数据委托给网络线程发送。每执行一个周期,将事件状态设置为非终止状态,导致线程阻止。当定时器达到下一次周期时,将事件状态设置为终止状态,允许等待线程继续。
图6多线程压缩桌面图像
三、结束语
图像数据的传输,难点在于数据量的大小。网络数据量的大小直接关系到软件的性能和质量,在程序设计之初,拟采用JPEG图片静态压缩算法,虽然在一定程度上减低了数据量,但是并不能达到高效。因为屏幕的图像区别与其他位图图像,所以采用专门的屏幕压缩算法可以更有效减小数据量。程序在后续的改进中,采用微软的Screen压缩算法,在5 frame/s 网络数据量可以降低到15 k/s,并确保图像质量清晰,在網络状况不是很好的时候也可以保证程序的流畅运行。高效的压缩算法对CPU的使用也是比较高的,多线程的处理数据的压缩,可以保证程序流畅运行。
参 考 文 献
[1] Ted Faison. Visual C#基于组件的开发. 北京:清华大学出版社.2003,4
[2] Robert C.Martin,Micah Martin.敏捷软件开发:原则、模式与实践(C#版). 北京:人民邮电出版社. 2008,1