工作原理
为什么 Pika 必须拆成 GNOME Shell 扩展和独立录制进程两半,两者如何通过 D-Bus 通信,门户采集与 GStreamer 编码管线是怎么搭起来的。
为什么是两个进程
Pika 由 GNOME Shell 扩展和一个独立的录制进程组成。这个划分不是可选的, 两个方向的约束各自成立:
界面必须在 Shell 里。 Wayland 协议没有浮层和窗口定位能力 ——
官方 wayland-protocols 里没有 layer-shell 类协议,Mutter 也拒绝实现
wlr-layer-shell。实时选区遮罩、录制取景框、顶栏指示器,普通应用一个都画不出来。
编码绝不能在 Shell 里。 GJS 是单线程的,和合成共用一个主循环 ——
在里面跑 H.264 整个桌面会掉帧。GNOME 自己也是这么分的
(gnome-shell + org.gnome.Shell.Screencast)。
结果是录制进程没有任何窗口,连设置和关于都在扩展的 prefs.js 里
(那是跑在独立进程的 GTK4,卡了也卡不到桌面)。
两半怎么说话
扩展调用录制进程的 D-Bus 接口 io.github.hungtcs.Pika;
录制进程需要选区时反过来调扩展的 io.github.hungtcs.PikaShell。
用方法调用而不是信号,是因为信号是广播、没有回执 —— 拿不到错误, 也没法触发按需启动。
录制进程通过 D-Bus 激活按需拉起,用户不需要手动启动任何东西。
激活文件里的 SystemdService= 是有讲究的:xdg-desktop-portal 靠 systemd
单元名反推应用 ID,而门户的授权记忆是按应用 ID 存的。少了这一行,
进程会落进调用方的 cgroup,门户认不出它,结果就是每次录制都重新弹授权框。
采集
采集走 org.freedesktop.portal.ScreenCast。门户返回的不是图像数据,
而是一个 PipeWire node ID 加一个 fd。
授权令牌持久化在 $XDG_STATE_HOME/pika/screencast-restore-token,
避免每次弹窗。用户随时可以撤销,所以每条采集路径都有重新申请的兜底。
区域录制其实是「采整块屏 + 裁剪」 —— 门户不支持只采一块区域。
编码管线
pipewiresrc → queue → [videocrop] → vapostproc/videoconvert → 编码器 → h264parse
→ mp4mux → filesink
- 编码器按
vah264lpenc→vah264enc→x264enc→openh264enc顺序探测, 前两个是 VA 硬编。 - 有音频时并入
audiomixer → audioconvert → audioresample → AAC → mux.audio_0。 即使只有一路来源也走 mixer —— 它会用静音填补空隙,麦克风掉线不会让时间轴缩短。 - 停止必须走 EOS 而不是直接关闭 ——
mp4mux要靠 EOS 才会写完索引。 分片模式是保底:被外部掐断时文件仍然可播。
配置怎么共享
io.github.hungtcs.Pika.gschema.xml 是唯一事实来源,构建时分别拷进扩展目录和
应用自己的 schema 目录。
必须拷两份,是因为扩展跑在宿主 Shell 里、应用(将来)跑在沙箱里,
两边看不见对方的文件系统。schema 只是元数据,真正的数据在 dconf 里 —— 那是通的。
所以两份的 id 和 path 逐字一致。