USB摄像头驱动程序分析

news/2024/12/5 5:52:55/

uvc驱动程序主要位于3.42内核\drivers\media\video\uvc文件夹中。由于本身十分复杂,在此只做简单分析。
在这里插入图片描述这幅图来源于UVC的规格书。可以看到一个完整的UVC设备主要分为两个部分:
通过VideoControl Interface来控制,
通过VideoStreaming Interface来读视频数据,
VC里含有多个Unit/Terminal等功能模块,可以通过访问这些模块进行控制,比如调亮度。

分析UVC驱动调用过程

在uvc_v4l2.c中,有:

const struct v4l2_file_operations uvc_fops = {.owner		= THIS_MODULE,.open		= uvc_v4l2_open,.release	= uvc_v4l2_release,.unlocked_ioctl	= uvc_v4l2_ioctl,
#ifdef CONFIG_COMPAT.compat_ioctl32	= uvc_v4l2_compat_ioctl32,
#endif.read		= uvc_v4l2_read,.mmap		= uvc_v4l2_mmap,.poll		= uvc_v4l2_poll,
#ifndef CONFIG_MMU.get_unmapped_area = uvc_v4l2_get_unmapped_area,
#endif
};

通过以上这些函数接口实现应用程序的系统调用。
下面一个一个分析:

  1. open:
    uvc_v4l2_open

ioctr:下面的调用通过uvc_v4l2_ioctl函数实现的:

  1. VIDIOC_QUERYCAP // video->streaming->type 应该是在设备被枚举时分析描述符时设置的
		if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)cap->capabilities = V4L2_CAP_VIDEO_CAPTURE| V4L2_CAP_STREAMING;elsecap->capabilities = V4L2_CAP_VIDEO_OUTPUT| V4L2_CAP_STREAMING;
  1. VIDIOC_ENUM_FMT // format数组应是在设备被枚举时设置的
 format = &video->streaming->format[fmt->index];
  1. VIDIOC_G_FMT //这个ioctr命令就是为了获取UVC设备支持的format和frame并返回
    uvc_v4l2_get_format // USB摄像头支持多种格式fromat, 每种格式下有多种frame(比如分辨率)
            	struct uvc_format *format = video->streaming->cur_format;struct uvc_frame *frame = video->streaming->cur_frame;
  1. VIDIOC_TRY_FMT //对比用户设置的默写参数UVC设备是否支持
    uvc_v4l2_try_format

         /* Check if the hardware supports the requested format. *//* Find the closest image size. The distance between image sizes is* the size in pixels of the non-overlapping regions between the* requested size and the frame-specified size.*/
    
  2. VIDIOC_S_FMT // 只是把参数保存起来,还没有发给USB摄像头

        uvc_v4l2_set_formatuvc_v4l2_try_formatvideo->streaming->cur_format = format;video->streaming->cur_frame = frame;
  1. VIDIOC_REQBUFS //申请缓冲区
        uvc_alloc_buffersfor (; nbuffers > 0; --nbuffers) {mem = vmalloc_32(nbuffers * bufsize);if (mem != NULL)break;}
  1. VIDIOC_QUERYBUF //查询已经分配完成的buf
uvc_query_buffer__uvc_query_buffermemcpy(v4l2_buf, &buf->buf, sizeof *v4l2_buf);  // 复制参数
  1. mmap
	uvc_v4l2_mmap

//之前的 操作,在内核空间中申请了buffer空间,但是在进一步的操作过程中,对内核空间内存的读写需要涉及到相对复杂的操作,因此需要将分配的buffer空间映射到用户空间当中。

  1. VIDIOC_QBUF //将buffer放在队列当中,有数据再将buffer取出来
        uvc_queue_bufferlist_add_tail(&buf->stream, &queue->mainqueue);list_add_tail(&buf->queue, &queue->irqqueue);
  1. VIDIOC_STREAMON
        uvc_video_enable(video, 1)  // 把所设置的参数发给硬件,然后启动摄像头/* Commit the streaming parameters. */uvc_commit_videouvc_set_video_ctrl  /* 设置格式fromat, frame */ret = __uvc_query_ctrl(video->dev /* 哪一个USB设备 */, SET_CUR, 0,video->streaming->intfnum  /* 哪一个接口: VS */,probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,uvc_timeout_param);/* 启动:Initialize isochronous/bulk URBs and allocate transfer buffers. */uvc_init_video(video, GFP_KERNEL);uvc_init_video_isoc / uvc_init_video_bulkurb->complete = uvc_video_complete; (收到数据后此函数被调用,它又调用video->decode(urb, video, buf); ==> uvc_video_decode_isoc/uvc_video_encode_bulk => uvc_queue_next_buffer => wake_up(&buf->wait);)usb_submit_urb                    	
  1. poll //等待数据发生,等待过程中处于休眠状态
       uvc_v4l2_poll            uvc_queue_pollpoll_wait(file, &buf->wait, wait);  // 休眠等待有数据
  1. VIDIOC_DQBUF //将buffer重新放回队列当中等待数据接收
    uvc_dequeue_buffer
    list_del(&buf->stream);

  2. VIDIOC_STREAMOFF
    uvc_video_enable(video, 0);
    usb_kill_urb(urb);
    usb_free_urb(urb);

分析设置亮度过程:

ioctl: VIDIOC_S_CTRLuvc_ctrl_setuvc_ctrl_commit__uvc_ctrl_commit(video, 0);uvc_ctrl_commit_entity(video->dev, entity, rollback);ret = uvc_query_ctrl(dev  /* 哪一个USB设备 */, SET_CUR, ctrl->entity->id  /* 哪一个unit/terminal */,dev->intfnum /* 哪一个接口: VC interface */, ctrl->info->selector,uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),ctrl->info->size);
总结:
  1. UVC设备有2个interface: VideoControl Interface, VideoStreaming Interface

  2. VideoControl Interface用于控制,比如设置亮度。它内部有多个Unit/Terminal(在程序里Unit/Terminal都称为entity)
    可以通过类似的函数来访问:
    ret = uvc_query_ctrl(dev /* 哪一个USB设备 /, SET_CUR, ctrl->entity->id / 哪一个unit/terminal /,
    dev->intfnum /
    哪一个接口: VC interface */, ctrl->info->selector,
    uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
    ctrl->info->size);

  3. VideoStreaming Interface用于获得视频数据,也可以用来选择fromat/frame(VS可能有多种format, 一个format支持多种frame, frame用来表示分辨率等信息)
    可以通过类似的函数来访问:
    ret = __uvc_query_ctrl(video->dev /* 哪一个USB设备 /, SET_CUR, 0,
    video->streaming->intfnum /
    哪一个接口: VS */,
    probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
    uvc_timeout_param);

  4. 我们在设置FORMAT时只是简单的使用video->streaming->format[fmt->index]等数据,
    这些数据哪来的?
    应是设备被枚举时设置的,也就是分析它的描述符时设置的。

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


http://www.ppmy.cn/news/563100.html

相关文章

WINCE USB摄像头驱动终于初步完成了!!

驱动是根据微软的UVC万能驱动改写的,改正了原驱动的一些错误和无效传输,增加了改变分辨率的功能。但是驱动现在还不稳定,显示总跳。如果大神们愿意抽时间帮我检查下,我可以提供驱动源码和测试程序,在下面评论留言就成。…

上位机与两台PLC之间无线以太网通信

本文以组态王和2台三菱FX5u PLC为例,介绍组态王与多台 PLC的无线以太网通信实现过程。在本方案中采用了三菱PLC无线通讯终端DTD419MB,作为实现无线通讯的硬件设备。 在这一无线以太网通讯系统的搭建中,用户无需更改网络参数和原有程序&#…

python 绘制一个四瓣花图

利用turtle库绘制一个四瓣花图形 import turtle as t for i in range(4):t.seth(90*(i1))t.circle(200, 90)t.seth(-90i*90)t.circle(200, 90) t.done()

花朵效果

一、新建一个800*800分辨率画布, 二、用黑白渐变工具,拉出一个渐变, 三、点击滤镜——扭曲——波浪,参数如下、 四、点击滤镜——扭曲——极坐标 五、点击滤镜——滤镜库——选择素描————铬黄渐变 六、最后添加一个渐变颜色&a…

Python-绘制花朵

import turtle as t t.penup() t.fd(-200) t.write("一朵小花\n", align"right", font("楷体", 16, "bold"))def draw_leaf():for i in range(2):for j in range(15):t.forward(5)t.right(6)t.right(90)t.goto(0,-150) t.left(90) t.…

ps制作花朵形状

操作步骤: (1)新建文件:800*600,分辨率72,背景白色,颜色模式RGB。 (2)新建图层1 ,使用椭圆选框工具,在图层1上,绘制一个垂直方向的椭…

SwiftUI 人工智能教程之图像识别植物或花朵通过图片和相机

实战需求 SwiftUI 人工智能教程之图像识别植物或花朵通过图片和相机 本文价值与收获 看完本文后,您将能够作出下面的界面 基础代码 载入模型guard let model = try? VNCoreMLModel(for: DDModel(configuration: MLModelConfiguration()).model)else {return}实战代码 1、…

python旅游推荐系统-计算机毕设 附源码82884

旅游推荐系统 摘 要 随着社会的快速发展和人们生活水平的不断提高,旅游已逐渐成为人们生活的重要组成部分,用户能够获取旅游信息的渠道也随信息技术的广泛应用而增加。大量未经过滤的信息在展示给用户的同时,也淹没了用户真正感兴趣的信息。为…