视频监控—uvc驱动框架分析
- 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3)
- 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统
- 参考资料:USB_Video_Example 1.5、UVC 1.5 Class specification
- 开发环境:Linux-3.4.2内核、arm-linux-gcc-4.3.2工具链、源码分析版本为:Linux-2.6.31.14
- 源码仓库:https://gitee.com/d_1254436976/Embedded-Linux-Phase-3
目录
-
视频监控—uvc驱动框架分析 - 一、UVC
- 二、以usb摄像头为例分析uvc框架
- 1、usb摄像头的拓扑结构
- 2、uvc_v4l2.c源码分析
- 2.1 打开驱动`open`
- 2.2 获取该设备的类型 VIDIOC_QUERYCAP
- 2.3 列举摄像头的数据格式 VIDIOC_ENUM_FMT
- 2.4 获得摄像头的数据格式 VIDIOC_G_FMT
- 2.5 测试是否支持该摄像头的数据格式 VIDIOC_TRY_FMT
- 2.6 设置参数VIDIOC_S_FMT
- 2.7 请求系统分配缓冲区VIDIOC_REQBUFS
- 2.8 查询所分配的缓冲区的信息 VIDIOC_QUERYBUF
- 2.9 映射缓冲区mmap
- 2.10 把缓冲区放入队列 VIDIOC_QBUF
- 2.11 启动摄像头 VIDIOC_STREAMON
- 2.12 采用poll机制等待数据
- 2.13 有数据后从队列里取出缓冲区VIDIOC_DQBUF
- 2.14 若此时需要关闭摄像头 VIDIOC_STREAMOFF
- 3、总结
- 4、修改usb摄像头数据
- 三、总结
一、UVC
UVC全称为USB Video Class,即:USB视频类,是一种为USB视频捕获设备定义的协议标准,在不需要安装任何的驱动程序下即插即用。
视频设备的USB设备类定义适用于用于操作视频和视频相关功能的复合设备中的所有设备或函数。包括桌面摄像机(或“网络摄像机”)、数字摄像机、模拟视频转换器、模拟和数字电视调谐器以及支持视频流的静态图像摄像机,也适用于使用时间编码器压缩视频的视频设备。
二、以usb摄像头为例分析uvc框架
1、usb摄像头的拓扑结构
整个拓扑结构主要分为两大部分:
-
VideoControl Interface(视频控制接口):控制特定视频功能的功能行为,主机可以操作Unit(单元)和Terminal(终端)内部的视频功能。
在这个部分中,有一个Video Function
部分,有以下的Unit(单元)和Terminal(终端)组成: -
- Input Terminal(输入终端):作为视频功能的“外部世界”和视频功能内部其他单元之间的接口。它充当数据流进视频功能的容器。
功能:在从数据源中提取数据之后表示传入数据的来源。数据可以包括音频和与视频流相关联的元数据。
- Input Terminal(输入终端):作为视频功能的“外部世界”和视频功能内部其他单元之间的接口。它充当数据流进视频功能的容器。
-
- Output Terminal(输出终端):作为视频功能内部单元与“外部世界”之间的接口。它作为视频信息的出口,流出视频功能。
功能:表示传出数据的接收器。
- Output Terminal(输出终端):作为视频功能内部单元与“外部世界”之间的接口。它作为视频信息的出口,流出视频功能。
-
- Camera Terminal(摄像头终端):控制传输视频流的设备组件的机械(或等效的数字)特征。因此,它只适用于具有可控制镜头或传感器特性的视频捕捉设备。
-
- Selector Unit(选择单元):从n个输入数据流中选择,并将它们不改变地路由到单个输出流(类似多路选择器)。它表示一个源选择器,能够在许多源中进行选择。
- Selector Unit(选择单元):从n个输入数据流中选择,并将它们不改变地路由到单个输出流(类似多路选择器)。它表示一个源选择器,能够在许多源中进行选择。
-
- Processing Unit(处理单元):控制流过它的视频的图像属性。
- Processing Unit(处理单元):控制流过它的视频的图像属性。
-
VideoStreaming Interface(视频流控制接口):视频流接口用于在主机和视频功能之间交换数据流。
2、uvc_v4l2.c源码分析
对于一个设备驱动的分析,最好的分析方式是根据应用层调用驱动的函数执行顺序来分析:
2.1 打开驱动open
在uvc_fops
结构体中可以找到该函数的函数指针。
之后就会调用uvc_v4l2_ioctl()
函数对该设备进行设置
2.2 获取该设备的类型 VIDIOC_QUERYCAP
对于分配的设备结点,需要通过uvc_v4l2_ioctl()
来对该设备结点的类型进行设置。
设备类型在video->streaming->type
,其值应该在设备被枚举时分析描述符时被设置。
2.3 列举摄像头的数据格式 VIDIOC_ENUM_FMT
数据格式存储在video->streaming->format[fmt->index]
数组,对于此数组应该在设备被枚举时分析描述符时被设置。
2.4 获得摄像头的数据格式 VIDIOC_G_FMT
对于USB摄像头,其支持多种的格式fromat
,每种格式下有多种分辨率frame
对于video->streaming->cur_format
和video->streaming->cur_frame
,其值的设置应该在设备被枚举时分析描述符时被设置
2.5 测试是否支持该摄像头的数据格式 VIDIOC_TRY_FMT
2.6 设置参数VIDIOC_S_FMT
把上面的到参数保存起来,此时参数仍未发给摄像头,即摄像头还没有开始摄像。
2.7 请求系统分配缓冲区VIDIOC_REQBUFS
此时分配的依旧是缓冲区的头部和设置头部信息,并未分配实际存储数据的空间。
2.8 查询所分配的缓冲区的信息 VIDIOC_QUERYBUF
根据其缓冲区的state
设置buf
的flags
2.9 映射缓冲区mmap
在此时才真正的分配存储数据的内存
2.10 把缓冲区放入队列 VIDIOC_QBUF
把上面已经拥有实际存储区域的缓存区采用尾插法插入队列中。
2.11 启动摄像头 VIDIOC_STREAMON
先设置流参数到设备流接口VideoStreaming interface
,后初始化设备。
2.12 采用poll机制等待数据
调用uvc_v4l2_poll()
函数,poll_wait
等待数据,何时何地被唤醒呢?
在 2.11 启动摄像头 VIDIOC_STREAMON
中的追踪到的uvc_init_video()
函数中存储了该uvc_video_complete
函数的地址,收到数据后调用该函数唤醒
2.13 有数据后从队列里取出缓冲区VIDIOC_DQBUF
从队列的头部开始取出第一个有数据的缓冲区,随后把该缓冲区从队列删除,待该缓冲区的数据处理完毕后,重新进入2.10 把缓冲区放入队列尾部,循环进行下一步
2.14 若此时需要关闭摄像头 VIDIOC_STREAMOFF
此时调用的函数与2.11 启动摄像头VIDIOC_STREAMON
的函数uvc_video_enable()
一致,但是传入的参数不一致,最终关闭该usb摄像头。
3、总结
对于上述根据应用程序调用usb摄像头驱动程序的分析,过程大致可以分为:
- open驱动----->2.1
- 设置设备的参数、数据格式------>2.2~~2.6
- 分配设置缓冲区------>2.7~~2.10
- 启动摄像头,调用poll机制等待数据----->2.11~~2.13
若无数据,则进程进入休眠
若有数据,则唤醒进程,处理完数据后重新进行2.10 - 使用完毕后关闭摄像头----->2.14
4、修改usb摄像头数据
以修改摄像头亮度为例子,肯定会调用到对应的ioctl
函数。
通过下面的函数调用可以知道,最终设置的是拓扑结构中的VideoControl Interface(视频控制接口)
三、总结
-
在实际usb摄像头时,主要接触这两个接口VideoControl Interface(视频控制接口)和VideoStreaming Interface(视频流控制接口);
-
VideoControl Interface 视频控制接口可用于控制,如设置摄像头的某些参数(亮度、对比度…),其内部有多个
Unit(单元)与Terminal(终端)
,每个对应的设置参数都不同;
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);
- 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);