Skip to content

系列三 | 跨平台桌面端(Windows/macOS/Linux)高性能屏幕采集与编解码架构

在桌面端(Windows、macOS、Linux)实现超低延迟的远程协助,比移动端面临更加复杂的底层生态。每个桌面操作系统都有其专有的图形驱动架构、窗口管理器以及硬件编码 API。

如果采用通用的 CPU 截图加软件编码方案(如 FFmpeg + x264),在 2K 或 4K 显示器下,仅截图和格式转换就会吃满一个 CPU 核心,导致客户端卡顿,帧率极低。

易连系统桌面端基于 Go 语言(结合 Wails 构建前端)实现,但底层的图形采集与视频编解码管线则通过原生 CGO 或动态系统调用,深度结合了各平台的硬件加速接口:Windows DXGI/Media FoundationmacOS ScreenCaptureKit 以及 Linux PipeWire/VA-API。本文将逐一揭秘这些平台的架构设计。


1. Windows 平台:DXGI 复制 API 与 Media Foundation 的 GPU 零拷贝

在 Windows 系统上,要获得超低延迟的屏幕数据,首选是微软自 Windows 8 引入的 DXGI 桌面复制 API(Desktop Duplication API)

DXGI 采集流程

通过获取显示输出接口 IDXGIOutput5 并调用 DuplicateOutput,我们可以获取一个 IDXGIOutputDuplication 实例。每次屏幕发生像素更新时:

  1. DXGI 会将像素帧存放在显存的 ID3D11Texture2D 纹理中。
  2. 我们在显存中直接对其进行操作,避免将其拖回 CPU 内存。

零拷贝硬件编码:与 Media Foundation 深度协同

为了将捕获的 D3D11 纹理高速转化为 H.264 视频流,我们集成了 Windows Media Foundation H.264 编码器(MFT)

[ DXGI 桌面复制 ] ──► [ 显存物理纹理 ID3D11Texture2D ]

                            ▼ (共享显存指针)
                 [ IMFDXGIDeviceManager 注册管理 ]

                            ▼ (MFCreateDXGISurfaceBuffer 封装)
                 [ Media Foundation 硬件编码器 (MFT) ]

                            ▼ (GPU 硬件压制 Annex-B H.264 字节)
                 [ 发送网络数据包 ]
  1. 设备上下文管理:创建一个 D3D11 渲染设备,并将其注册进 Media Foundation 的 IMFDXGIDeviceManager 实例中。
  2. 显存缓冲区封装:利用 MFCreateDXGISurfaceBuffer,直接将 DXGI 抓取到的 ID3D11Texture2D 纹理句柄,封装为 Media Foundation 的 IMFMediaBuffer
  3. 零拷贝送入 MFT:将该显存 Buffer 直接传入 MFT 编码器进行压缩。由于数据始终留在显存中,MFT 可以直接调用 Intel/NVIDIA/AMD 显卡的专用硬编电路输出 H.264 Annex-B 字节流,CPU 占用率接近 0%

纯 Go COM 互操作与无 CGO 编译

传统的 DXGI/MF 编程需要编写大量 C++ 代码,再通过 CGO 链接。但 CGO 会导致 Windows 上的交叉编译变得极其困难。

易连助手在 Windows 端实现了一套纯 Go 的 COM 互操作层。我们利用 syscall.SyscallNwindows.NewLazySystemDLL 动态装载系统底层的 d3d11.dllmfplat.dll,在 CGO_ENABLED=0 的纯净环境下,直接在 Go 中实现了所有的 COM 接口调用,大大简化了工程链,同时保持了极致性能。

稳健的 CPU 退避路径

当硬件驱动损坏或多显卡切换导致 DXGI/MFT 初始化失败时,系统会自动启用 CPU 退避路径:将 GPU 纹理拷贝至 D3D11 Staging(暂存)纹理,调用 Map() 将像素映射回 CPU 内存,转换为 BGRA 格式,并首先尝试回退至 OpenH264 进行软件编码。若 OpenH264 加载或编码失败,则最终回退到极轻量的软件 JPEG 编码进行流传输兜底,确保远程协助连接绝不断开。


2. macOS 平台:ScreenCaptureKit 原生 GPU 采集管线

在 macOS 上,自 macOS 13 开始,苹果推出了现代化的图形采集框架 —— ScreenCaptureKit

  • 高性能采集:ScreenCaptureKit 允许我们指定只捕获某个特定窗口、某个应用程序,或者整个显示器。它返回的数据直接包装在 CoreVideo 的 CVPixelBuffer 中,并且自始至终在显存中保留。
  • VideoToolbox 硬件对接:在 Go 中,我们通过轻量 CGO 封装,将 ScreenCaptureKit 的 Objective-C 接口引出,并将 CVPixelBuffer 直接递交给 macOS 的 VideoToolbox 接口进行 H.264 硬件编码。其架构思想与 iOS 端高度一致,实现了在 macOS 端的高清、高帧率、超低功耗远程协助。

3. Linux 平台:PipeWire 采集与 VA-API 动态装载

Linux 平台的图形服务器目前正从老旧的 X11 转向现代的 Wayland。为了在这两种环境下都实现高性能采集,易连系统集成了 PipeWireVA-API (Video Acceleration API)

基于 PipeWire 的 DMA-BUF 零拷贝采集

  1. PipeWire 连接:客户端通过 PipeWire 服务订阅屏幕图像更新。
  2. DMA-BUF 传递:Wayland 合成器(如 Mutter 或 KWin)通过 PipeWire 将代表屏幕像素显存位置的 DMA-BUF 文件描述符(File Descriptor) 传递给我们的 Go 客户端。
  3. 硬件编码对接:客户端无需将像素拷贝回内存,直接将该文件描述符传入 VA-API 编码器,实现硬件级别的零拷贝压缩。
[ Linux 图形服务 (Wayland/X11) ]

               ▼ (PipeWire 跨进程文件描述符传递)
      [ DMA-BUF 文件描述符 ]

               ▼ (VA-API 硬件直接映射显存)
         [ VA-API 硬编 ] ──► H.264

极致的兼容性设计:动态 dlopen 与 dlsym 封装

Linux 设备的硬件环境极为分裂,如果直接静态链接 libpipewire-0.3.solibva.so,在没有安装这些库的精简 Linux 系统上,程序启动时就会因为“动态库找不到”而直接崩溃。

为实现“编译一次,处处运行”的二进制移植性,我们采用了动态装载设计

  • 动态 dlopen:在程序运行时,我们使用 Go 自研的动态装载器,尝试装载系统的 libpipewire-0.3.solibva.so
  • 符号映射:如果装载成功,解析符号并绑定指针,开启高性能的 PipeWire + VA-API 编码管线。
  • 平滑退避:如果装载失败,说明系统没有 PipeWire 或 VA-API。客户端会自动退避至传统的 X11 轮询截图,并首选尝试使用 Cisco 提供的 **OpenH264 库(运行时动态下载加载)**进行软件编码;若 OpenH264 软件编码同样加载或执行失败,则最终退避到轻量级 JPEG 软编进行兜底。这保证了 Linux 客户端即使在极简的无头(Headless)服务器环境下也能正常运行。

总结来说,跨平台桌面端的采集与编解码架构通过深度定制和底层优化,完美释放了 GPU 硬件的物理算力,确保了多端画面共享的极速呈现。在下一篇中,我们将前往 Web 前端,探讨如何通过 WebCodecs 在网页上进行超低延迟的解码与渲染。

Released under the MIT License. Terms | Privacy