我最近需要一个网络摄像头由 3 个应用程序(网络浏览器、视频会议应用程序和用于保存流的 ffmpeg)同时共享。
不可能简单地共享 /dev/video* 流,因为一旦一个应用程序使用它,其他应用程序就不能使用它,并且其他任何应用程序都会出现“设备或资源繁忙”或类似情况。
因此,我转向 v4l2-loopback,目的是将网络摄像头镜像到 3 个环回。
使用 3 个环回确实可以按预期工作,但真正令我惊讶的是事实证明我实际上并没有需要3 个环回,但只有 1 个。
如果我创建一个环回并用 ffmpeg 提供它,那么单镜像环回可以使用同时进行所有 3 个应用程序,不存在“设备或资源繁忙”问题。
所以这比我计划的还要好,而且没有任何实际问题需要我帮助。
但我的问题是,环回怎么可能做到这一点?为什么不直接使用原始来源呢?
创建单个环回的示例命令:
sudo modprobe v4l2loopback video_nr=30 exclusive_caps=1 card_label="loopback cam"
使用 ffmpeg 将 /dev/video5 镜像到环回 (/dev/video30) 的示例命令。这将默认为原始数据,但最近构建的 ffmpeg 可以使用 MJPEG 等替代流,无论如何,行为都是相同的:
ffmpeg -f v4l2 -i /dev/video5 -codec copy -f v4l2 /dev/video30
完成此操作后,尝试使用多个应用程序访问 /dev/video30,以下是一些示例:
ffmpeg -f v4l2 -i /dev/video30 -codec libx264 recordstream.mp4
ffplay -f video4linux2 -i /dev/video30
系统信息(如果相关):
- 乌班图20.04
- 内核:5.4.0-31-generic
- 软件包:v4l2loopback-dkms 0.12.3-1
答案1
这是设计使然。首先,假设多个进程可以打开 /dev/video0 设备,但只有其中一个能够发出某些命令控制(ioctl()) 直到流开始。
那些V4L2控制定义诸如比特率之类的东西。开始流式传输后,如果您尝试,内核将不允许您更改它们并返回EBUSY
(设备或资源繁忙)。看这张纸条在内核源代码中。这有效地阻止了其他消费者,因为您应该在开始流式传输之前设置这些消费者。
v4l2loopback 有什么不同之处?它添加了逻辑和数据结构多个开场白并且默认情况下会不尝试应用新的控制措施通过提供自己的设置器。
请注意,v4l2loopback 需要有多个开启器,至少两个有用。一名读者和一名作者。