☰
Ambxst原生截图与录屏深度剖析:wlr-screencopy协议与SHM零拷贝的完整实现
2026/10/11 22:53:38 网站建设 项目流程

【免费下载链接】Ambxst

An Axtremely customizable shell.

项目地址:https://gitcode.com/gh_mirrors/am/Ambxst
点击查看免费下载

Ambxst 是一款高度可定制的 Wayland Shell,它的原生截图工具与录屏功能不依赖任何第三方工具,而是直接基于 wlr-screencopy 协议与 SHM 共享内存实现"零拷贝"屏幕捕获,兼顾了速度、隐私与多显示器混合缩放场景的稳定性。本文带你完整看懂这套原生截图录屏的实现原理。

🎯 为什么需要"原生"屏幕捕获?

在 Wayland 环境下,传统import -window root式的 X11 截屏方案完全失效——每个应用只能访问自己的窗口。想在 Wayland 上截屏,必须让合成器主动配合,把画面"交给"客户端。

Ambxst 的解决方案分两层:

层技术作用
协议层wlr-screencopy-unstable-v1向合成器申请抓取某块屏幕的一帧画面
传输层wl_shm 共享内存(memfd + mmap)让合成器直接写入客户端内存,避免二次拷贝

整个捕获引擎实现在 backend/internal/screenshot/capture.go 的Engine中:它连接 Wayland 显示服务、绑定compositor、wl_shm、wl_output与zwlr_screencopy_manager_v1四个全局对象,缺一不可。协议绑定失败时,Connect()会直接报出"compositor does not support wlr-screencopy-unstable-v1",帮你快速定位环境兼容性问题。

📡 wlr-screencopy 协议:一帧画面是怎么拿到的?

协议的核心交互在 backend/internal/proto/wlr_screencopy/screencopy.go 中生成,流程非常清晰:

  1. 申请:客户端调用CaptureOutput(或CaptureOutputRegion抓取指定区域),参数overlayCursor控制是否把鼠标光标也合成进画面;
  2. 协商:合成器回发buffer事件,告知支持的像素格式、宽高、stride(行距);
  3. 拷贝:客户端按规格创建一块 SHM 缓冲,发送copy请求;
  4. 就绪:合成器写入完成后回发flags(例如y_invert表示画面垂直翻转)+ready事件,或回发failed。

Engine.processFrame()(capture.go 第 355 行起)用一个事件循环for !ready && !failed驱动 Wayland 事件派发,直到画面就绪才返回——没有轮询、没有忙等,完全由合成器事件驱动。

🚀 SHM 零拷贝:共享内存是核心秘诀

所谓"零拷贝",关键在于 backend/internal/wayland/shm/buffer.go 中CreateBuffer()的三步操作:

  • memfd_create("dms-shm")创建一个匿名共享文件描述符(见 fd_linux.go);
  • ftruncate把文件大小撑到stride × height;
  • mmap(MAP_SHARED)将这块内存映射进自己的地址空间。

随后通过wl_shm_pool.create_buffer把这个 fd 的句柄传给合成器。合成器把像素直接写进这块内存,客户端在同一时刻就已经"看到"了画面——不需要 socket 传像素、不需要序列化、不需要额外内存复制。用完后只需munmap+close(fd),资源即被回收。

🧊 截图工具流程:冻结预览 → 选择 → 保存

前端体验由 modules/services/Screenshot.qml 与 modules/tools/ScreenshotTool.qml 驱动,这里藏着一个很聪明的设计——冻结帧会话(freeze session):

  1. 打开截图工具时,freezeScreen()对每一块显示器依次调用screenshot.frame,把整屏画面拍下来。注意 Screenshot.qml 中的注释:并发 screencopy 请求会在合成器内部竞争,因此在混合缩放布局下工具采用逐屏串行请求,保证可靠性;
  2. 帧缓冲被保留在后端(backend/pkg/capture/session.go 的StoreSessionFrame),你拖选区域时屏幕上显示的预览图,就是冻结的那一帧,而不是正在变动的真实屏幕——所见即所得;
  3. 确认区域后,screenshot.capture从冻结帧中CropBuffer裁剪出选区,坐标先按 backend/pkg/axmon 解析出的显示器缩放比例换算成物理像素;
  4. 若 2 分钟内没有后续操作,后台清扫协程会自动释放冻结帧,避免内存长期占用;工具关闭时也会立即screenshot.release释放。

后端服务注册在 backend/pkg/svc/screenshot/service.go,提供frame/capture/release/list/dir五个方法,截图默认保存到~/Pictures/Screenshots,可选同步写入剪贴板。最终 PNG 由自研编码器 backend/internal/screenshot/png.go 生成——它按 CPU 核心数把图像切分成多条"行带"并行压缩,速度优于常规实现。

🎬 录屏:gpu-screen-recorder 的低开销路径

录屏部分见 backend/pkg/svc/recorder/service.go,Ambxst 后端直接管理一个gpu-screen-recorder子进程,通过 IPC 暴露recorder.start / stop / status / dir四个方法,前端 modules/services/ScreenRecorder.qml 订阅recorder.state事件实时显示时长与状态。

设计上几个值得注意的点:

  • 四种模式:region(区域)、screen(指定/整屏)、portal/window(经 Portal 走用户授权,满足 Wayland 隐私要求);
  • 音频混录:支持同时录制输出与输入音轨(-a default_output|default_input);
  • 优雅停止:stop发送 SIGINT 让录制器正常收尾 mp4 容器,退出码 130/2 被视为正常结束;守护进程退出时若录制仍在进行,会等待 3 秒后强制终止,保证文件不损坏。

🌈 10-bit HDR 也原生支持

如果你的屏幕输出 10-bit(如XRGB2101010)或 HDR(PQ/BT.2020),捕获引擎同样能处理:SHM 层内置Convert10To8、ConvertPQ2020ToSRGB等转换(shm/buffer.go 中实现了 SMPTE ST 2084 逆 EOTF 与 BT.2087 色域矩阵),对外输出的 PNG 则是 16-bit 通道,最大限度保留色彩深度。此外Upright()会根据显示器的transform自动旋转/翻转画面,保证任何方向的屏幕截出来都是正立的。

📂 关键源码地图

想深入动手,从这几个入口入手即可:

  • 协议绑定:backend/internal/proto/wlr_screencopy/screencopy.go
  • 捕获引擎:backend/internal/screenshot/capture.go
  • SHM 零拷贝缓冲:backend/internal/wayland/shm/buffer.go
  • 区域/冻结帧封装:backend/pkg/capture/capture.go
  • 截图服务(IPC):backend/pkg/svc/screenshot/service.go
  • 录屏服务(IPC):backend/pkg/svc/recorder/service.go
  • 前端截图工具:modules/tools/ScreenshotTool.qml
  • 前端录屏服务:modules/services/ScreenRecorder.qml

✅ 小结

Ambxst 的截图与录屏是一套教科书级的 Wayland 原生实现:用wlr-screencopy 协议拿到合成器的帧、用SHM 共享内存实现零拷贝传输、用冻结帧会话解决预览一致性、用并行 PNG 编码和GPU 录制器压低落盘开销。理解了这套架构,你几乎可以为任何自研工具(OCR、取色、视频流推)复用同一个捕获底座 🛠️

【免费下载链接】Ambxst

An Axtremely customizable shell.

项目地址:https://gitcode.com/gh_mirrors/am/Ambxst
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询