v4l2简介

V4L是linux内核中关于视频设备的子系统,为linux下的视频驱动提供了统一的接口,使应用程序可以使用统一的API操作不同的视频设备,简化视频系统的开发与维护

V4L2相比与V4L有更好的扩展性和灵活性

(一)V4L2支持设备:

V4L2可以支持多种设备,可以有以下几种接口:

1)视频采集接口

2)视频输出接口

3)直接传输视频接口:将视频采集设备上采集的信号直接输出到视频输出设备上,不用经过系统CPU

4)视频间隔消隐信号接口(VBI Interface):使引用可以访问传输消隐期的视频信号

5)收音机接口:

 

(二)V4L2设备处理流程

打开V4L2设备节点

int fd = open("/dev/video0",O_RDWR |O_NONBLOCK);

配置设备/查询设备属性

int ioctl (int fd, unsigned long int request, .../*args*/) ;

常见的request命令:

VIDIOC_REQBUFS:在内核空间中分配帧缓冲区

struct v4l2_requestbuffers req;

req.count=4;

req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

req.memory=V4L2_MEMORY_MMAP;

ioctl(fd,VIDIOC_REQBUFS,&req);

VIDIOC_QUERYBUF:将REQBUFS中分配的缓存转换成物理地址,并将物理地址映射到用户空间

for (n_buffers = 0; n_buffers < req.count; ++n_buffers)

{

        struct v4l2_buffer buf;

        memset(&buf,0,sizeof(buf));

        buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;

        buf.memory =V4L2_MEMORY_MMAP;

        buf.index =n_buffers;

        if (-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf))

        {

                printf("error in VIDIOC_QUERYBUF\n");

                return -1;

        }

        buffers[n_buffers].length= buf.length;

        buffers[n_buffers].start=mmap (NULL,buf.length,PROT_READ | PROT_WRITE ,MAP_SHARED,fd, buf.m.offset);

        if (MAP_FAILED== buffers[n_buffers].start)

                return -1;

}

VIDIOC_QUERYCAP:查询驱动功能

struct v4l2_capability cap;

if( ioctl(fd,VIDIOC_QUERYCAP,&cap) == -1)

        printf("error\n");

printf("capability:\n");

printf("driver:%s\n",cap.driver);

printf("card:%s\n",cap.card);

printf("bus info:%s\n",cap.bus_info);

printf("version:%d\n",cap.version);

printf("capabilities:%x\n",cap.capabilities);

VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式

struct v4l2_fmtdesc fmtdesc;

fmtdesc.index = 0;

fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

printf("fmtdesc:\n");

while(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1)

{

        printf("\t%d.%s\n",fmtdesc.index+1,fmtdesc.description);

        fmtdesc.index++;

}

VIDIOC_G/S_FMT:读取/设置当前驱动的视频捕捉格式

struct v4l2_format format;

memset(&format, 0, sizeof(struct v4l2_format));

format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if( ioctl(fd, VIDIOC_G_FMT, &format) == -1)

{

        printf("VIDIOC_G_FMT error\n");

        return -1;

}

struct v4l2_pix_format pix_format;

pix_format = format.fmt.pix;

printf("pix_format\n");

printf("width:%d\n",pix_format.width);

printf("height:%d\n",pix_format.height);

printf("bytesperline:%d\n",pix_format.bytesperline);

printf("sizeimage:%d\n",pix_format.sizeimage);

VIDIOC_TRY_FMT:验证当前驱动的显示格式

VIDIOC_CROPCAP:查询驱动的修剪能力

VIDIOC_G/S_CROP:读取/设置视频信号的边框

struct v4l2_cropcap cropcap;

struct v4l2_crop crop;

cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  

if(0 == ioctl(fd, VIDIOC_CROPCAP, &cropcap))  

{  

        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  

        crop.c = cropcap.defrect;  

        if(-1 == ioctl(fd, VIDIOC_S_CROP, &crop))

        {

                printf("VIDIOC_S_CROP error\n");

                return -1;

        }

}

VIDIOC_QBUF:把缓存区放入缓存队列

VIDIOC_DQBUF:把缓存去从缓存队列中取出

unsigned int i;

enum v4l2_buf_type type;

for (i = 0; i< 4; ++i)

{

        struct v4l2_buffer buf;

        buf.type =V4L2_BUF_TYPE_VIDEO_CAPTURE;

        buf.memory =V4L2_MEMORY_MMAP;

        buf.index = i;

        ioctl (fd,VIDIOC_QBUF, &buf);

}

type =V4L2_BUF_TYPE_VIDEO_CAPTURE;

ioctl (fd,VIDIOC_STREAMON, &type);

struct v4l2_buffer buf;

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory =V4L2_MEMORY_MMAP;

if( ioctl (fd,VIDIOC_DQBUF, &buf)==-1)

{

        printf("error in VIDIOC_DQBUF\n");

        return -1;

}

VIDIOC_STREAMON:开始视频显示函数

VIDIOC_STREAMOFF:结束视频显示函数

VIDIOC_QUERYSTD:检查当前视频设备支持的标准,亚洲一般使用PAL制式摄像头,欧洲一般使用NTSC摄像头

v4l2_std_id std;

int ret;

do

{

          ret = ioctl(fd,VIDIOC_QUERYSTD,&std);                  

}while(-1==ret && errno==EAGAIN);

switch(std)

{

case V4L2_STD_NTSC:

   //

case V4L2_STD_PAL:

   //   

} 

处理v4l2视频数据

v4l2设定了三种应用程序与驱动的交互方式:

1)直接读取设备文件方式read/write

2)mmap映射方式

3)用户指针方式

mmap方式:驱动将内部数据空间映射到应用程序空间上,双方直接在这个空间上进行数据交换

用户指针方式:首先由应用程序申请一段缓冲区,然后将缓冲区传给驱动,驱动将其作为缓冲区,从而实现内存共享

直接read/write:一般配合select使用,直接读取设备文件的方式进行I/O

关闭设备

调用close关闭文件描述符,如果进行了内存映射,关闭之前还需要munmap解除映射

你可能感兴趣的:(简介)