一、先给结论
如果你正准备给板子接一个 USB 摄像头,下面五条可以先用起来:
结论 | 一句话解释 |
|---|---|
只认 UVC 免驱 | Linux 内核自带驱动,插上就有节点;不是免驱的别折腾 |
一颗摄像头会注册两个节点 | 能出画面的只有一个,判据是 Device Caps |
格式优先选 MJPG | 同为 720p:MJPG 跑 28.8 fps,YUYV 只有 9.0 fps |
记得加 video 组 | 不加就 Permission denied,而且必须重新登录才生效 |
供电软件测不到 | 别指望用命令读母线电压,能看的只有过流告警和满载长稳 |
下面逐条说怎么验证。
二、第一步:系统认不认这颗摄像头
插上去先看三样东西:
lsusb | grep -i camera
v4l2-ctl --list-devices
ls -l /dev/video*
我这颗摄像头的实测输出:
Bus 001 Device 003: ID 0bda:5846 Realtek Semiconductor Corp. USB Camera
USB Camera: USB Camera (usb-0000:01:00.0-1.1):
/dev/video4
/dev/video5
/dev/media0
能看到这些就说明它免驱。 v4l2-ctl --list-devices 能把节点列出来,意味着内核已经用 uvcvideo 把它接管了,不用装任何驱动。
再看它在 USB 通路上挂在哪:
lsusb -t
图 1:lsusb -t 的真实输出。摄像头挂在 Bus 001(480M,即 USB 2.0)下面的板载 4 口 Hub 上,而 Bus 002 那个 5000M 的 USB 3.0 控制器,当前一个设备都没有。
这里有个很常见的误会值得单独说:"我明明插在 USB 3.0 口上,为什么还是 480M?"
因为速率上限由设备决定,不由接口决定。看一眼设备自己的描述符就明白了:
cat /sys/bus/usb/devices/1-1.1/bcdUSB
cat /sys/bus/usb/devices/1-1.1/bMaxPower
2.00
500mA
bcdUSB = 2.00 的意思就是"我是 USB 2.0 设备"。这类摄像头插到 USB 3.0 口上也不会变成 5000M —— 那多出来的针脚它根本不用。
路径里的 1-1.1 是 USB 拓扑编号(Bus 1 → Hub 的第 1 口 → 设备的第 1 个接口),换 USB 口就会变。对着 lsusb -t 的树看即可,或者到 /sys/bus/usb/devices/ 下找带 idVendor 的那个目录。
把整台机器的视频节点摆开看,格局就清楚了:
图 2:这台机器上的 /dev/video* 全景。8 个节点里,6 个属于板载 MIPI CSI 接口,只有 2 个属于你插的 USB 摄像头。
为什么 USB 摄像头不是 video0? 因为节点号是按注册顺序发的,跟"插了几个设备"没关系。板载 CSI 通路先启动、先占号,USB 摄像头后到,于是拿到 4 和 5。所以永远不要用编号去猜用途 —— 更不要拿 video0 去开 USB 摄像头,那是板子自己的 MIPI 接口。
三、第二步:两个节点,哪个才是"看画面"的
/dev/video4 和 /dev/video5 来自同一颗摄像头。上一篇我写过"编号小的那个用来采集",但那是经验规律,不是判据 —— 遇到注册顺序不同的摄像头就会踩坑。
真正的判据在 Device Caps 里:
v4l2-ctl -d /dev/video4 --info | grep -A3 'Device Caps'
v4l2-ctl -d /dev/video5 --info | grep -A3 'Device Caps'
图 3:同一颗摄像头(序列号都是 202001010001)的两个节点。video4 的 Device Caps 里有 Video Capture*,它才出画面;video5 只剩* Metadata Capture*,连格式列表都是空的。*
再补一条命令交叉验证 —— 去看 video5 支持什么格式:
v4l2-ctl -d /dev/video5 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
Type: Video Capture
空的。 一个格式都没有,因为它根本不是取画面的节点。按 UVC 规范,摄像头可以额外注册一个 metadata 节点,用来输出每帧的元信息(时间戳、曝光参数等)。它顶着 /dev/videoN 的名字,但不产图像。
所以判断顺序是这样:
v4l2-ctl --list-devices 找出属于这颗摄像头的所有节点
对每一个跑一遍 --info | grep -A3 'Device Caps'
有 Video Capture 的那个,才是采集节点
有的摄像头会注册 4 个节点,有的只注册 1 个。别看编号,看能力。
四、第三步:格式选错,帧率直接掉到三分之一
这是本篇最值得看的一张表:
v4l2-ctl -d /dev/video4 --list-formats-ext
图 4:摄像头的完整格式能力表(原样输出,未做整理)。MJPG 的六种分辨率全部 30fps;YUYV 只有 640×480 能到 25fps,其余都是 10fps。
同一颗摄像头,同样标着 720p,两种像素格式的帧率上限差了 3 倍:
MJPG 1280×720 → 30 fps
YUYV 1280×720 → 10 fps
原因在于这两种格式根本不是一回事:
MJPG:每帧就是一张 JPEG,相机内部先压缩再传 —— 数据量小,但主机要解码
YUYV:未压缩的裸像素,一帧固定 宽 × 高 × 2 字节 —— 数据量大,主机不用解码
720p 的 YUYV 一帧是 1280×720×2 = 1,800 KB,是 MJPG(约 70 KB)的 25 倍。USB 2.0 的可用带宽就那么多,于是帧率被硬压到 10 fps。
但"标称上限"不等于"你实际跑的"。 我把四种配置各跑了一遍固定帧数:
bash e-cam-bench.sh /dev/video4
图 5:四种格式的实测(脚本见文末)。用 date 取采集前后的时间戳,帧数 ÷ 耗时得到帧率。先后跑了两轮,同一配置的偏差都在 1% 以内。
把四个数字放一起:
格式 | 分辨率 | 实测帧率 | 单帧大小 | 等效带宽 |
|---|---|---|---|---|
MJPG | 1280×720 | 28.8 fps | ~70 KB | 16.4 Mbps |
MJPG | 640×480 | 28.8 fps | ~25 KB | 5.9 Mbps |
YUYV | 1280×720 | 9.0 fps | 1800 KB | 132.8 Mbps |
YUYV | 640×480 | 22.5 fps | 600 KB | 110.4 Mbps |
(MJPG 的带宽按实测文件字节数换算;YUYV 是未压缩流,按 宽×高×2 的理论值换算,两者是同一个量级的口径。)
三个结论:
同分辨率下,MJPG 比 YUYV 快 3 倍多,带宽只要它的 1/8。 除非摄像头不支持 MJPG,否则没有任何理由用 YUYV。
MJPG 把分辨率降到 640×480,帧率一点不掉(还是 28.8),带宽再降到 1/2.8。 这就是多路扩展的第一招 —— 先降分辨率,而不是先怀疑摄像头或 USB 口。
MJPG 720p 只吃掉 16.4 Mbps。 USB 2.0 理论 480 Mbps、实测可用大约 280 到 320 Mbps(协议开销),这颗摄像头只用了 5% 出头,带宽上其实很宽裕。
然后是我自己踩的一个坑,很值得说。 我第一轮测 MJPG 720p,数字很怪:帧率 22.5 fps、单帧 600 KB —— 那明明不是 720p 的数据量。查了半天才反应过来:v4l2-ctl 不指定格式时,沿用设备"上次生效"的格式,而那颗摄像头当时停在 YUYV 640×480 上,我测的其实是它。
所以采集之前,一定要显式设一遍、再确认一遍:
v4l2-ctl -d /dev/video4 --set-fmt-video=width=1280,height=720,pixelformat=MJPG
v4l2-ctl -d /dev/video4 --get-fmt-video
Format Video Capture:
Width/Height : 1280/720
Pixel Format : 'MJPG' (Motion-JPEG)
--get-fmt-video 输出里的 Pixel Format 那行,才是它真正会用的格式。
GStreamer 里同理。v4l2src 后面的 caps 协商不上时会静默换一个能用的格式,所以要么把 caps 写死,要么事后确认一遍 —— 不然你会在错误的帧率上优化半天。
五、一个小权限,不加就起不来
如果访问 /dev/video* 报 Permission denied:
sudo usermod -aG video $USER
要重新登录(或重启)才生效,因为用户的组关系在登录那一刻就定下来了。验证:
id
uid=1000(user) gid=1000(user) groups=1000(user),27(sudo),44(video)
看到 44(video) 就对了。这条看着琐碎,但不做的话后面整条 GStreamer 流水线都起不来,而且报错位置往往指向别处,容易查偏。
顺手还能看看镜头有哪些可调项:
v4l2-ctl -d /dev/video4 --list-ctrls
亮度、对比度、饱和、曝光、白平衡都能调。比如画面偏暗:
v4l2-ctl -d /dev/video4 --set-ctrl=brightness=160
六、供电:先说清楚"软件测不到什么"
这类文章一般会写"拿万用表量一下电压"。但我想先把软件能测到什么、测不到什么划清楚,免得你在错误的路上花时间。
cat /sys/class/hwmon/hwmon0/name
ls /sys/class/hwmon/hwmon*/in*_input /sys/class/hwmon/hwmon*/curr*_input
sfctemp
(无 in*_input / curr*_input —— 即读不到母线电压与电流)
图 6:这台机器上唯一的 hwmon 是温度传感器;regulator 下 26 路读到的全是 PMIC 的目标设定值;唯一一条供电硬信号,是开机 5.6 秒时的 over-current。
三个事实:
hwmon 下只有一个温度传感器(sfctemp),没有任何电压 / 电流采样节点。想知道 5V 母线此刻是多少伏,软件层问不出来。
/sys/class/regulator/*/microvolts 读到的不是实测值,而是 PMIC 的目标设定值。比如 vcc_3v3 报 3300000,意思是"这里配了 3.3V",不是"此刻真的是 3.3V"。而且那 26 路里根本没有 5V 母线 —— 5V 是直接进稳压器的,不在 PMIC 的可读范围内。
唯一能拿到的供电硬信号是过流告警 over-current:
dmesg | grep -i 'over-current'
[ 5.594076] usb usb2-port2: over-current condition
开机 5.6 秒时,USB 3.0 控制器的 port2 报过一次过流。
这条告警说明什么? 说明整板的 5V 余量并不宽裕 —— USB 3.0 口在开机瞬间就触发过一次过流保护。之后连续运行 18 小时(含满载测试)没有再出现。
那摄像头这一路到底够不够? 有几个证据:
摄像头自己申报的需求:bMaxPower = 500mA,也就是 ≤ 2.5 W
满载实测:1280×720 @ 28.8 fps 连续采集 760 帧,零丢帧、零报错
它挂在 USB 2.0 那一条通路上,而 USB 3.0 那一路空着,互不争抢
结论:这颗摄像头的供电是够的。
但整板要算总账。 与其拍脑袋说"够 / 不够",不如算一算:
部件 | 峰值功耗 | 数值来源 |
|---|---|---|
开发板本体 | 约 5 W(峰值更高) | 板厂手册 |
USB 摄像头 | ≤ 2.5 W(500mA × 5V) | 设备描述 |
M.2 NPU 卡 | 6.6 W | 卡厂手册 |
加起来峰值接近 15 W,除以 5V 就是 3 A。所以板厂标的"5V/3A"是底线而不是"推荐配置" —— 建议按 5V/4A 备电源,把余量留出来。供电不足的典型症状是:设备枚举随机失败、lspci 时有时无、跑一会儿就掉。
还有一条实用建议:以后要接多路摄像头时,别把供电压力全压在板上。用带独立供电的 USB Hub(有源 Hub),让摄像头吃自己的电源,开发板只管数据。这比换一个更大的电源更便宜,也更稳。
七、一张清单
挑摄像头时看这 5 条:
确认是 UVC 免驱 —— 免驱就意味着 Linux 插上就能用
看 --list-formats-ext 里有没有 MJPG —— 没有 MJPG 的 720p 摄像头,大概率只能跑 10 帧
别只看"支持 1080P",要看那个分辨率下的帧率是挂在哪种格式下面的
优先选带序列号的(我这颗有 202001010001),多摄像头时能区分谁是谁
线别贪长,超过 3 米考虑带供电的延长方案,长线掉速是常见现象
出问题时按这个顺序查:
lsusb 都看不到 → 供电或接触问题,换口换线
能看到 USB 但 --list-devices 没有 → 不是 UVC 设备,或驱动没加载(dmesg | grep -i uvcvideo)
有节点但打不开 → 先看是不是 metadata 节点(Device Caps),再看 video 组权限
帧率远低于标称 → 先确认实际生效的格式(--get-fmt-video),多半是被协商成 YUYV 了
跑一会儿掉线 → 查 dmesg 有无 over-current,怀疑供电
