一.UVC简介
摄像头分为两类:
1.CAMER接口的摄像头;
2.USB接口接口的摄像头;
这里主要介绍usb摄像头的设备驱动程序。
UVC全称为USB Video Class,即:USB视频类,是一种为USB视频捕获设备定义的协议标准。
如今的主流操作系统(如Windows XP SP2 and later, Linux 2.4.6 and later, MacOS 10.5 and later)都已提供 UVC 设备驱动,因此符合 UVC 规格的硬件设备在不需要安装任何的驱动程序下即可在主机中正常使用。使用 UVC 技术的包括摄像头、数码相机、类比影像转换器、电视棒及静态影像相机等设备。
Linux UVC driver(uvc) 驱动适用于符合USB视频类规范的摄像头设备,它包括V4L2内核设备驱动和用户空间工具补丁。只要符合这类标准,则不同厂商的USB camera设备,不需要特定的driver就能在Linux下使用。
V4L2:
简单的讲V4L2就是用来管理UVC设备的并且能够提供视频相关的一些API。那么这些API怎么使用或者能被谁使用呢。在Linux系统上有很多的开源软件能够支持V4L2。常见的有FFmpeg、opencv、Skype、Mplayer等等。
我们知道在linux下,一切设备皆是是文件,可以像访问普通文件一样对其进行读写。因此,我们不难猜出,V4L2提供的API实际上就是一系列read、write、open、ioctl等函数:
APP在应用层调用read、write、open等接口,调用库函数,触发swi软件异常,进入内核,最终会调用到驱动程序的open、read、write等等。
二.Windows系统
我们将usb设备插入到window操作系统,我们打开设备管理器:
右键属性 -> 详细信息 –> 属性 选择硬件 Id 查看:
可以得到插的usb摄像头VID=0x0c45、PID=0x6340。
此外我这usb摄像头还自带麦克风,因此也可以在设备管理器中看到:
window下camera设备测试,使用电脑微信打开视频功能,查看usbcamera是否正常。
三.配置UVC
驱动配置:
Device Drivers -->--- Multimedia support [ ] Filter media drivers (取消选择)Media core support ---><*> Video4Linux core (NEW) [*] Media Controller API (NEW)Media drivers --->[*] Media USB Adapters(启用usb总线的媒体驱动程序,drivers/media/usb) <*> USB Video Class(UVC)(我们的摄像头支持UVC,选择这个驱动即可)[*] UVC input events device supports(NEW)<> GSPCA based webcams --> (GSPCA 是一个法国程序员在业余时间制作的一个万能USB 摄像头驱动程序,在此可以选择对应类型USB摄像头的支持)<> SONIX Bayer USB Camer Driver (NEW)<> OV772x/OV965x/... 系列摄像头支持<> ....
usb插上camera后的打印:
[ 347.559618] usb 1-1: new high-speed USB device number 2 using ehci-pci
[ 347.926071] usb 1-1: New USB device found, idVendor=0c45, idProduct=6340
[ 347.926074] usb 1-1: New USB device strings: Mfr=2, Product=1, SerialNumber=0
[ 347.926076] usb 1-1: Product: USB 2.0 Camera
[ 347.926077] usb 1-1: Manufacturer: Sonix Technology Co., Ltd.
[ 347.981873] media: Linux media interface: v0.10
[ 347.986155] Linux video capture interface: v2.00
[ 348.130562] usb 1-1: 3:1: cannot get freq at ep 0x84
[ 349.190706] usbcore: registered new interface driver snd-usb-audio
[ 349.194058] uvcvideo: Found UVC 1.00 device USB 2.0 Camera (0c45:6340)
[ 349.217865] input: USB 2.0 Camera: USB Camera as /devices/pci0000:00/0000:00:11.0/0000:02:03.0/usb1/1-1/1-1:1.0/input/input6
[ 349.218030] usbcore: registered new interface driver uvcvideo
[ 349.218030] USB Video Class driver (1.1.1)
[ 349.270678] usb 1-1: 3:1: cannot get freq at ep 0x84
[ 349.374801] usb 1-1: 3:1: cannot get freq at ep 0x84
[ 349.389464] retire_capture_urb: 12 callbacks suppressed
从输出信息可以看到:
usb主机控制器ehci识别到了我们的usb设备,并且为usb设备分配了一个地址为2,同时可以看到我们这是一个高速usb设备,即我们的usb设备采用usb 2.0通信协议。
此外内核根据识别的usb设备信息,进行设备驱动匹配,匹配成功后,注册usb接口驱动snd-usb-audio(声卡驱动)、uvcvideo(usb摄像头驱动);
注册事件类输入设备节点/dev/input/event6,用于usb设备数据的上报;
此外,从输出信息中我们也可以得知usb设备的VID=0x0c45、PID=0x6340。
四.UVC驱动分析
UVC驱动路径:\kernel-5.10\drivers\media\usb\uvc
Kconfig uvc_ctrl.c uvc_driver.c uvc_isight.c uvc_queue.c uvc_v4l2.c uvcvideo.h
Makefile uvc_debugfs.c uvc_entity.c uvc_metadata.c uvc_status.c uvc_video.c
uvc_driver.c文件是UVC驱动模块的入口文件,我们定位到模块的入口和出口函数:
static int __init uvc_init(void)
{int ret;uvc_debugfs_init();ret = usb_register(&uvc_driver.driver);if (ret < 0) {uvc_debugfs_cleanup();return ret;}printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");return 0;
}static void __exit uvc_cleanup(void)
{usb_deregister(&uvc_driver.driver);uvc_debugfs_cleanup();
}module_init(uvc_init);
module_exit(uvc_cleanup);
由于UVC属于usb设备,所以在uvc_init函数,通过usb_register进行了usb接口驱动uvc_driver.driver的注册。
struct uvc_driver uvc_driver = {.driver = {.name = "uvcvideo",.probe = uvc_probe,.disconnect = uvc_disconnect,.suspend = uvc_suspend,.resume = uvc_resume,.reset_resume = uvc_reset_resume,.id_table = uvc_ids,.supports_autosuspend = 1,},
};
当在系统中insmod装载该驱动程序时,会在入口函数直接注册usb_drvier结构体,通过比较usb设备提供的信息,和id_table比较,若匹配,则表明驱动支持该usb。uvc_ids里面可以填充某个厂家特定的设备,也可以填充通用的设备,如下所示:
static const struct usb_device_id uvc_ids[] = {/* LogiLink Wireless Webcam */{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE| USB_DEVICE_ID_MATCH_INT_INFO,.idVendor = 0x0416,.idProduct = 0xa91a,.bInterfaceClass = USB_CLASS_VIDEO,.bInterfaceSubClass = 1,.bInterfaceProtocol = 0,.driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax },/* Genius eFace 2025 */{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE| USB_DEVICE_ID_MATCH_INT_INFO,.idVendor = 0x0458,.idProduct = 0x706e,.bInterfaceClass = USB_CLASS_VIDEO,.bInterfaceSubClass = 1,.bInterfaceProtocol = 0,.driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax },/* Microsoft Lifecam NX-6000 */{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE| USB_DEVICE_ID_MATCH_INT_INFO,.idVendor = 0x045e,.idProduct = 0x00f8,.bInterfaceClass = USB_CLASS_VIDEO,.bInterfaceSubClass = 1,.bInterfaceProtocol = 0,.driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax },{}
}
这里只是列举一部分uvc_ids。
假设我们接入一个usb摄像头,而这个usb摄像头的信息在uvc_ids中,驱动usb_driver.probe函数将会被调用。
待更新。。。。。。。