Windows 截图原理,高难度问题,请慎入

2020-12-31 09:53:44 +08:00
 cool1205
windows 截图可以使用 windows 自带的,也可以使用 QQ 等辅助工具截图,效果还是可以的。我想请教各位大神一个问题,windows 通过 API 截图是拿的哪里的数据,这可能与 windows 刷新屏幕有关系了,windows 是直接从屏幕直接截取,还是从内存中直接获取。这么说有些抽象,比如屏幕刷新率是 1HZ (例子而已),那就是一秒屏幕更新一下,此时有个程序每隔 0.1 秒向控制台输出当前毫秒时间戳,那此时使用截图工具,截到图片的时间戳会不会一秒内截图的十张图片一样,还是十张不一样。我尝试使用软件去验证,但不存在可操作性,希望有大哥指教一二
10022 次点击
所在节点    程序员
53 条回复
cool1205
2020-12-31 11:08:21 +08:00
@aloxaf 没隔 5ms 就够了
murmur
2020-12-31 11:11:01 +08:00
@cool1205 你怎么保证 5ms 的精确时钟 编程时钟都是受系统负载干扰的 你的 timer 能精确到这个速度么

不如这个东西 Elgato 4K60 Pro MK.2 这是真的 1080p 240hz 采集卡 全自动按你要求录视频 然后逐帧你可以满满分析
sampeng
2020-12-31 11:12:01 +08:00
这。。哪高难度了。。。随便怎么想都不可能是截图显示器啊。。显示器的刷新率和我软件有什么关系?你用接口去操作显示器?我为什么不直接操作显卡的输出不更简单?
cool1205
2020-12-31 11:12:11 +08:00
描述存在歧义,不是 1ms 截一次,5ms 截取就够了
sujin190
2020-12-31 11:12:31 +08:00
截图从显存复制就行吧,窗口内容不变,显存内容又不会变更,和显示器刷新率页没啥关系,如果窗口渲染也要像显示器那么时时刻刻在刷新,那你这也太资源了吧,再说就算串口内容变更了,现在也完全是哪部分区域变更了重新渲染哪部分区域变更显存内容就行了吧,并不需要整个刷新
aloxaf
2020-12-31 11:16:39 +08:00
@cool1205
你这个需求我感觉是在记录日志,请问「将程序的输出重定向到文件」这种方案是否考虑过,还是说考虑过但被否决了?
shenjinpeng
2020-12-31 11:21:15 +08:00
你猜不要显示器能不能截图 ?
jones2000
2020-12-31 11:46:39 +08:00
下个开源的截图软件, 看下源码不就知道了。
iriyave
2020-12-31 12:06:54 +08:00
正好搞过截图的,我试过两种方法:
1 是 GDI,GetDesktopWindow,CreateCompatibleBitmap,GetDIBits ;
2 是 DX,CreateOffscreenPlainSurface,GetFrontBufferData ;
cool1205
2020-12-31 12:08:13 +08:00
刚才是试了一下,当我把 HDMI 线拔了后,进行截图,可以截图,截图内容与为拔截图内容一样,只有时间不一样。证明 windows 会继续上一屏幕进行截图,此时显卡有输出。其实这并没有解答我的疑问,windows 截图的内容来源是哪里? 1. Windows 通过自身 API 调用显卡内存,再输出我们看得到的图片; 2. Windows 根据自身 UI 句柄或其他方式,再不调用显存的情况下直接截图。如果是按照显存来的话,按照大家所说相当于显存是实时更新的,更新的频率就根据显卡性能来定,Windows 前往显存去抓取,至于显示器是多少 hz 则由显卡根据设定的 hz 从显存中获取数据后输出到显示器。不知道我这个理解对不对?
cool1205
2020-12-31 12:12:02 +08:00
不用任何第三方截图软件,我认为 windows 自身的 API 必定是最快的。若真有这种代码存在,请大家推荐完全不调用 windows 自身 API 的方式,我试过几种,都是在 windows 自身 API 上做了一些封装而已,这种方式只会增加程序截图的时间,若对实时性要求不高的场景可以使用,但我对实时性要求很高。
iriyave
2020-12-31 12:12:28 +08:00
补充一下,虽然我搞过截图功能,但也只是调用 win 提供的 API,也不懂 win 底层是怎么实现的,
我的猜测是 dwm 也是双缓冲,各种程序的数据都是汇总到 BackBuffer,FrontBuffer 是随桌面刷新率更新,而截图是获取的 FrontBuffer 的数据,当然只是推测没验证过。
GuuJiang
2020-12-31 12:56:41 +08:00
显示器的刷新率和程序进行重绘的速率两者之间没有任何关联,并且两者相差了好几个数量级,你完全可以写个程序显示一个静态图片并且不再进行任何重绘,此时显示器的刷新率仍然是固定的值
如同楼上各位指出,这大概率是个 XY 问题,还是直接说出你的真正需求吧
crystom
2020-12-31 13:04:09 +08:00
截图和屏幕没关系吧,有刘海或者圆角屏幕的手机,截屏出来也是完整的长方形,不会像物理屏幕一样的形状
janus77
2020-12-31 13:10:24 +08:00
友情提示人眼所看到的东西只要是 60 帧就不卡了,也就是 16ms 一帧。你要 5ms 一次那你不如直接录视频,然后从视频里慢慢分析,还能暂停呢。
3dwelcome
2020-12-31 13:13:20 +08:00
NVIDIA 有 60fps 输出流视频的 API,就和现在的游戏直播一样,在 H265 视频里截图,可以精确到 16ms 。
正常 windows api 也可以截图,我写过这种软件,就是没办法连续抓取。
phpfpm
2020-12-31 13:23:38 +08:00
不太懂 windows 世界的事儿,但是应该是和 windows 窗口渲染有关

DWM,窗口管理器什么的应该有好多个渲染层,有一些视频(比如 hdr )渲染的和窗口什么的都不一样

所以这个问题还是挺复杂的

https://www.zhihu.com/question/21747929/answer/498345137

之前看过这篇文章,供参考
phpfpm
2020-12-31 13:25:45 +08:00
@cool1205 hdmi 实际上是显示适配器,决定了 DWM 绘制的时候要显示多大的视窗范围。

如果只有显卡没有显示适配器,系统不会绘制图形什么的。
SlipStupig
2020-12-31 14:46:40 +08:00
这块我刚好做过远程会议类软件,使用 GDI 系列 API 就可以得到,也可以通过 DX 得到,至于图像每一帧是不是一样的话,从 hash 比较上比较可能会不一样,稳妥的方法是监听鼠标和键盘事件
Lemeng
2020-12-31 15:11:14 +08:00
除非特殊需求。不然真没研究过。貌似也没必要

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/740500

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX