虚拟机上用摄像头,第一步不是装驱动,是「把设备从宿主手里抢过来」。 抢不到,Ubuntu 里怎么找都是空的。
前面四节都在讲命令,这一节讲操作——把设备接进虚拟机。 9.5.2 再回到命令,看接进去之后怎么采。
一、为什么虚拟机要「抢」设备
摄像头是独占设备:同一时刻只能被一个操作系统打开。 插上 U 盘时宿主会自动挂载,摄像头却不会自动交出去—— 因为宿主自己也可能在用(比如微信视频)。
所以这一步必须手动做,而且必须在虚拟机运行、摄像头已插好的状态下做。
角色 手里有什么 能不能用
宿主 Windows 物理插口 默认在用 虚拟机 Ubuntu 虚拟 USB 控制器 要手动连接
连接的动作本质上是「把 USB 设备从宿主的驱动栈上摘下来, 挂到虚拟机的虚拟 USB 控制器上」—— 在操作系统看来,就像插到了另一台电脑上。
二、四步连接法
按顺序做,每一步都有明确的成功标志。
步骤 点哪里 看到什么算成功
1 插上摄像头,等宿主认出 宿主能打开预览 2 虚拟机菜单 可移动设备 列表里出现摄像头名 3 点「连接(断开与主机连接)」 宿主那一侧自动释放 4 Ubuntu 里看 /dev/video* 多出 video0
第 3 步括号里那几个字是关键:「断开与主机连接」。 只选「连接」不选断开,经常出现「两边都拿着、两边都用不了」的状态。
如果第 2 步的列表里根本没有摄像头名字, 先确认 USB 控制器在虚拟机设置里是打开的(USB 3.0/2.0 要选对)。
三、Ubuntu 里怎么确认接到了
四条命令,按顺序走,一条比一条深。
命令 看什么
ls /dev/video* 有没有 video0
v4l2-ctl --list-devices 设备名与节点对应
v4l2-ctl -d /dev/video0 --all 支持的分辨率与格式
ffplay -f v4l2 /dev/video0 能不能出画面
顺序不能颠倒:先看节点、再看能力、最后试画面。 反过来做,一旦没画面就分不清是「没认到」还是「格式不对」。
ls /dev/video* 常见输出是 video0 video1 两个节点——
很多摄像头会同时提供「采集」与「元数据」两个接口,
真正能出画面的通常是 video0,但也要试一下 video1 才知道。
四、三个最常见的失败
这三条基本覆盖了虚拟机接摄像头时的绝大多数问题。
现象 多半是什么
列表里没有摄像头 USB 没透传,或插在 USB 3.0 口上 连上了但没 video0 宿主还占着,没断开 有 video0 但采不到 权限不够,要加 video 组
第一条的「USB 3.0 口」是个老问题: 虚拟机的 USB 控制器版本与物理口不匹配时,透传会失败。 换到 USB 2.0 口往往立刻就好——这跟 FFmpeg 一点关系都没有, 但排查时最省时间。
第三条的权限问题,标准做法是把用户加进 video 组:
sudo usermod -aG video $USER,然后注销重登。
不重登不生效,这一点很容易漏。
五、动手 Demo:先证明本机没有 Linux 那套接口
这一节是纯操作,沙箱跑的是 Windows,/dev/video0 在这里不存在。
所以演示只能做到「确认这些接口一个都没有」,
把「没有」跟「有但没设备」这两种情况分清楚。
import av
def probe(fmt, arg):
c = None
try:
c = av.open(arg, format=fmt)
st = c.streams[0]
return u"打开成功 %dx%d" % (st.codec_context.width,
st.codec_context.height)
except Exception as e:
return u"%s: %s" % (type(e).__name__, str(e)[:40])
finally:
if c is not None:
c.close()
for fmt, arg in (("v4l2", "/dev/video0"),
("x11grab", ":0.0"),
("alsa", "default"),
("avfoundation", "0")):
print(u"%-12s %-14s -> %s" % (fmt, arg, probe(fmt, arg)))
实跑输出:
--------------------------------------------------------------------
9.5.1 VMware 中的 Ubuntu 连接 USB 摄像头
--------------------------------------------------------------------
**① 先说清楚:这一节是纯操作,沙箱验不了**
环节 在哪做 能不能实测
--------------------------------------------------
虚拟机连摄像头 VMware 菜单 不能
Linux 认到设备 Ubuntu 里 不能
FFmpeg 采到画面 Ubuntu 里 不能
**沙箱跑的是 Windows,`/dev/video0` 这种东西在这里根本不存在。**
**所以这一节的实测只能到「证明这些接口本机没有」为止,**
**真正的操作步骤按下面的清单走。**
**② 证明本机确实没有 Linux 那套接口**
接口 参数 结果
-----------------------------------------------
v4l2 /dev/video0 ValueError
x11grab :0.0 ValueError
alsa default ValueError
avfoundation 0 ValueError
**四个全是 `ValueError`,而且错在同一个地方:**
**`no container format`——说明这些「格式」在编译时就没进去,**
**不是「设备没找到」,是「根本没有这条通路」。**
**这个区别很重要:设备没找到还能插一个,通路没有只能换机器或重编 FFmpeg。**
**③ VMware 连接 USB 摄像头的四步**
步骤 点哪里 看到什么算成功
----------------------------------------------------------------------------
1 插上摄像头,等宿主认出 宿主能打开摄像头预览
2 虚拟机菜单 可移动设备 列表里出现摄像头名字
3 点「连接(断开与主机连接)」 宿主那一侧自动释放
4 Ubuntu 里看 /dev/video* 多出 video0(可能还有 video1)
**第 3 步是最容易漏的:不点「断开与主机连接」,Ubuntu 就抢不到这台设备。**
**因为摄像头是独占设备,同一时刻只能被一个系统用。**
**④ 在 Ubuntu 里怎么确认接到了**
命令 看什么
----------------------------------------------------------
`ls /dev/video*` 有没有 video0
`v4l2-ctl --list-devices` 设备名与对应节点
`v4l2-ctl -d /dev/video0 --all` 支持的分辨率与格式
`ffplay -f v4l2 /dev/video0` 能不能直接出画面
**顺序不能颠倒:先有节点,再看能力,最后才试画面。**
**反过来做,一旦没画面就分不清是「没认到」还是「格式不对」。**
**⑤ 三个最常见的失败**
现象 多半是什么
----------------------------------------------------------
列表里没有摄像头 USB 没透传,或插在 USB 3.0 口上
连上了但没 video0 宿主还占着,没断开
有 video0 但采不到 权限不够,要加 video 组
**USB 3.0 口兼容性是虚拟机里的老问题,插到 USB 2.0 口往往就好了——**
**这一条跟 FFmpeg 一点关系都没有,但排查时最省时间。**
四条全是 ValueError: no container format,错在同一个地方。
这个错的意思不是「设备没找到」,而是「这条通路根本没编进去」。 区别很重要:设备没找到还能插一个,通路没有只能换机器或重编 FFmpeg。
30 秒实验
- 在 Windows 上跑
dshow那一条:对比一下OSError与ValueError的差别。 - 把
v4l2改成v4l2:///dev/video0:看错误会不会变成别的(URL 写法)。 - 查一下
av.formats_available里有没有v4l2:与试开结果互相印证。
常见误区
- 以为连上摄像头 Ubuntu 就自动有了。必须手动在菜单里连接。
- 只点「连接」不点「断开与主机连接」。两边都拿着,两边都用不了。
- 加进 video 组但不重登。组权限要重新登录才生效。
自测三问(点开对答案)
1. 为什么摄像头要手动连接进虚拟机? —— 它是独占设备,宿主默认占着,必须手动把 USB 设备从宿主驱动栈上摘下来。 2. Ubuntu 里确认接到摄像头的第一条命令是什么? —— `ls /dev/video*`,看有没有 video0。 3. `ValueError: no container format` 说明什么? —— 这个接口在编译时就没包含进去,不是设备没找到。- ☐ 9.5.1 完,下一节 9.5.2 FFmpeg 采集 USB 摄像头获取的数据