zoukankan      html  css  js  c++  java
  • 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
    ");
                    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
    ");
    printf("capability:
    ");
    printf("driver:%s
    ",cap.driver);
    printf("card:%s
    ",cap.card);
    printf("bus info:%s
    ",cap.bus_info);
    printf("version:%d
    ",cap.version);
    printf("capabilities:%x
    ",cap.capabilities);

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

    struct v4l2_fmtdesc fmtdesc;
    fmtdesc.index = 0;
    fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
    printf("fmtdesc:
    ");
    while(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1)
    {
            printf("	%d.%s
    ",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
    ");
            return -1;
    }
    struct v4l2_pix_format pix_format;
    pix_format = format.fmt.pix;
    printf("pix_format
    ");
    printf("%d
    ",pix_format.width);
    printf("height:%d
    ",pix_format.height);
    printf("bytesperline:%d
    ",pix_format.bytesperline);
    printf("sizeimage:%d
    ",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
    ");
                    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
    ");
            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解除映射

  • 相关阅读:
    ArrayAdapter与SimpleAdapter的使用
    ThinkPHP之数据库操作
    android之显示数据库信息
    linux下定时任务的使用
    ThinkPHP中的跨控制器调用与框架执行流程
    android之SQLlite操作
    linux中的进程管理
    [技巧篇]16.MyEclipse2014安装SVN插件,在线安装
    [技巧篇]15.火狐浏览器缓存设置,提高开发效率!
    [技巧篇]14.据说SSH框架需要的监听器,IntrospectorCleanupListener
  • 原文地址:https://www.cnblogs.com/buptlyn/p/4152167.html
Copyright © 2011-2022 走看看