Linux--V4L2摄像头驱动框架及UVC浅析

5 篇文章 0 订阅

 一、前言

对于一个usb摄像头,它的内核驱动源码位于/drivers/media/usb/uvc/

核心层:V4L2_dev.c文件

硬件相关层: uvc_driver.c文件

UVC驱动和V4L2之间主要的交互方式:
设备注册和初始化
UVC驱动在系统启动或USB视频设备插入时,会被初始化并注册为V4L2设备。这一过程包括设置设备的V4L2能力、支持的格式、控制操作等,确保UVC设备能够通过V4L2接口与用户空间应用程序交互。
控制查询和设置
UVC驱动实现了一系列V4L2控制类(control class)接口,允许用户空间应用程序查询和设置视频设备的参数,如亮度、对比度、饱和度等。这些控制操作通过UVC驱动转换为USB传输,与硬件设备交互。
缓冲区管理
UVC驱动使用V4L2提供的videobuf2 API来管理视频帧的缓冲区。这包括缓冲区的分配、队列管理、数据传输等。Videobuf2作为V4L2的一部分,提供了一个高效的机制来处理视频数据的缓冲和流转。
数据流控制
用户空间应用程序可以通过V4L2接口来启动和停止视频流。UVC驱动响应这些请求,通过USB接口与硬件设备进行交互,控制视频数据的捕获和传输。
事件处理
UVC驱动能够处理来自硬件的事件,比如状态变化、错误报告等,并通过V4L2框架将这些事件上报给用户空间应用程序,使得应用程序能够对特定的硬件事件做出响应。
格式协商
在视频捕获或输出过程中,UVC驱动和用户空间应用程序会通过V4L2接口进行格式协商,确定视频数据的格式、分辨率、帧率等参数。UVC驱动根据这些协商结果配置USB视频设备,以满足应用程序的需求。

本篇记录基于对6.8.8.8内核下vivid-core.c文件(虚拟视频驱动程序)的分析,梳理Linux系统中vedio视频设备的驱动框架。   

二、虚拟摄像头驱动源码分析

1、入口函数

module_init(vivid_init);

vivid_init
	//注册vivid设备和驱动
	platform_device_register(&vivid_pdev);
	platform_driver_register(&vivid_pdrv);

通过入口函数将平台设备和平台驱动结构体注册到内核中,关于具体的设备和驱动注册先关内容可以看Linux--平台设备、平台驱动的注册源码分析-CSDN博客这篇。

在代码中,vivid_pdrv 平台驱动没有 of_match_table 字段,因为该驱动程序不依赖设备树进行匹配和初始化。如果是真实的硬件驱动程序需要支持设备树匹配,则需要定义 of_match_table 字段,并提供一个设备树兼容字符串数组,也就是compatible属性值。

2、probe()函数

vivid_init()里分别注册了vivid_pdevvivid_pdrv,注册后,当他们匹配时,内核会自动则会调用该驱动程序probe()初始化该设备。在probe()里面主要进行初始化、注册等相关流程。

vivid_probe
   1) vivid_create_instance			/* 创建实例 */
    	dev = kzalloc(sizeof(*vivid_dev), GFP_KERNEL);/* 分配video_devicede */
    	v4l2_device_register		/* 初始化v4l2_device */
    	
    2)    static int vivid_create_devnodes(struct platform_device *pdev,
				 struct vivid_dev *dev, int inst,
				 unsigned int cec_tx_bus_cnt,
				 v4l2_std_id tvnorms_cap,
				 v4l2_std_id tvnorms_out,
				 unsigned in_type_counter[4],
				 unsigned out_type_counter[4])
{
      	/* 设置video_device */
    	1.vfd->fops = &vivid_fops;       /*也就是在probe里的这一步实现设备操作和驱动操作的绑定*/
		  vfd->ioctl_ops = &vivid_ioctl_ops;
		  vfd->release = video_device_release_empty;
		2.vfd->v4l2_dev = &dev->v4l2_dev;
		3.设置"ctrl属性"(用于APP的ioctl)
		   	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
			v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out);
			...
   
         /*注册vedio_device*/   /*分配主次设备号*/
    	video_register_device(video_device, type:VFL_TYPE_GRABBER, nr)
            __video_register_device
            	vdev->cdev = cdev_alloc();
				vdev->cdev->ops = &v4l2_fops;
				video_devices[vdev->minor] = vdev;//将video_device放入全局数组中
				ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
				if (vdev->ctrl_handler == NULL)
				vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;

关键点:

1、分配video_device结构体内存          video_device_alloc()kzalloc()

2、设置video_device       .fops.ioctl_opsdev;、

也就是在probe里的这一步实现设备操作和驱动操作的绑定

3、注册video_device结构体      video_register_device()

3、操作函数(open、read、wirite等)

1、open

app:     open("/dev/video0",....)

---------------------------------------------------
drv:     v4l2_fops.v4l2_open
            vdev = video_devdata(filp);  // 根据次设备号从数组中得到video_device
            ret = vdev->fops->open(filp);
                        vivi_ioctl_ops.open
                           v4l2_fh_open

当应用层发生系统调用时,会先调用到v4l2_fops中的v4l2_open,v4l2_open会找到对应设备video_device的file opr中的open,而设备中的open是在驱动注册后调用probe函数与驱动函数定义的open绑定的,这样就实现了video设备用户空间open调用驱动open的过程。

2、ioctl

app:    read ....
		
-----------------------------------------------

drv:    v4l2_fops.v4l2_read
            struct video_device *vdev = video_devdata(filp);
            ret = vdev->fops->read(filp, buf, sz, off);

核心层v4l2_ctrl_handler会找到video_device的fops 。过程如下(在上文中通过v4l2_ctrl_handler_setup设置了某些属性的ioctl处理函数)

 __video_do_ioctl
	struct video_device *vfd = video_devdata(file);
		v4l2_is_known_ioctl(cmd)
        info = &v4l2_ioctls[_IOC_NR(cmd)]; 		/* v4l2_ioctls数组存有全部IOCTL_INFO,含有													ioctl函数指针 */
        ret = info->func(ops, file, fh, arg);	/* 调用对应的ioctl函数 */

三、UVC(USB Video Class)

UVC全称为USB Video Class,即:USB视频类,是一种为USB视频捕获设备定义的协议标准。是Microsoft与另外几家设备厂商联合推出的为USB视频捕获设备定义的协议标准,已成为USB org标准之一。

最新的UVC版本为UVC 1.5,由USB Implementers Forum定义包括基本协议及负载格式。             

USB摄像头示例如下:

对于框架具体细节可以看这篇UVC 1.5 Class Specification 简解_uvc1.5-CSDN博客

UVC硬件模型

首先从USB官网下载标准协议相关资料:Video Class -> Video Class 1.5 document set (.zip format, size 6.58MB)
USB_Video_Example 1.5.pdf里,可以得知硬件模型分为两部分:VC interfaceVS interface
VC interface用于控制,内部又分为多个unitterminalunit用于内部处理,terminal用于内外链接;(在程序里Unit/Terminal都称为entity)
VS interface用于传输,内部包括视频数据传输的端点以及摄像头支持的视频格式等信息;

每个视频有且仅有一个Vieo Control接口和可有多个Video Streaming接口;

一个接口,就相当于一个逻辑上的USB设备。
现在,想象一下当USB摄像头插上主机,就相当于同时插上了两个设备,可通过函数去选中其中一个设备,从而去操作它。
一个设备用于控制,比如设置亮度等;
一个设备用于获取数据,选择所支持的某个格式等;
这样就基本把控制和数据分开,要控制则操作控制接口,要数据则通过数据接口。

UVC驱动的重点在于:
   描述符的分析
   属性的控制: 通过VideoControl Interface来设置
   格式的选择:通过VideoStreaming Interface来设置
   数据的获得:通过VideoStreaming Interface的URB来获得

参考文章:

​​​​​​【Linux驱动】Linux--虚拟摄像头vivid驱动分析(基于5.4内核)-CSDN博客

【转载】linux摄像头驱动_linux 摄像头驱动-CSDN博客           

https://blog.csdn.net/chunchun2021/article/details/136634409      

  • 13
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值