v4l2驱动编程,摄像头v4l2驱动编写
V4是V4L2的升级版,它为linux下的视频设备程序提供了一个windows sockets规范。包括一组数据结构和底层V4L2驱动程序接口。
1.常见的结构定义在内核目录include/Linux/videodev2.h中。
strutv 4 l 2 _ req Buffers//申请帧缓冲,对应命令VIDIOC_REQBUFS
Struct v4l2_capability//视频设备的功能对应命令VIDIOC_QUERYCAP。
strutv 4 l 2 _ input//视频输入信息,对应命令VIDIOC_ENUMINPUT
strutv 4 l 2 _ standard//PAL、NTSC等视频标准对应的是命令VIDIOC_ENUMSTD。
struct v4l2_format//frame的格式对应命令VIDIOC_G_FMT、VIDIOC_S_FMT等。
struct v4l2_buffer//driver中的一帧图像缓存,对应命令VIDIOC_QUERYBUF。
strutv 4 l 2 _ crop//视频信号的矩形边框
V4l2_std_id//视频系统
2.include/Linux/videodev2.h中也定义了常用的IOCTL接口命令。
VIDIOC_REQBUFS //分配内存
VIDIOC_QUERYBUF //将VIDIOC _ REQBUFS中分配的数据缓存转换为物理地址
VIDIOC_QUERYCAP//查询驱动函数
VIDIOC_ENUM_FMT//获取当前驱动支持的视频格式
VIDIC _ S _ FMT//设置当前驱动的频率捕获格式
VIDIOC_G_FMT//读取当前驱动的频率捕获格式
VIDIOC_TRY_FMT//验证当前驱动程序的显示格式
VIDIOC_CROPCAP//查询驱动的剪枝能力
VIDIOC_S_CROP//设置视频信号的矩形边框
VIDIOC_G_CROP//读取视频信号的矩形帧
VIDIOC_QBUF//从缓存中读取数据
VIDIOC_DQBUF//将数据放回缓存队列
VIDIOC_STREAMON//启动视频显示功能
VIDIOC_STREAMOFF//结束视频显示功能
VIDIOC_QUERYSTD //检查当前视频设备支持的标准,如PAL或NTSC。
3.操作过程
V4L2提供了很多访问接口,您可以根据自己的具体需求选择操作方式。应该注意的是,很少有驱动程序完全实现所有的接口功能。因此,使用时需要参考驱动程序源代码或仔细阅读驱动程序提供商的说明。
以下是操作流程,供参考。
(1)打开设备文件。
int fd=open(Devicename,mode);
设备名称:/dev/video0 、/dev/video1 ……
模式:O_RDWR [ O_NONBLOCK]
如果在非阻塞模式下调用视频设备,当没有可用的视频数据时,它将不会阻塞,并将立即返回。
(2)获得设备的能力。
struct v4l2_capability能力;
int ret=ioctl(fd,VIDIOC_QUERYCAP,capability);
看设备有什么功能,比如有没有视频输入功能。
(3)选择视频输入。
struct v4l2_input输入;
.初始化输入
int ret=ioctl(fd,VIDIOC_QUERYCAP,input);
一个视频设备可以有多个视频输入。如果只有一个输入,该功能可以省略。
(4)检测视频支持的系统
v4l2 _ std _ id std
做{
ret=ioctl(fd,VIDIOC_QUERYSTD,STD);
} while(ret==-1 errno==EAGAIN);
开关(标准){
案例V4L2_STD_NTSC:
//……
案例V4L2_STD_PAL:
//……
}
(5)设置视频采集格式
struct v4l2 _ format fmt
fmt . TYPE=v4 L2 _ BUF _ TYPE _ VIDEO _ OUTPUT;
fmt . fmt . PIX . pixel format=v4 L2 _ PIX _ FMT _ UYVY;
fmt.fmt.pix.height=高度;
fmt.fmt.pix.width=宽度;
fmt . fmt . pix . FIELD=v4 L2 _ FIELD _ INTERLACED;
ret=ioctl(fd,VIDIOC_S_FMT,fmt);
if(ret) {
佩罗尔(维迪奥克_ S _ FMT n );
关闭(FD);
return-1;
}
(6)向驱动程序申请帧缓冲。
struct v4l2 _ requestbuffers req
if (ioctl(fd,VIDIOC_REQBUFS,req)==-1) {
return-1;
}
缓存的数量是在v4l2_requestbuffers结构中定义的,驱动会相应地申请相应数量的视频缓存。可以使用多个缓冲器来建立FIFO,以提高视频捕获的效率。
(7)获取每个缓存的信息,并将其映射到用户空间。
typedef结构VideoBuffer {
void * start
size_t长度;
}视频缓冲区;
video buffer * buffers=calloc(req . count,sizeof(* buffers));
struct v4l2 _ buffer buf
for(numBufs=0;numBufs req.countnumufs){//映射所有缓存
memset( buf,0,sizeof(buf));
BUF . TYPE=v4 L2 _ BUF _ TYPE _ VIDEO _ CAPTURE;
buf . MEMORY=v4l 2 _ MEMORY _ MMAP;
buf.index=numBufs
If (ioctl (fd,vidioc _ query buf,buf)==-1){//获取对应索引的缓存信息,这里主要用长度信息和偏移量信息来完成下面的mmap操作。
return-1;
}
缓冲区[数字]。长度=buf.length
//转换为相对地址
缓冲区[数字]。start=mmap(NULL,buf.length,
PROT _读 PROT _写,
MAP_SHARED,
fd,buf . m . offset);
if(缓冲区[numBufs]。start==MAP_FAILED) {
return-1;
}
(8)开始收集视频。
int BUF _ TYPE=v4 L2 _ BUF _ TYPE _ VIDEO _ CAPTURE;
int ret=ioctl(fd,VIDIOC_STREAMON,buf _ type);
(9)取出FIFO缓冲器中的采样帧缓冲器。
struct v4l2 _ buffer buf
memset( buf,0,sizeof(buf));
BUF . TYPE=v4 L2 _ BUF _ TYPE _ VIDEO _ CAPTURE;
buf . MEMORY=v4l 2 _ MEMORY _ MMAP;
buf . index=0;//此值由以下ioctl返回
if (ioctl(fd,VIDIOC_DQBUF,buf)==-1)
{
return-1;
}
根据返回的buf.index找到对应的mmap映射缓存,取出视频数据。
(10)将刚刚处理的缓冲区放回队列的末尾,以便循环回收。
if (ioctl(fd,VIDIOC_QBUF,buf)==-1) {
return-1;
}
(11)停止视频采集。
int ret=ioctl(fd,VIDIOC_STREAMOFF,buf _ type);
(12)关闭视频设备。
关闭(FD);
关于视频捕捉模式
一般操作系统将系统使用的内存分为用户空间和内核空间,分别由应用程序和操作系统管理。应用程序可以直接访问内存的地址,而内核空间存储的是内核访问的代码和数据,用户无法直接访问。v4l2捕获的数据最初存储在内核空间,这意味着用户不能直接访问这个内存,必须通过某种方式改变地址。
有三种视频采集方法:
1)使用读写方法:直接使用读写函数进行读写。这种方法最简单,但是在用户空间和内核空间不断复制数据,占用用户空间和内核空间大量内存,效率低下。
2)内存映射法(mmap):将设备中的内存映射到应用程序中的内存控件,直接处理设备的内存,是一种有效的方法。上面的mmap函数就是这样使用的。
3)用户指针模式:内存由应用在用户空间分配,地址传递给内核中的驱动,然后v4l2驱动直接将数据填充到用户空间的内存中。这需要将v4l2_requestbuffers中的存储器域设置为V4L2_MEMORY_USERPTR。
第一种方法效率最低,后两种方法可以提高执行效率,但是对于mmap方法,文档中有一个描述——请记住,缓冲区是在物理内存中分配的,而不是可以换出到磁盘的虚拟内存。应用程序应该使用munmap()函数尽快释放缓冲区。(使用mmap方法时,缓冲区分配在内核空间。在这种情况下,这些缓冲区不能交换到虚拟内存中。这种方法虽然不影响读写效率,但总是占用内核空间的内存。在系统内存有限的情况下,如果有大量的进程同时运行,会对系统的整体性能产生一定的影响。)
所以对于三种视频拍摄方式的选择,推荐的顺序是userptr、mmap、读写。使用mmap或userptr时,有一个循环缓冲队列的概念。在这个队列中,有N个缓冲区,驱动程序采集的视频帧数据存储在每个缓冲区中。每次使用VIDIOC_DQBUF取出一个缓冲区并处理数据时,都必须使用VIDIOC_QBUF将这个缓冲区再次放回循环缓冲队列中。循环缓冲队列也使得这两种视频采集方式的效率高于直接方式。
读/写.