远程控制之屏幕截取 小结
为了实现高速屏幕传输,势必不能每次都截取整个屏幕,这样做的后果就是待传输的过大数据量和有限带宽(假设约20K~50K)之间的矛盾。为了让显示更加流畅,必须在单位时间内利用有限的带宽传输近可能多帧的图象过来,这里就需要实现差异截屏!
实现差异截屏有以下三种方案可以选择:
使用差异截屏有可能需要进行屏幕分块,就是将整个屏幕分成N个小区域,每次仅仅传输通过某种算法判断已经变化的部分,区域的大小一般都是根据经验设定!
为了进一步减少待传输的数据量,还可以选择性地进行压缩,压缩方式也有两种选择:
目前该应用的瓶颈主要是带宽的限制,为此需要尽量减小差异截屏后获得的数据量,但是测试的结果也只能达到每秒数帧的效果,和网上某些文章提到的动辄几十帧上百帧(注:个人感觉有水分^_^)的效果相差甚远!
2007/07/06 Update:
使用虚拟显卡驱动本质上是编写一个Display Mirror Driver,安装之后该驱动和物理显卡驱动将会收到完全相同的事件,根据这些事件可以判断屏幕的那些区域发生改变,而且在驱动中可以直接操作显存,就不需要耗费大量的CPU进行bltting!
据说PcAnyWhere、远程桌面(WIN2000之后)以及部分远程控制软件均采用该技术实现。
DirectDraw好像也是可以直接操作现存的,不知道和用Mirror Driver这种方法比效率相差有多大!?
参考:http://www.osronline.com/showthread.cfm?link=111960
2007/07/11 Update:
在用GDI Bitblt函数或DirectDraw进行高速截屏时,为了得知那些区域发生变化,必须保存一份屏幕拷贝,通过将最新的屏幕镜像和保存的拷贝进行比较,从而获得发生变化的区域!用Bitblt获得屏幕拷贝速度非常慢,为了获得1280*720大小的截屏,在我机器上需要350ms左右,用DirectDraw在这一点上就好多了。
VNC采用Hook的方法截获所有相关的Windows消息,然后判断各个消息对哪些屏幕矩形区域有影响,把这些矩形区域合成一个Region,在更新的时候进行更新这些区域。
采用虚拟驱动的原理和Hook方法类似,不过截获的不是Windows消息,而是直接在驱动中截获GDI函数调用,在这些函数中获得变化的矩形区域并组合成最终的Region,由于驱动和普通应用程序处于不同的特权级别,因此在读显存之后需要将数据传到ring3,处理起来相当麻烦,而且处理不善将有很大的效率问题!
实现差异截屏有以下三种方案可以选择:
- (BitBlt或DirectDraw) + (隔行取样或CRC或Hash)
- Hook: 参考VNC实现
- 虚拟显卡:参考陈经韬的例子,无源码(Delphi)
使用差异截屏有可能需要进行屏幕分块,就是将整个屏幕分成N个小区域,每次仅仅传输通过某种算法判断已经变化的部分,区域的大小一般都是根据经验设定!
为了进一步减少待传输的数据量,还可以选择性地进行压缩,压缩方式也有两种选择:
- BMP -> JPEG:有损压缩,压缩比相对较高
- 通用压缩:Zip、ZLib(Ex)等
目前该应用的瓶颈主要是带宽的限制,为此需要尽量减小差异截屏后获得的数据量,但是测试的结果也只能达到每秒数帧的效果,和网上某些文章提到的动辄几十帧上百帧(注:个人感觉有水分^_^)的效果相差甚远!
2007/07/06 Update:
使用虚拟显卡驱动本质上是编写一个Display Mirror Driver,安装之后该驱动和物理显卡驱动将会收到完全相同的事件,根据这些事件可以判断屏幕的那些区域发生改变,而且在驱动中可以直接操作显存,就不需要耗费大量的CPU进行bltting!
据说PcAnyWhere、远程桌面(WIN2000之后)以及部分远程控制软件均采用该技术实现。
DirectDraw好像也是可以直接操作现存的,不知道和用Mirror Driver这种方法比效率相差有多大!?
参考:http://www.osronline.com/showthread.cfm?link=111960
2007/07/11 Update:
在用GDI Bitblt函数或DirectDraw进行高速截屏时,为了得知那些区域发生变化,必须保存一份屏幕拷贝,通过将最新的屏幕镜像和保存的拷贝进行比较,从而获得发生变化的区域!用Bitblt获得屏幕拷贝速度非常慢,为了获得1280*720大小的截屏,在我机器上需要350ms左右,用DirectDraw在这一点上就好多了。
VNC采用Hook的方法截获所有相关的Windows消息,然后判断各个消息对哪些屏幕矩形区域有影响,把这些矩形区域合成一个Region,在更新的时候进行更新这些区域。
采用虚拟驱动的原理和Hook方法类似,不过截获的不是Windows消息,而是直接在驱动中截获GDI函数调用,在这些函数中获得变化的矩形区域并组合成最终的Region,由于驱动和普通应用程序处于不同的特权级别,因此在读显存之后需要将数据传到ring3,处理起来相当麻烦,而且处理不善将有很大的效率问题!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥