昨天防截图的主题 /t/951728,让我想起了很多年前 Windows XP 中对 Windows Media Player 截屏的神奇现象:
播放视频时按下键盘 PrintScreen 截屏,粘贴到画图工具保存为 BMP 文件。打开图片文件,发现播放器内是黑的,看不到视频。
打开 Windows Media Player ,播放另一个视频;接着打开截图 BMP 文件,发现截图里的 “Windows Media Player” 正在播放后方播放器一模一样的内容,仿佛截屏会动了。
截屏里的黑色好像和真正的黑色不一样,截屏播放器的黑色可以透过窗口播放后方视频,而用画图板在截屏的基础上画上一个黑色矩形,那么在播放的视频上真的就产生了一个不透明的黑色遮罩。
我只记得当时这么一个现象,给了年幼的我很大震撼,让我一度以为是什么黑魔法(卧槽,BMP 图片会动了)
不过如今回想起来,还是不大能理解:BMP 应该是一系列 RGB 的组合吧,有什么 RGB 值是能够透过窗口播放视频的呢?
现在我没有 Windows XP 系统了,还请各位大神帮忙解惑。
1
codehz 2023-06-27 10:42:27 +08:00 3
虽然不能确定,但是我可以提供一个可能原因
视频播放用的是硬件叠加层( https://en.wikipedia.org/wiki/Hardware_overlay )(然后就能获得硬件加速),在前 dwm 时代,硬件叠加层是完全独立于窗口绘制,windows 需要给叠加层设置裁剪区域以“模拟”窗口被别的窗口覆盖的场景,显然截图变黑就很好理解了,因为根本就不在一个图层上( 至于穿透的话,则应该算是 bug 了,考虑到 mspaint 以前基本上是 gdi 功能演示程序,不排除是 gdi 和硬件叠加层之间的处理问题 |
2
krixaar 2023-06-27 10:44:55 +08:00
原理不懂,当年书上还是哪儿看到过通过硬件加速( DirectX )的视频,是播放器窗口那块单纯显示黑色,然后视频图像是 dx 实时渲染到那个位置覆盖在上面的,视频内容对于截图功能来说不可见,想要截图得关掉视频的硬件加速。
|
3
geelaw 2023-06-27 10:50:02 +08:00
我记得的,而且最近我忘了在 V2EX 还是知乎提到过。我当时也感觉很震撼,因为我想象中截图之后剪贴板里存放的就是一大堆像素的值,DirectX 绘制的部分变成黑色是可以理解的,但是再用 DirectX 绘制图像会反映在粘贴到的 mspaint.exe 里是无法理解的。
此外 Windows XP 时代的 mspaint.exe 还有更多神奇的东西,比如调色板其实除了前景色和背景色还有第三个颜色。 |
4
seers 2023-06-27 11:09:53 +08:00 via Android
我怎么感觉像是 drm 加密
|
5
winix 2023-06-27 11:15:50 +08:00
BMP 是支持通明背景的吧
|
6
yesterdaysun 2023-06-27 11:26:27 +08:00
隐约记得, 在 Win98 时代, 有一个邪门技巧, 把桌面壁纸设成一个固定的纯色, 是一种特殊的粉红色, 然后用超级解霸播放视频, 视频就会显示在桌面壁纸上, 就像如今的动态桌面一样, 非常神奇, 这个 BUG 或者技巧给我留下很深的印象
|
7
felixlong 2023-06-27 13:52:43 +08:00 12
哈哈,专做视频好多年,从 DVD 到蓝光到失业:). 给你解释一下。基本原理就是#1 说的没错。
但是呢。他虽然叫 Overlay 。其实它是在窗口的下面。MediaPlayer 通过画一个黑的矩形把那一层透过来。你截的图就是 MediaPlayer 画的那个黑矩形。自然也把它透过来了。 然后呢,这个颜色是可以设置的。超级解霸设的估计是粉红色。 为啥它要放在下面不放在上面呢,因为放在上面你就没办法在视频上面放字幕了,也没办法在视频上面放一些 Button 之类的 UI 了:) 为啥它不用 Alpha ,因为那时候的硬件太烂。还没有 Alpha Channel. |
8
huajingyu 2023-06-27 14:06:37 +08:00 4
那块黑色并不是纯黑色,而是非常暗的粉色。可以截图后用画图的取色工具查看。(如果我没记错的话是 rgb(16,0,16),只要是显示这种颜色的部分,在视频区域都会被替换成视频内容。)
这个问题在 Windows 10 中也会出现。某些游戏在播放视频时按 Ctrl+Alt+Delete 、Windows+L 或切换到 UAC 安全桌面又或是其它某种情况会导致程序的视频播放变为叠加层模式,即使被菜单或其它窗口挡住,阴影部分也会完全变黑。(鼠标指针不变黑是因为鼠标指针是另一个图层渲染的。)缩放率大于 100% 且程序为 96 dpi 强行拉伸时,画面会小一截。窗口预览、Alt+Tab 和任务视图会发现视频内容错位。视频内容会忽略颜色校准的颜色配置文件以及 Windows 夜间模式(暖屏)。 部分新电脑的显卡不支持硬件叠加层,会导致程序触发叠加层模式后视频区域白屏(可以被截图程序截到)无法播放视频。 切换到叠加模式播放视频的程序会在当前用户下的某个位置创建一个注册表项,删除后重启会恢复成正常模式。 印象中在 HKEY_CURRENT_USER\SOFTWARE\Microsoft\ 里面有个 Direct3D ,里面有个 DXGI Overlay 字眼的项,里面有程序路径为名称的值删掉即可。我现在正在用的设备还没有触发过硬件叠加层播放。 |
9
ysc3839 2023-06-27 14:11:10 +08:00 via Android
@codehz 个人认为只是 DirectX 和 GDI 交互做得不好而已。DirectX 系列最初是为了解决 Windows 早期多媒体框架性能差的问题,但是又来不及重写,所以当时的 DirectX 相对来说是比较独立于 GDI 那些传统组件的。实际工作时基本就是“绕过”原有的框架,“直接”(Direct)与硬件交互,所以使用 GDI 截图时截出来的就截不到,因为绕过了 GDI 。后续的 Windows 逐步重写了多媒体框架,DirectX 也变成了核心组件,自然就没有这些问题了。
|
10
ysc3839 2023-06-27 14:16:50 +08:00 via Android
|
11
codehz 2023-06-27 14:17:51 +08:00
@felixlong 果然是用颜色 mask 做的,我看 wiki 里写
As a consequence of hardware overlay use, a screenshot program (for example, the one automatically built into Windows that activates when a user presses the PrtSc key) often does not capture the content appearing in the hardware overlay window. Rather, a blank region containing only the special mask color is captured. This is because the screen capture routine doesn't consider the special video memory regions dedicated to overlays – it simply captures the shared main screen as rendered by the software's graphical subsystem. 还以为是啥特殊的东西,原来就是直接特殊颜色啊 |
12
ji39 2023-06-27 14:26:45 +08:00
我记得投影播不出画面,只有播放器界面
|
13
geelaw 2023-06-27 15:46:40 +08:00 via iPhone
所以说就是绿幕咯?可是为什么 DirectX 绘制的时候不是只抠目标窗口 /进程的“透明色”,而是抠全屏呢?是因为 DirectX 没有和进程 /窗口相关联吗?
|
14
huajingyu 2023-06-27 16:49:30 +08:00
@ysc3839 这种渲染方式,估计是系统组件的方法。而不是写程序时手动实现。(因为我在多个游戏都遇到过相同的情况,游戏很可能只是通过了 MCI 的 Video for Windows 来播放视频,而 Video for Windows 会调用 Direct3D 来显示视频画面。而 Direct3D 会视情况决定将视频直接渲染到窗口还是通过这种透明色叠加的方法来显示。后者新显卡似乎不支持。)以上部分是猜测出来的。至于程序能不能自行调用这种方法来渲染画面,我就不清楚了。
顺带一提在 Windows Vista 以上版本似乎对音频播放进行了大改,可以分别调整每个程序的音量。MCI 中 CD 播放程序是没法正确获取播放进度更新的。这导致部分游戏的背景音乐不循环。这个 Bug 至今还未修复。以前调用 MCI CD 播放是整个系统共享一个播放器的,甚至程序关闭或者用户注销也会继续播放。(程序自己读取 CD 数据并播放的不在内。)后面是每个程序调用 MCI ,播放状态互不影响。而且还可以分别调整每个程序的音量。 |
15
ysc3839 2023-06-27 17:59:21 +08:00 via Android
@huajingyu 我猜测透明色这种是早期 Windows GDI 和 DirectX 对接的一种 trick ,可能是因为 GDI 和 DirectX 相对来说比较独立,不好进行数据交互,就用这种方式来“告诉 DirectX 该在哪块渲染”,说不定对于任何 DirectX 程序,系统在背后都会偷偷用这种方式来渲染。
|
16
JeffGe 2023-06-27 18:03:46 +08:00 via Android 1
我记得这个现象,当时觉得很神奇但也没深究,没想到时隔多年在这里得到了解答🤣
|
17
secondwtq 2023-06-27 21:05:38 +08:00 1
这个主题颇有 The Old New Thing 的观感
|
18
codehz 2023-06-27 21:12:40 +08:00 2
@geelaw
@ysc3839 我找到了微软官方的文档 https://learn.microsoft.com/en-us/windows/win32/directshow/overlay-mixer-filter 早期视频叠加渲染独立于 d3d ( VMR-9 开始才支持 d3d ),用的是 directshow ,和 dx surface 没有任何联系 楼上说的不用 alpha 混合,说的应该是 vmr-7 以及之后的渲染方式,显然稍微新一些的应用都不需要在这个方面扣性能了 也找到了颜色相关的描述,如果没有指定颜色键的话,深灰色适用于较新的显卡,洋红色适用于较旧的 256 色卡。 这种模式下,最多只能显示一个视频流,有两个视频播放的话就可能产生闪烁 启用了视频叠加还会禁用 dwm ,也就是说,基本上和 d3d 也冲突了 这个模式充满了历史感,用的是所谓的视频端口,文档中还包括了 line-21 也就是 cc 显示的功能和所谓的 DVD 子画面(显然也是特殊显示器 /电视机才能实现的),为了用上硬件加速可真的是不择手段啊。。。 这里列出了古代视频渲染(显示到屏幕的部分)方式列表 https://learn.microsoft.com/en-us/windows/win32/directshow/choosing-the-right-renderer |
19
mmdsun 2023-06-27 22:25:35 +08:00
DRM OverView 技术
https://learn.microsoft.com/zh-cn/windows-hardware/drivers/audio/drm-overview 现在应该用 playready 比较多,奈飞也和微软有合作,防止录播: https://learn.microsoft.com/zh-cn/playready/overview/ecosystem |
21
ooool 2023-06-28 13:53:53 +08:00
这个是 Multiplane overlay
https://learn.microsoft.com/en-us/windows-hardware/drivers/display/multiplane-overlay-support 视频播放这块区域,不是程序用 D3D DrawIndexed 直接画在最外层的交换链上, 而是一个单独的交换链区域,相当于子窗口一样,那块区域本质上没有任何像素,IDXGIFactory2::CreateSwapChainForComposition,CreateSwapChainForCoreWindow 如果你 HOOK dwm 截图,开启了 MPO 之后回来这个函数 IDXGISwapChainDWM1::PresentMultiplaneOverlay , 这里面的 ID3D11Texture2D 也和你说的一样,是没有视频播放区域的,看起来都是黑色的, 除非你的交换链不是 DXGI_SWAP_EFFECT_FLIP_XXX 形式创建的 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Dwm, create DWORD OverlayTestMode with value 00000005. 可以通过修改注册表关闭 MPO 这样就不会出现这种情况 如果你想截图到这些东西,可以 HOOK IDXGISwapChainDWM1::CheckMultiplaneOverlaySupport 直接返回 E_FAIL 这个函数绘制的时候,会实时监测窗口遮挡覆盖之类的东西,是否走 IDXGISwapChainDWM1::PresentDWM 分支 IDXGISwapChainDWM1::PresentDWM 截图出来的图,就是好的,UAC 之类的框也能截到 不管你反截图还是防录播,都可以截图到,以后系统更新好不好使就不知道了 |