🔍
B站技术平台,嵌入式Jerry :
请关注,记得标为原始粉丝。
在嵌入式系统中添加摄像头功能,USB 摄像头往往是首选。它不依赖硬件 CSI 通道,不需要设备树支持,只要内核配置得当,即插即用。本文将从内核架构原理出发,系统讲解 USB 摄像头驱动的核心机制,并结合 NXP 的 linux-imx 内核,分析实际配置、驱动加载、调试方法,确保你可以从底层搞明白 USB 摄像头在 Linux 中是如何工作的。
一、V4L2 框架与驱动架构:USB 摄像头的"宿主"系统
1.1 什么是 V4L2?
V4L2(Video4Linux version 2)是 Linux 内核提供的一个统一视频设备接口标准,它定义了用户空间与内核空间之间操作视频设备的统一方式。
其核心职责包括:
- 提供标准设备节点:
/dev/videoX
- 定义 ioctl 接口(如
VIDIOC_QUERYCAP
,VIDIOC_STREAMON
) - 管理视频缓冲区(使用 vb2 框架)
- 为各种摄像头、解码器、转换器等提供统一的驱动框架
V4L2 是一个 "驱动框架 + 用户接口",而具体的设备驱动(如 USB 摄像头)则是它的实现者。
1.2 uvcvideo 是什么?
uvcvideo
是 Linux 内核中专为 USB 摄像头(符合 USB Video Class 标准)提供的驱动模块,它是 V4L2 框架下的一个具体驱动实现。
它负责:
- 与 USB 栈配合,识别符合 UVC 的 USB 摄像头
- 分析摄像头提供的 USB 描述符
- 注册 V4L2 video_device,提供
/dev/videoX
- 实现标准 ioctl 接口、帧缓冲管理、图像采集
1.3 USB 摄像头驱动与 MIPI 摄像头驱动的本质区别
特性 | USB 摄像头(uvcvideo) | MIPI 摄像头(CSI + sensor 驱动) |
---|---|---|
接口 | USB(UVC 标准) | MIPI CSI + I2C |
总线模型 | USB device | platform device |
设备树支持 | ❌ 不需要 | ✅ 必须描述 sensor 信息 |
典型驱动 | uvcvideo | imx-media + sensor 驱动 |
自动识别 | ✅ 支持热插拔 | ❌ 需设备树和固定绑定 |
二、USB 摄像头驱动架构详解(基于 linux-imx)
2.1 uvcvideo 模块的内核入口分析
路径:drivers/media/usb/uvc/uvc_driver.c
c
static struct usb_driver uvc_driver = {
.name = "uvcvideo",
.id_table = uvc_ids,
.probe = uvc_probe,
.disconnect = uvc_disconnect,
.suspend = uvc_suspend,
.resume = uvc_resume,
};
这是典型的 USB 设备驱动模型,uvc_driver 注册到 USB 栈,匹配符合 uvc_ids 的设备后回调 uvc_probe()
。
2.2 uvc_probe:V4L2 注册流程核心
c
int uvc_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
// 初始化 uvc_device 结构
struct uvc_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
uvc_video_init(dev);
// 绑定到 V4L2 框架
v4l2_device_register(&intf->dev, &dev->v4l2_dev);
// 注册 video_device,最终形成 /dev/videoX
video_register_device(&stream->vdev, VFL_TYPE_VIDEO, -1);
}
v4l2_device_register()
将该设备纳入 V4L2 框架video_register_device()
创建设备节点/dev/video0
- 所有标准 ioctl 由
v4l2_ioctl_ops
实现
2.3 缓冲区管理:vb2_queue
c
stream->queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
stream->queue.io_modes = VB2_MMAP | VB2_USERPTR;
stream->queue.ops = &uvc_queue_ops;
vb2_queue_init(&stream->queue);
uvcvideo 使用 Video Buffer 2(vb2)框架来处理帧缓冲,支持多种 I/O 模式(MMAP、USERPTR 等)。
2.4 uvcvideo 与 USB 子系统交互
在 uvc_probe()
中会调用:
c
usb_set_intfdata(intf, dev);
usb_register_dev(intf, &uvc_class);
用于将 USB 接口与 uvcvideo 驱动绑定,并实现 /dev/video0
的注册。
三、Yocto 环境下启用 uvcvideo(以 linux-imx 为例)
3.1 配置内核
在 Yocto 工程中执行:
bash
bitbake -c menuconfig virtual/kernel
进入路径:
Device Drivers --->
Multimedia support --->
Media USB Adapters --->
<*> USB Video Class (UVC)
[*] UVC input events device support

这将启用:
config
CONFIG_USB_VIDEO_CLASS=y
CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
3.2 检查配置是否生效
bash
grep CONFIG_USB_VIDEO_CLASS tmp/work/.../linux-imx*/build/.config
确认为:
CONFIG_USB_VIDEO_CLASS=y
3.3 镜像中添加驱动模块(如果为 <M>
)
bitbake
IMAGE_INSTALL:append = " kernel-module-uvcvideo"
四、插入摄像头后的内核日志分析
使用:
bash
dmesg | grep -i uvc
输出如下,表示识别成功:
usb 1-1: UVC 1.00 device USB Camera (0c45:6366)
uvcvideo: Found UVC 1.00 device USB Camera (0c45:6366)
此时 /dev/video0
自动创建,可通过 v4l2-ctl
操作。
五、usb_camera.c 相关结构概览
关键结构包括:
结构体 | 说明 |
---|---|
uvc_device |
驱动私有结构体,挂接 V4L2 核心 |
uvc_streaming |
一个 video 流(如 YUYV 流) |
video_device |
表示 /dev/videoX 的核心对象 |
vb2_queue |
用于 buffer 管理 |
uvc_buffer |
表示单帧缓冲区 |
这些结构通过 uvc_register_video()
、uvc_queue_init()
等函数连接成完整的采集通路。
六、实战调试经验总结
✅ 检查 USB 摄像头是否 UVC 兼容
bash
lsusb
查找是否有关键词 UVC
、Video
✅ 查看设备节点
bash
ls /dev/video*
无节点可能是驱动未加载,或 udev 未创建。
✅ 使用 v4l2-ctl 检查能力
bash
v4l2-ctl --list-formats-ext
确认是否支持 YUYV、MJPEG 等主流格式。
✅ 使用 ffmpeg/Qt/CV 实时预览(内核测试层面验证)
bash
ffmpeg -f v4l2 -i /dev/video0 out.mkv
七、为什么不需要设备树支持?
USB 驱动模型是基于设备枚举的,不依赖设备树绑定流程。
内核识别流程如下:
- 摄像头插入 USB
- USB 栈识别设备 ID
- 查表匹配 uvcvideo 驱动(根据
uvc_ids
) - 调用
uvc_probe()
注册 V4L2 设备
平台摄像头(如 OV5640)才需要设备树描述 I2C 地址、MCLK、CSI path,而 USB 摄像头全部自动识别,无需配置。
八、常见问题解析
问题 | 原因与建议 |
---|---|
无 /dev/video0 | 未启用 uvcvideo 或摄像头非 UVC |
插入摄像头无响应 | USB host 控制器未启用 |
v4l2-ctl 提示 ioctl 错误 |
驱动未正确绑定、摄像头不支持格式 |
图像不流畅 | 缓冲区不足或采集帧率未设置 |
九、小结与推荐实践
- 对于 USB 摄像头,只需启用
CONFIG_USB_VIDEO_CLASS
即可 - 不需要设备树,也不需要 V4L2 sub-device 支持
uvcvideo
驱动直接在 V4L2 框架下注册 video 设备- 可使用
v4l2-ctl
、ffmpeg
等工具验证采集功能 - 在 Yocto 中添加内核模块和调试工具是基本操作,建议封装为 image 配置
如需进一步构建嵌入式摄像应用(OpenCV / Qt / MJPEG 推流),建议先确保内核 UVC 驱动完全可用,再往上搭建用户空间系统。
🔍
B站技术平台,嵌入式Jerry :
请关注,记得标为原始粉丝。