想了解如何利用eBPF技术在Linux系统中检测摄像头开关事件并自动控制灯光吗?从内核函数追踪到用户空间程序的联动,这一创新方法将为您的视频通话体验带来智能化升级。
本文译自 Detecting camera on/off events for Linux and controlling lights automatically with eBPF - Shuhao's Blog[1]
作者:Shuhao Wu,时间:2026-03-27
在 Linux 上,没有标准的方法可以获取相机打开或关闭的事件。在内核层面,有各种不同的相机 API,最常见的一个是 V4L2(Video4Linux),它没有内置机制来通知用户空间相机何时打开或关闭。在用户空间方面,如今大多数应用程序直接使用 V4L2,但这种情况正在逐渐转变为使用 libcamera 或 PipeWire。据我所知,V4L2 在用户空间端和 libcamera 也不支持相机开关事件。PipeWire 看起来似乎支持,但我不是专家,甚至无法让它正常工作 [1][2]。
| [1][3] |
能够以编程方式响应相机开关事件非常有用。一个用例是在系统托盘中显示相机开关指示器,这对于没有开关 LED 的网络摄像头来说,这是一个虽不完美但很有用的替代方案。另一个用例可能是记录相机访问以用于审计目的。我个人关心的是在我开始视频通话时自动打开 Logitech Litra 灯光。但如果这些 API 都不提供这种事件,该如何实现呢?
这就是 eBPF 的用武之地。eBPF 是一种可以在 Linux 内核中的多个指令位置运行程序的技术。这些内核侧的程序随后可以将数据发送到相应的用户空间程序进行进一步处理。eBPF 通常用于在内核或用户空间函数的入口和出口处执行自定义程序以进行跟踪。我们可以利用这一机制,在启动/停止相机视频流的内核函数执行时运行自定义程序。该自定义程序随后可以发出相机开关事件,供其他程序订阅。这就是 CameraCoordinator[4] 项目所实现的功能。它可以检测相机开关事件、运行脚本,并在检测到事件时发送 DBus 信号。
CameraCoordinator 仓库还包含一个名为 Autolight 的程序。它的功能包括:
下图展示了一个演示。如果你想下载并尝试使用,请前往 CameraCoordinator[5] 仓库并按照那里的安装说明操作。

CameraCoordinator 与 AutoLight(v1.1.0)演示,展示了相机状态和灯光控制。托盘图标上的灯光亮度和色温控制是在 1.2.0 版本中添加的,未在此演示中。
CameraCoordinator 通过追踪两个内核函数 vb2_ioctl_streamon 和 vb2_ioctl_streamoff 来工作。根据文档、源码阅读和一些实验,似乎这些函数在相机捕获开始和停止时大多数情况下都会被调用 [2][6]。可以通过运行以下 bpftrace[7] 脚本来验证相机开启事件,同时打开相机(完整脚本在此处[8]):
kprobe:vb2_ioctl_streamon { $file = (struct file *) arg0; if ($file == 0) { return; } $dentry = $file->f_path.dentry; if ($dentry == 0) { return; } $name = $dentry->d_name.name; printf("vb2_ioctl_streamon: file=%s\n", str($name)); // 这将输出 video0, video1 等。 }| [2][9] |
这个概念验证的 bpftrace 脚本可以检测摄像头的开启和关闭事件,但无法运行自定义脚本或发送 DBus 信号。使用具有良好 eBPF 支持的常规编程语言更容易实现这一点。我选择了 Golang,因为通过 cilium/ebpf[10] 库可以很好地支持 eBPF。代码比 bpftrace 脚本稍微复杂一些,并遵循以下流程:
该数据流也显示在下图中:

当前的一个问题是,当使用摄像头的进程未清理而关闭时,vb2_ioctl_streamoff 并不总是执行。为缓解这一问题,我尝试跟踪 vb2_fop_release,该函数在进程关闭且未调用 streamoff 时被调用。然而,由于该函数也会因其他原因被调用 [3][13],我不得不过滤事件,仅保留进程关闭的情况。为了检测这一点,我尝试查看调用 vb2_fop_release 的进程 PID 是否已被回收。这并不能很好地工作,因为它存在竞争条件,即 eBPF 事件可能在进程被内核完全回收之前触发(我认为)。因此,这并不完全可靠,偶尔会错过摄像头关闭事件。目前我没有更好的方法来检测这一点。如果你有,请给我留言[14]。要在当前代码库中解决这个问题,你必须正常打开和关闭摄像头。
事实证明,基于摄像头开启和关闭事件来开关灯光对于某些应用程序(如 Microsoft Teams)来说并不是最佳用户体验。Microsoft Teams 在你最终加入通话之前会多次打开和关闭摄像头,因为它有一个“预检查”屏幕。这会导致多次触发开关事件,从而在你加入通话时几次触发灯光开关。在我看来,这里的用户体验问题实际上并不是 Autolight 的问题,而是 Microsoft Teams 的问题。我想这并不令人意外。
| [3][15] |
目前的检测方法仍然相当脆弱,但它确实适用于我使用 UVC 摄像头的场景。正如开头所述,Linux 生态系统正处于从 V4L2 向 libcamera + PipeWire 过渡的过程中。PipeWire 应该会使检测更加稳健。CameraCoordinator 的架构可扩展以支持 PipeWire,但当前实现可能过于依赖 V4L2,需要进行一些重构才能让 PipeWire 检测器正常工作。特别是摄像头事件结构和事件合并器都与 V4L2 绑定。
此外,该项目为摄像头的开启和关闭事件定义了自定义的 DBus 信号。理想情况下,这应该在 FreeDesktop 规范的标准下得到支持。
对于 Autolight 项目,如果能自动调整灯光的亮度和色温就更好了。这有点困难,因为 Linux(甚至 Windows)没有现成可用的亮度和白平衡传感器 [4][16]。不调整亮度和色温可能导致视频质量不佳,图像可能过曝或白平衡不准。目前,Autolight 程序允许通过托盘图标手动控制温度和亮度来缓解这一问题。这不是很好,因为很容易忘记,但目前是可以接受的。
| [4][17] |
以下是一些可能只对我自己有意义而对其他人无关紧要的个人笔记:
[1] Detecting camera on/off events for Linux and controlling lights automatically with eBPF - Shuhao's Blog:https://shuhaowu.com/blog/2026/02-camera-coordinator.html[2][1]:#f1[3][1]:#footnote-reference-1[4]CameraCoordinator:https://github.com/shuhaowu/CameraCoordinator[5]CameraCoordinator:https://github.com/shuhaowu/CameraCoordinator[6][2]:#f2[7]bpftrace:https://github.com/bpftrace/bpftrace[8]完整脚本在此处:https://github.com/shuhaowu/CameraCoordinator/blob/7b66afc/scripts/trace-camera-rec-vb2-ioctl.bt[9][2]:#footnote-reference-2[10]cilium/ebpf:https://github.com/cilium/ebpf[11]一个 eBPF C 程序:https://github.com/shuhaowu/CameraCoordinator/blob/7b66afc/bpf/camera_detector_vb2_ioctl.bpf.c[12]一种架构:https://github.com/shuhaowu/CameraCoordinator/blob/a6ecd42/docs/development/architecture.md[13][3]:#f3[14]给我留言:https://github.com/shuhaowu/CameraCoordinator/issues[15][3]:#footnote-reference-3[16][4]:#f4[17][4]:#footnote-reference-4[18]争议:https://hackaday.com/2025/06/17/statusnotifieritem-how-standard-non-standards-tear-linux-desktops-apart/