v4l2 学习笔记1--基本概念
写在前面:
最近打算系统的学习一下v4l2,希望能通过笔记来总结,带着问题来学习,让知识由杂乱变得清晰,由浅入深,逐渐理清脉络。
本文主要希望从宏观的层面来弄清“是什么?”,“为什么?”,“做了什么?”等相关问题,力求避免代码细节,一些参考文章,附在末尾,在此对文章作者一并感谢,感谢他们的分享精神。
感谢博客园,能让我和朋友一起,一点点来积累知识,也方便交流共享。
限于作者知识有限,若有不正确的地方,敬请指正。
1. v4l2基本概念
(1)什么是v4l2?
video4linux2(V4L2)是Linux内核中关于视频设备的内核驱动。
(2)支持哪些接口类型?视频设备指哪些?
1)视频采集接口(video capture interface):高频头,摄像头
2)视频输出接口 (video output interface):视频图像设备,如输出电视信号格式的设备
3)直接传输视频接口(video overlay interface):视频采集设备采集信号直接输出到输出设备,不经过CPU
4)视频间隔消隐信号接口(VBI interface):使应用可以访问传输消隐期的视频信号。
5)收音机接口(radio interface):处理从AM或FM高频头设备接收来的音频流。
(3)设备文件?
字符设备
主设备号:81
1)视频设备:
video capture device
video output device
video overlay device
设备文件:/dev/video/videoX major number: 81 minor number: 0-63
2)radio device:
设备文件:/dev/radio0~radio63 major number: 81 minor:64-127
3)teletext设备:
minor: 192-223
4)VBI(vertical blanking interval) device
设备文件:/dev/vbi0~31 major number: 81 minor:224-255
(4)用户空间与内核空间如何交互?
控制:ioctl系统调用
内存映射:mmap
(5)主要ioctl控制命令
ioctl命令所在文件: linux/drivers/include/uapi/linux/videodev2.h
VIDIOC_QUERYCAP /*查询能力*/
VIDIOC_G_FMT /*获得格式*/
VIDIOC_S_FMT /*设置格式*/
VIDIOC_REQBUFS /*申请内存*/
VIDIOC_G_FBUF /*获得Framebuffer*/
VIDIOC_S_FBUF /*设置Framebuffer*/
VIDIOC_OVERLAY /*设置Overlay*/
VIDIOC_QBUF /*将内存加入队列*/
VIDIOC_DQBUF /*从队列取出内存*/
VIDIOC_STREAMON /*开始流*/
VIDIOC_STREAMOFF /*停止流*/
VIDIOC_G_CTRL /*得到控制*/
VIDIOC_S_CTRL /*设置控制*/
(6) v4l2简单框图
(7)V4L2支持三种I/O方式:
Read/Write:通过调用设备节点文件的read/write函数,与设备交互数据。(默认)
Stream I/O:流操作I/O,只传递数据缓冲区指针,不拷贝数据。
需要调用VIDIOC_REQBUFS ioctl来通知设备。
两种方式memory map和user buffer。
overlay : memory to memory 传输。将数据从内存拷贝到显存中。overlay设备独有的。
(8)Capture device 启动设备方式:
调用VIDIOC_REQBUFS ioctl 来分配缓冲区队列;
调用VIDIOC_STREAMON ioctl 通知设备开始stream IO
调用VIDIOC_QBUF ioctl 从设备获取一帧视频数据;
使用完数据后,调用 VIDIOC_DQBUF 将缓冲区还给设备,以便设备填充下一帧数据。
(9)
//待续。。。
2. 重要结构
头文件:include/linux/videodev2.h
include/media/v4l2-dev.h
核心实现:driver/media/video/v4l2-dev.c
重要数据结构:
struct video_device [v4l2-dev.h]
负责向内核注册字符设备
struct v4l2_device
管理所有的子设备
struct v4l2_subdev
子设备,实现具体的功能
v4l2_device, v4l2_subdev 看作所有设备和子设备的基类,编写驱动时,需要将基类嵌入到具体设备结构体,以实现继承设备基类。
常用数据结构:
1) 设备能力 v4l2_capability
2) 数据格式 v4l2_format
3) 像素格式 v4l2_pix_format
4) 请求缓冲 v4l2_requestbuffers
5) 数据流类型 v4l2_memory
3. 注册 video4linux 设备
(1)video_register_device 注册v4l设备 [drivers/media/video/v4l2-dev.h]
1) __video_register_device 的封装函数
2)驱动探测 probe到后被调用
(2)v4l2_fops接口 [v4l2-dev.c]
1)struct file_operations 类型,统一的应用层文件操作对应的驱动接口(字符设备)。
2)其成员函数调用对应 struct video_device 对象的fops成员中的接口。
3)struct video_device->fops 是具体v4l2摄像头驱动必须实现的接口。
图1: fops中的接口,通过struct file指针得到次设备号,进而在video_device数组中得到对应的video_device设备,最终可以调用这个设备的fops。
4. v4l2设备基本操作流程(从应用层看)
1)user space 打开设备
fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
2) 查询设备能力
获取设备的capability, 查看设备功能。
struct v4l2_capability
VIDIOC_QUERYCAP
3)设置优先级(可选)
VIDIOC_G_PRIORITY
VIDIOC_S_PRIORITY
4)配置设备
视频输入源的视频标准,VIDIOC_*_STD
视频数据的格式 , VIDIOC_*_FMT
视频输入端口, VIDIOC_*_INPUT
视频输出端口,VIDIOC_*_OUTPUT
选择视频输入
struct v4l2_input
VIDIOC_G_INPUT
VIDIOC_ENUMINPUT
VIDIOC_S_INPUT
5)遍历所有视频格式,查询驱动所支持的格式
struct v4l2_fmtdes
VIDIOC_ENUM_FMT
6)设置视频捕获格式
struct v4l2_format
VIDIOC_S_FMT
7)查询视频格式
a)查询一种格式 VIDIOC_G_FMT
b)遍历所有视频格式,查询驱动所支持的格式 VIDIOC_ENUM_FMT
8) 向驱动申请帧缓冲,内存,一般不超过5个,帧缓冲管理
struct v4l2_requestbuffers
VIDIOC_REQBUFS 分配内存
VIDIOC_QUERYBUF 把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
9) 开始捕捉图像数据(采集视频)
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
VIDIOC_STREAMON
10)出队列以取得已采集数据的帧缓冲,取得原始采集数据。
11)停止视频的采集
VIDIOC_STREAMOFF
12) 关闭视频设备
close(fd);
5. 从驱动层看v4l2
实现硬件相关的代码,并注册相关设备。
(1)硬件相关的代码:
1)具体硬件的控制代码
2)与v4l2框架绑定
(2)绑定:
1)数据结构(关系)绑定:自己的结构体绑定到v4l2框架中关联结构体
2)函数绑定:v4l2定义的空的函数指针,绑定为自己实现的函数。
图:v4l2 framework 简略版
(3)如何进行关系绑定:
1)根据需要“继承” v4l2_device 或v4l2_subdev结构体,添加需要的结构体成员,获得一个具体设备的结构体。即将这两个结构体嵌入到新定义的结构体中,并添加链表,锁,名字,操作方法等相关成员。
2)v4l2_device 与 v4l2 框架绑定:调用 v4l2_device_register 函数向v4l2 框架注册。
3)v4l2_subdev 与 v4l2_device 绑定:调用 v4l2_device_register_subdev 函数向父设备注册。
4)video_device 与 v4l2_device 绑定:将v4l2_device 的地址赋值给video_device的v4l2_dev即可。(不必要,只要能通过文件节点struct file找到 v4l2_device即可)
(5)如何进行函数绑定
将驱动所实现的函数赋值给相关的变量。
在 图v4l2 framework 中, 绿色方框都是需要绑定并实现的。
v4l2_file_operations和v4l2_ioctl_ops是必须实现的。
v4l2_subdev_ops下的八类ops中,v4l2_subdev_core_ops是必须实现的,其余需要根据设备类型选择实现的。
比如video capture类设备需要实现v4l2_subdev_core_ops, v4l2_subdev_video_ops。
1)v4l2_file_operations:实现文件类操作,比如open,close,read,write,mmap等。但是ioctl是不需要实现的,一般都是用video_ioctl2代替。
2)v4l2_ioctl_ops:V4L2导出给应用层使用的所有ioctl都在这个地方实现
3)v4l2_subdev_ops:v4l2_subdev有可能需要实现的ops的总合。
分为8类,core,audio,video,vbi,tuner ......等。
ps:个人理解,如果没有具体的设备注册,v4l2 框架注册到内核驱动中,框架和具体硬件的接口都为NULL,也不会有提供给应用层的具体设备的设备文件。内核应该是先注册框架层,然后各个具体驱动的注册,就会把自己的相关接口挂接到框架层的接口,并留出给应用层的设备文件。
v4l2 core 层在内核中的存在形式,以EXPORT_SYMBOL导出接口供底层调用,v4l2相关的重要数据结构。
v4l2的设备和驱动也是通过platform总线接口注册的。//待补充
**********
references:
1. V4L2驱动程序架构