精华内容
下载资源
问答
  • V4L2摄像头采集

    2016-06-07 10:48:46
    V4L2摄像头采集,根据分辨率和帧率 用于android
  • V4L2摄像头采集数据

    2012-12-04 21:43:53
     V4L2摄像头采集数据 一.什么是video4linux Video4linux2(简称V4L2),是linux中关于视频设备的内核驱动。在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video0下。   二....

    转自:http://blog.csdn.net/clc4210408/article/details/6956197

         V4L2摄像头采集数据

    一.什么是video4linux
    Video4linux2(简称V4L2),是linux中关于视频设备的内核驱动。在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video0下。

     

    二.一般操作流程(视频设备):

    1.打开设备文件。 int fd=open(”/dev/video0″,O_RDWR);
    2.取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability
    3.设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
    VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format
    4.向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers
    5.将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。mmap
    6.将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer
    7.开始视频的采集。VIDIOC_STREAMON
    8.出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF
    9.将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF
    10.停止视频的采集。VIDIOC_STREAMOFF
    11.关闭视频设备。close(fd);


    三、常用的结构体(参见/usr/include/linux/videodev2.h):

    struct v4l2_requestbuffers reqbufs;//向驱动申请帧缓冲的请求,里面包含申请的个数
    struct v4l2_capability cap;//这个设备的功能,比如是否是视频输入设备
    struct v4l2_standard std;//视频的制式,比如PAL,NTSC
    struct v4l2_format fmt;//帧的格式,比如宽度,高度等

    struct v4l2_buffer buf;//代表驱动中的一帧
    v4l2_std_id stdid;//视频制式,例如:V4L2_STD_PAL_B
    struct v4l2_queryctrl query;//查询的控制
    struct v4l2_control control;//具体控制的值

     

    下面具体说明开发流程(网上找的)

    打开视频设备

    在V4L2中,视频设备被看做一个文件。使用open函数打开这个设备:

    //用非阻塞模式打开摄像头设备

    intcameraFd;

    cameraFd= open(“/dev/video0″, O_RDWR| O_NONBLOCK, 0);

    //如果用阻塞模式打开摄像头设备,上述代码变为:

    //cameraFd = open(”/dev/video0″, O_RDWR, 0);

    关于阻塞模式和非阻塞模式

    应用程序能够使用阻塞模式或非阻塞模式打开视频设备,如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。

    设定属性及采集方式

    打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。这一步是可选的。在Linux编程中,一般使用ioctl函数来对设备的I/O通道进行管理:

    extern intioctl(int__fd, unsigned long int__request, …) __THROW;

    __fd:设备的ID,例如刚才用open函数打开视频通道后返回的cameraFd;

    __request:具体的命令标志符。

    在进行V4L2开发中,一般会用到以下的命令标志符:

    1 VIDIOC_REQBUFS:分配内存

    2 VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址

    3 VIDIOC_QUERYCAP:查询驱动功能

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

    5 VIDIOC_S_FMT:设置当前驱动的频捕获格式

    6 VIDIOC_G_FMT:读取当前驱动的频捕获格式

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

    8 VIDIOC_CROPCAP:查询驱动的修剪能力

    9 VIDIOC_S_CROP:设置视频信号的边框

    10 VIDIOC_G_CROP:读取视频信号的边框

    11 VIDIOC_QBUF:把数据从缓存中读取出来

    12 VIDIOC_DQBUF:把数据放回缓存队列

    13 VIDIOC_STREAMON:开始视频显示函数

    14 VIDIOC_STREAMOFF:结束视频显示函数

    15 VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。

    这些IO调用,有些是必须的,有些是可选择的。

    检查当前视频设备支持的标准

    在亚洲,一般使用PAL(720X576)制式的摄像头,而欧洲一般使用NTSC(720X480),使用VIDIOC_QUERYSTD来检测:

    v4l2_std_id std;

    do{

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

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

    switch(std) {

    caseV4L2_STD_NTSC:

    //……

    caseV4L2_STD_PAL:

    //……

    }

    设置视频捕获格式

    当检测完视频设备支持的标准后,还需要设定视频捕获格式:

    structv4l2_format    fmt;

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

    fmt.type= V4L2_BUF_TYPE_VIDEO_CAPTURE;

    fmt.fmt.pix.width= 720;

    fmt.fmt.pix.height= 576;

    fmt.fmt.pix.pixelformat= V4L2_PIX_FMT_YUYV;

    fmt.fmt.pix.field= V4L2_FIELD_INTERLACED;

    if(ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {

    return-1;

    }

    v4l2_format结构体定义如下:

    structv4l2_format

    {

    enumv4l2_buf_type type;    //数据流类型,必须永远是//V4L2_BUF_TYPE_VIDEO_CAPTURE

    union

    {

    structv4l2_pix_format    pix;

    structv4l2_window        win;

    structv4l2_vbi_format    vbi;

    __u8    raw_data[200];

    } fmt;

    };

    structv4l2_pix_format

    {

    __u32                   width;         //宽,必须是16的倍数

    __u32                   height;        //高,必须是16的倍数

    __u32                   pixelformat;   //视频数据存储类型,例如是//YUV4:2:2还是RGB

    enumv4l2_field         field;

    __u32                   bytesperline;

    __u32                   sizeimage;

    enumv4l2_colorspace    colorspace;

    __u32                   priv;

    };

    分配内存

    接下来可以为视频捕获分配内存:

    structv4l2_requestbuffers  req;

    if(ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {

    return-1;

    }

    v4l2_requestbuffers定义如下:

    structv4l2_requestbuffers

    {

    __u32               count;  //缓存数量,也就是说在缓存队列里保持多少张照片

    enumv4l2_buf_type  type;   //数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE

    enumv4l2_memory    memory; // V4L2_MEMORY_MMAP或 V4L2_MEMORY_USERPTR

    __u32               reserved[2];

    };

    获取并记录缓存的物理空间

    使用VIDIOC_REQBUFS,我们获取了req.count个缓存,下一步通过调用VIDIOC_QUERYBUF命令来获取这些缓存的地址,然后使用mmap函数转换成应用程序中的绝对地址,最后把这段缓存放入缓存队列:


    <!--[if !supportLineBreakNewLine]-->
    <!--[endif]-->

    typedef structVideoBuffer{

    void*start;

    size_t  length;

    } VideoBuffer;

     

    VideoBuffer*          buffers= calloc( req.count, sizeof(*buffers) );

    structv4l2_buffer    buf;

     

    for(numBufs= 0; numBufs< req.count; numBufs++) {

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

    buf.type= V4L2_BUF_TYPE_VIDEO_CAPTURE;

    buf.memory= V4L2_MEMORY_MMAP;

    buf.index= numBufs;

    //读取缓存

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

    return-1;

    }

    buffers[numBufs].length= buf.length;

    //转换成相对地址

    buffers[numBufs].start= mmap(NULL, buf.length,

    PROT_READ| PROT_WRITE,

    MAP_SHARED,

    fd, buf.m.offset);

     

    if(buffers[numBufs].start== MAP_FAILED) {

    return-1;

    }

     

    //放入缓存队列

    if(ioctl(fd, VIDIOC_QBUF, &buf) == -1) {

    return-1;

    }

    }

    关于视频采集方式

    操作系统一般把系统使用的内存划分成用户空间和内核空间,分别由应用程序管理和操作系统管理。应用程序可以直接访问内存的地址,而内核空间存放的是供内核访问的代码和数据,用户不能直接访问。v4l2捕获的数据,最初是存放在内核空间的,这意味着用户不能直接访问该段内存,必须通过某些手段来转换地址。

    一共有三种视频采集方式:使用read、write方式;内存映射方式和用户指针模式。

    read、write方式:在用户空间和内核空间不断拷贝数据,占用了大量用户内存空间,效率不高。

    内存映射方式:把设备里的内存映射到应用程序中的内存控件,直接处理设备内存,这是一种有效的方式。上面的mmap函数就是使用这种方式。

    用户指针模式:内存片段由应用程序自己分配。这点需要在v4l2_requestbuffers里将memory字段设置成V4L2_MEMORY_USERPTR。

    处理采集数据

    V4L2有一个数据缓存,存放req.count数量的缓存数据。数据缓存采用FIFO的方式,当应用程序调用缓存数据时,缓存队列将最先采集到的 视频数据缓存送出,并重新采集一张视频数据。这个过程需要用到两个ioctl命令,VIDIOC_DQBUF和VIDIOC_QBUF:

    structv4l2_buffer buf;

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

    buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

    buf.memory=V4L2_MEMORY_MMAP;

    buf.index=0;

    //读取缓存

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

    {

    return-1;

    }

    //…………视频处理算法

    //重新放入缓存队列

    if(ioctl(cameraFd, VIDIOC_QBUF, &buf) == -1) {

    return-1;

    }

    关闭视频设备

    使用close函数关闭一个视频设备

    close(cameraFd)

    还需要使用munmap方法。

     

    下面是代码,加了一部分注释:

    //#加了点注释

     

    //#Rockie Cheng

     

     

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include <assert.h>

     

    #include <getopt.h>           

     

    #include <fcntl.h>            

    #include <unistd.h>

    #include <errno.h>

    #include <malloc.h>

    #include <sys/stat.h>

    #include <sys/types.h>

    #include <sys/time.h>

    #include <sys/mman.h>

    #include <sys/ioctl.h>

     

    #include <asm/types.h>        

    #include <linux/videodev2.h>

     

    #define CLEAR(x) memset (&(x), 0, sizeof (x))

     

    struct buffer {

            void *                  start;

            size_t                  length;

    };

     

    static char *           dev_name        = "/dev/video0";//摄像头设备名

    static int              fd              = -1;

    struct buffer *         buffers         = NULL;

    static unsigned int     n_buffers       = 0;

     

    FILE *file_fd;

    static unsigned long file_length;

    static unsigned char *file_name;

    //

    //获取一帧数据

    //

    static int read_frame (void)

    {

    struct v4l2_buffer buf;

    unsigned int i;

     

    CLEAR (buf);

    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    buf.memory = V4L2_MEMORY_MMAP;

    int ff = ioctl (fd, VIDIOC_DQBUF, &buf);

    if(ff<0)

    printf("failture\n"); //出列采集的帧缓冲

     

    assert (buf.index < n_buffers);

       printf ("buf.index dq is %d,\n",buf.index);

     

    fwrite(buffers[buf.index].start, buffers[buf.index].length, 1, file_fd); //将其写入文件中

     

    ff=ioctl (fd, VIDIOC_QBUF, &buf); //再将其入列

    if(ff<0)

    printf("failture VIDIOC_QBUF\n");

    return 1;

    }

     

    int main (int argc,char ** argv)

    {

    struct v4l2_capability cap;

    struct v4l2_format fmt;

    unsigned int i;

    enum v4l2_buf_type type;

     

    file_fd = fopen("test-mmap.jpg", "w");//图片文件名

     

    fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);//打开设备

     

    int ff=ioctl (fd, VIDIOC_QUERYCAP, &cap);//获取摄像头参数

    if(ff<0)

    printf("failture VIDIOC_QUERYCAP\n");

     

           struct v4l2_fmtdesc fmt1;

            int ret;

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

           fmt1.index = 0;

           fmt1.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

           while ((ret = ioctl(fd, VIDIOC_ENUM_FMT, &fmt1)) == 0)

           {

                  fmt1.index++;

                  printf("{ pixelformat = '%c%c%c%c', description = '%s' }\n",

                                fmt1.pixelformat & 0xFF, (fmt1.pixelformat >> 8) & 0xFF,

                                (fmt1.pixelformat >> 16) & 0xFF, (fmt1.pixelformat >> 24) & 0xFF,

                                fmt1.description);

                 

           }

    CLEAR (fmt);

    fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    fmt.fmt.pix.width       = 640;

    fmt.fmt.pix.height      = 480;

    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;//V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YVU420;//V4L2_PIX_FMT_YUYV;

    fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;

    ff = ioctl (fd, VIDIOC_S_FMT, &fmt); //设置图像格式

    if(ff<0)

    printf("failture VIDIOC_S_FMT\n");

    file_length = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; //计算图片大小

     

    struct v4l2_requestbuffers req;

    CLEAR (req);

    req.count               = 1;

    req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    req.memory              = V4L2_MEMORY_MMAP;

     

    ioctl (fd, VIDIOC_REQBUFS, &req); //申请缓冲,count是申请的数量

    if(ff<0)

    printf("failture VIDIOC_REQBUFS\n");

    if (req.count < 1)

       printf("Insufficient buffer memory\n");

     

    buffers = calloc (req.count, sizeof (*buffers));//内存中建立对应空间

     

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

    {

       struct v4l2_buffer buf;   //驱动中的一帧

       CLEAR (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 ("VIDIOC_QUERYBUF error\n");

     

       buffers[n_buffers].length = buf.length;

       buffers[n_buffers].start =

       mmap (NULL /* start anywhere */,    //通过mmap建立映射关系

        buf.length,

        PROT_READ | PROT_WRITE /* required */,

        MAP_SHARED /* recommended */,

        fd, buf.m.offset);

     

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

        printf ("mmap failed\n");

            }

     

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

    {

       struct v4l2_buffer buf;

       CLEAR (buf);

     

       buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;

       buf.memory      = V4L2_MEMORY_MMAP;

       buf.index       = i;

     

       if (-1 == ioctl (fd, VIDIOC_QBUF, &buf))//申请到的缓冲进入列队

        printf ("VIDIOC_QBUF failed\n");

    }

                   

    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

     

    if (-1 == ioctl (fd, VIDIOC_STREAMON, &type)) //开始捕捉图像数据

       printf ("VIDIOC_STREAMON failed\n");

     

    for (;;) //这一段涉及到异步IO

    {

       fd_set fds;

       struct timeval tv;

       int r;

     

       FD_ZERO (&fds);//将指定的文件描述符集清空

       FD_SET (fd, &fds);//在文件描述符集合中增加一个新的文件描述符

     

       /* Timeout. */

       tv.tv_sec = 2;

       tv.tv_usec = 0;

     

       r = select (fd + 1, &fds, NULL, NULL, &tv);//判断是否可读(即摄像头是否准备好),tv是定时

     

       if (-1 == r) {

        if (EINTR == errno)

         continue;

        printf ("select err\n");

                            }

       if (0 == r) {

        fprintf (stderr, "select timeout\n");

        exit (EXIT_FAILURE);

                            }

     

       if (read_frame ())//如果可读,执行read_frame ()函数,并跳出循环

       break;

    }

     

    unmap:

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

       if (-1 == munmap (buffers[i].start, buffers[i].length))

        printf ("munmap error");

    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  

            if (-1 == ioctl(fd, VIDIOC_STREAMOFF, &type))  

                printf("VIDIOC_STREAMOFF");

    close (fd);

    fclose (file_fd);

    exit (EXIT_SUCCESS);

    return 0;

    }

    展开全文
  • ARM Cortex-A8平台Linux下V4l2摄像头采集图片程序,实现yuyv转RGB,RGB转BMP保存,RGB缩放等功能。利用jpeglib实现RGB转JPEG,并且压缩结果保存至内存中,无需再用文件操作来保存JPEG图片,JPEG经UDP发送至远程服务器...
  • 一、简介 一般采集过程:打开视频设备 → 设定属性(裁剪、缩放)→ 设定采集方式 → 开始采集,并处理采集数据(循环) → 关闭视频设备 ...struct v4l2_capability{ u8 driver[16]; //驱动名 u8 card...

    一、简介

    • 一般采集过程:打开视频设备 → 设定属性(裁剪、缩放)→ 设定采集方式 → 开始采集,并处理采集数据(循环) → 关闭视频设备
    • 头文件:<linux/videodev2.h>

     

    二、查询设备属性:VIDIOC_QUERYCAP

    • 相关结构体
    struct v4l2_capability{
        u8 driver[16];    //驱动名
        u8 card[32];      //设备名
        u8 bus_info[32];  //设备在系统中位置
        u32 version;      //驱动版本号
        u32 capabilities; //设备支持操作
        u32 reserved[4];  //保留字段
    }
    • 原型:int ioctl(int fd,int request,struct v4l2_capability *argp);
    • ioctl(fd,VIDIOC_QUERYCAP,&CAP);    //显示设备信息
    • capabilities常用:V4L2_CAP_VIDEO_CAPTURE //是否支持图像获取

     

    三、查询并显示所有支持格式:VIDIOC_ENUM_FMT

    • 原型:int ioctl(int fd,int request,struct v4l2_fmtdesc* argp)
    • 相关结构体
    struct v4l2_fmtdesc{
        u32 index;        //要查询的格式序号,应用程序设置
        enum v4l2_buf_type type;      //帧类型,应用程序设置
        u32 flags;        //是否为压缩格式
        u8 description[32];    //格式名称
        u32 pixelformat;    //格式
        u32 reserved[4];    //保留
    }

     

    四、显示(设置)当前帧的相关信息

    • 相关结构体
    struct v4l2_format{
       enum v4l2_buf_type type;    //帧类型,应用程序设置,一般为V4L2_BUF_TYPE_VIDEO_CAPTURE
       union fmt{
           struct v4l2_pix_format pix;    //视频设备使用
           struct v4l2_window win;
           struct v4l2_vbi_format vbi;
           struct v4l2_sliced_vbi_format sliced;
           u8 raw_data[200];
       };
    }
    
    struct v4l2_pix_format{
        u32 width;    //帧宽,单位是像素
        u32 height;    //帧高,单位是像素
        u32 pixelformat;    //帧格式
        enum v4l2_field field;
        u32 bytesperline;
        u32 sizeimage;
        enum v4l2_colorspace colorspace;
        u32 priv;
    };
    • 显示当前帧信息:ioctl(fd,VIDIOC_G_FMT,&fmt) 【struct v4l2_format fmt;】
    • 设置当前帧信息:ioctl(fd,VIDIOC_S_FMT,&fmt)

     

    五、视频输入输出

    • request:VIDIOC_G_INPUT 和 VIDIOC_S_INPUT 。一个video设备节点可能对应多个视频源,通过S进行切换,通过G查询当前输入输出的index。
    • 可通过VIDIOC_ENUMINPUT进行列举
    • 相关结构体
    struct v4l2_input{
        _u32 index;    //which input
        _u8 name[32];    //label
        _u32 type;    //type of input
        _u32 audioset;    //associated audios
        _u32 tuner;    //associated tuner
        v4l2_std_id std;
        _u32 status;
        _u32 reserved[4];
    };

     

    六、Video standards

    • 存在如NTSC 和 PAL 等多种视频标准,查询支持或当前标准
    • 相关结构体
    typedef u64 v4l2_std_id;    //64位数表示的标准
    
    struct v4l2_standard{
        u32 index;
        v4l2_std_id id;
        u8 name[24];
        struct v4l2_fract frameperiod;    //frame,not fields
        u32 framelines;
        u32 reserved[4];
    };

     

    七、申请、管理缓冲区

    1、向设备申请缓冲区VIDIOC_REQBUFS

    //相关结构体,该结构体在应用时候都要手动设置
    struct v4l2_requsetbuffers{
        U32 count;    //缓冲区内缓冲帧数
        enum v4l2_buf_type type;    //缓冲帧格式
        enum v4l2_memory memory;    //区别内存映射还是用户指针方式
        U32 reserved[2];
    }
    
    enum v4l2_memory{
        V4L2_MEMORY_MMAP,V4L2_MEMORY_USERPTR
    }
    //例,申请4个缓冲帧的缓冲区
    
    struct v4l2_requestbuffers req;
    req.count=4;
    req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory=V4L2_MEMORY_MMAP;
    ioctl(fd,VIDIOC_REQBUFS,&req);

    2、获取缓冲帧地址、长度:VIDIOC_QUERYBUF

    • 原型:int ioctl(int fd,int request,struct v4l2_buffer *argp);

    • 相关结构体

    struct v4l2_buffer{
        U32 index;    //buffer序号
        enum v4l2_buf_type;
        U32 byteused;    //已用帧数
        U32 flags;    //MMAP or USERPTR
        enum v4l2_field field;
        struct timeval tiemstamp;    //获取第一个字节的系统时间
        struct v4l2_timecode timecode;
        enum v4l2_memory memory;
        union m{
            U32 offset;    //只对MMAP有效,缓冲帧地址
            unsigned long userptr;
        }
        U32 length;//缓冲帧长度
        U32 input;
        U32 reserved;
    }

    3、内存映射(MMAP)和定义一个结构来映射每个缓冲帧

    • 头文件:#include<sys/mman.h>中的一些函数
    void * mmap(void* addr,size_t length,int prot, int flags, int fd,off_t offset)
    /*
    addr:映射起始地址,一般填NULL让内核自动选择
    length:被映射的内存长度
    prot:标志映射后能否被读写,值有:PROT_EXEC,PROT_READ,PROT_WRITE,PROT_NONE
    flags:确定次内存映射是否能被其他进程共享,有:MAP_SHARED,MAP_PRIVATE
    fd,offset:确定被映射的内存地址返回成功映射后的地址
    */
    
    
    int munmap(void* addr,size_t length);
    //断开映射,addr为地址,length为映射后内存长度
    • 自己定义的结构体
    struct buffer{
        void* start;
        unsigned int length;
    }*buffers;
    • 例:将4个已申请的缓冲帧映射到应用程序,用buffer指针记录
    buffer=(buffer*)calloc(req.count,sizeof(*buffers));
    for(unsigned int n_buffers=0;n_buffers<req.cout;n_buffers++){
        struct v4l2_buffer buf;
        memset(&buf,0,sizeof(buf));
    
        buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.index=n_buffers;
        buf.memory=V4L2_MEMORY_MMAP;
        //查询序号为n_buffers的缓冲区,得到起始物理地址和大小
        if(ioctl(fd,VIDIOC_QUERYBUF,&buf))
            exit(-1);
        //映射内存
        buffers[n_buffers].start=mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,buf.m.offset);
    }

     

    八、获取数据

    1、启动/停止数据流

    VIDIOC_STREAMON 和 VIDIOC_STREAMOFF

    int ioctl(fd,~,&V4L2_BUF_VIDEO_CAPTURE)

    2、把帧放入队列和从队列中取出帧

    VIDIOC_QBUF   VIDIOC_DQBUF

    3、获取一帧并且处理

    struct v4l2_buffer;
    clear(buf);
    buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory=V4L2_MEMORY_MMAP;
    while(1){
        ioctl(fd,VIDIOC_DQBUF,&buf)
        process(buffer[buf.index].start)
    }

     

    展开全文
  • linux v4l2 摄像头采集视频的方法

    千次阅读 2017-04-13 16:04:03
    Linux上用v4l2函数接口获取视频主要是一个步骤流程,一步步做就很容易,现已我在qt下编写的一个读取摄像头视频的程序中的相关代码为例。 首先打开视频设备,比如/dev/video0, [cpp] view plain copy ...

    Linux上用v4l2函数接口获取视频主要是一个步骤流程,一步步做就很容易,现已我在qt下编写的一个读取摄像头视频的程序中的相关代码为例。

    首先打开视频设备,比如/dev/video0,

    [cpp] view plain copy
    1. fd = open(dev_name.toStdString().c_str(), O_RDWR/*|O_NONBLOCK*/, 0);  
    2.   
    3.     if(-1 == fd)  
    4.     {  
    5.         emit display_error(tr("open: %1").arg(QString(strerror(errno))));  
    6.         return -1;  
    7.     }  
    然后初始化设备
    [cpp] view plain copy
    1. v4l2_capability cap;  
    2. v4l2_cropcap cropcap;  
    3. v4l2_crop crop;  
    4. v4l2_format fmt;  
    5.   
    6. if(-1 == ioctl(fd, VIDIOC_QUERYCAP, &cap))  
    7. {   //查询设备功能  
    8.     if(EINVAL == errno)  
    9.     {  
    10.         emit display_error(tr("%1 is no V4l2 device").arg(dev_name));  
    11.     }  
    12.     else  
    13.     {  
    14.         emit display_error(tr("VIDIOC_QUERYCAP: %1").arg(QString(strerror(errno))));  
    15.     }  
    16.     return -1;  
    17. }  
    18.   
    19. if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))  
    20. {   //视频采集  
    21.     emit display_error(tr("%1 is no video capture device").arg(dev_name));  
    22.     return -1;  
    23. }  
    24.   
    25. if(!(cap.capabilities & V4L2_CAP_STREAMING))  
    26. {   //视频流  
    27.     emit display_error(tr("%1 does not support streaming i/o").arg(dev_name));  
    28.     return -1;  
    29. }  
    30.   
    31. CLEAR(cropcap);  
    32.   
    33. cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
    34.   
    35. if(0 == ioctl(fd, VIDIOC_CROPCAP, &cropcap))  
    36. {  
    37.     CLEAR(crop);  
    38.     crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
    39.     crop.c = cropcap.defrect;  
    40.   
    41.     if(-1 == ioctl(fd, VIDIOC_S_CROP, &crop))  
    42.     {  
    43.         if(EINVAL == errno)  
    44.         {  
    45.             emit display_error(tr("VIDIOC_S_CROP not supported"));  
    46.         }  
    47.         else  
    48.         {  
    49.             emit display_error(tr("VIDIOC_S_CROP: %1").arg(QString(strerror(errno))));  
    50.             return -1;  
    51.         }  
    52.     }  
    53. }  
    54. else  
    55. {  
    56.     emit display_error(tr("VIDIOC_CROPCAP: %1").arg(QString(strerror(errno))));  
    57.     return -1;  
    58. }  
    59.   
    60. CLEAR(fmt);  
    61.   
    62. fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
    63. fmt.fmt.pix.width = 640;  
    64. fmt.fmt.pix.height = 480;  
    65. fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//YUV4:2:2  
    66. fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;//隔行扫描  
    67.   
    68. if(-1 == ioctl(fd, VIDIOC_S_FMT, &fmt))  
    69. {  //设置视频格式  
    70.     emit display_error(tr("VIDIOC_S_FMT").arg(QString(strerror(errno))));  
    71.     return -1;  
    72. }  
    73.   
    74. if(-1 == init_mmap())  
    75. {  //初始化mmap,内存映射  
    76.     return -1;  
    77. }  
    初始化mmap   
    [cpp] view plain copy
    1. v4l2_requestbuffers req;  
    2. CLEAR(req);  
    3.   
    4. req.count = 4;  
    5. req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
    6. req.memory = V4L2_MEMORY_MMAP;  
    7.   
    8. if(-1 == ioctl(fd, VIDIOC_REQBUFS, &req))  
    9. {   //请求buf  
    10.     if(EINVAL == errno)  
    11.     {  
    12.         emit display_error(tr("%1 does not support memory mapping").arg(dev_name));  
    13.         return -1;  
    14.     }  
    15.     else  
    16.     {  
    17.         emit display_error(tr("VIDIOC_REQBUFS %1").arg(QString(strerror(errno))));  
    18.         return -1;  
    19.     }  
    20. }  
    21.   
    22. if(req.count < 2)  
    23. {  
    24.     emit display_error(tr("Insufficient buffer memory on %1").arg(dev_name));  
    25.     return -1;  
    26. }  
    27.   
    28. buffers = (buffer*)calloc(req.count, sizeof(*buffers));//分配内存大小  
    29.   
    30. if(!buffers)  
    31. {  
    32.     emit display_error(tr("out of memory"));  
    33.     return -1;  
    34. }  
    35.   
    36. for(n_buffers = 0; n_buffers < req.count; ++n_buffers)  
    37. {  
    38.     v4l2_buffer buf;  
    39.     CLEAR(buf);  
    40.   
    41.     buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
    42.     buf.memory = V4L2_MEMORY_MMAP;  
    43.     buf.index = n_buffers;  
    44.   
    45.     if(-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf))  
    46.     {   //获取buf信息起始位置,长度等  
    47.         emit display_error(tr("VIDIOC_QUERYBUF: %1").arg(QString(strerror(errno))));  
    48.         return -1;  
    49.     }  
    50.   
    51.     buffers[n_buffers].length = buf.length;  
    52.     buffers[n_buffers].start =  
    53.             mmap(NULL, // start anywhere  
    54.                  buf.length,  
    55.                  PROT_READ | PROT_WRITE,  
    56.                  MAP_SHARED,  
    57.                  fd, buf.m.offset);//映射  
    58.   
    59.     if(MAP_FAILED == buffers[n_buffers].start)  
    60.     {  
    61.         emit display_error(tr("mmap %1").arg(QString(strerror(errno))));  
    62.         return -1;  
    63.     }  
    64. }  
    开始捕获视频
    [cpp] view plain copy
    1. int VideoDevice::start_capturing()  
    2. {  
    3.     unsigned int i;  
    4.     for(i = 0; i < n_buffers; ++i)  
    5.     {  
    6.         v4l2_buffer buf;  
    7.         CLEAR(buf);  
    8.   
    9.         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
    10.         buf.memory =V4L2_MEMORY_MMAP;  
    11.         buf.index = i;  
    12. //        fprintf(stderr, "n_buffers: %d\n", i);  
    13.   
    14.         if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))  
    15.         {   //把buf排成一列  
    16.             emit display_error(tr("VIDIOC_QBUF: %1").arg(QString(strerror(errno))));  
    17.             return -1;  
    18.         }  
    19.     }  
    20.   
    21.     v4l2_buf_type type;  
    22.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
    23.   
    24.     if(-1 == ioctl(fd, VIDIOC_STREAMON, &type))  
    25.     {  
    26.         emit display_error(tr("VIDIOC_STREAMON: %1").arg(QString(strerror(errno))));  
    27.         return -1;  
    28.     }  
    29.     return 0;  
    30. }  
    获取一帧图像
    [cpp] view plain copy
    1. int VideoDevice::get_frame(void **frame_buf, size_t* len)  
    2. {  
    3.     v4l2_buffer queue_buf;  
    4.     CLEAR(queue_buf);  
    5.   
    6.     queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
    7.     queue_buf.memory = V4L2_MEMORY_MMAP;  
    8.   
    9.     if(-1 == ioctl(fd, VIDIOC_DQBUF, &queue_buf))  
    10.     {   //从队列中取出一个buf  
    11.         switch(errno)  
    12.         {  
    13.         case EAGAIN:  
    14. //            perror("dqbuf");  
    15.             return -1;  
    16.         case EIO:  
    17.             return -1 ;  
    18.         default:  
    19.             emit display_error(tr("VIDIOC_DQBUF: %1").arg(QString(strerror(errno))));  
    20.             return -1;  
    21.         }  
    22.     }  
    23.   
    24.     *frame_buf = buffers[queue_buf.index].start;  
    25.     *len = buffers[queue_buf.index].length;  
    26.     index = queue_buf.index;  
    27.   
    28.     return 0;  
    29.   
    30. }  
    获取完后,将这一帧图像的buf放回去
    [cpp] view plain copy
    1. int VideoDevice::unget_frame()  
    2. {  
    3.     if(index != -1)  
    4.     {  
    5.         v4l2_buffer queue_buf;  
    6.         CLEAR(queue_buf);  
    7.   
    8.         queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
    9.         queue_buf.memory = V4L2_MEMORY_MMAP;  
    10.         queue_buf.index = index;  
    11.   
    12.         if(-1 == ioctl(fd, VIDIOC_QBUF, &queue_buf))  
    13.         {   //将buf放入队列  
    14.             emit display_error(tr("VIDIOC_QBUF: %1").arg(QString(strerror(errno))));  
    15.             return -1;  
    16.         }  
    17.         return 0;  
    18.     }  
    19.     return -1;  
    20. }  
    停止视频捕捉
    [cpp] view plain copy
    1. int VideoDevice::stop_capturing()  
    2. {  
    3.     v4l2_buf_type type;  
    4.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
    5.   
    6.     if(-1 == ioctl(fd, VIDIOC_STREAMOFF, &type))  
    7.     {  
    8.         emit display_error(tr("VIDIOC_STREAMOFF: %1").arg(QString(strerror(errno))));  
    9.         return -1;  
    10.     }  
    11.     return 0;  
    12. }  
    卸载摄像头设备
    [cpp] view plain copy
    1. int VideoDevice::uninit_device()  
    2. {  
    3.     unsigned int i;  
    4.     for(i = 0; i < n_buffers; ++i)  
    5.     {  
    6.         if(-1 == munmap(buffers[i].start, buffers[i].length))  
    7.         {  
    8.             emit display_error(tr("munmap: %1").arg(QString(strerror(errno))));  
    9.             return -1;  
    10.         }  
    11.   
    12.     }  
    13.     free(buffers);  
    14.     return 0;  
    15. }  
    关闭视频设备文件
    [cpp] view plain copy
    1. int VideoDevice::close_device()  
    2. {  
    3.     if(-1 == close(fd))  
    4.     {  
    5.         emit display_error(tr("close: %1").arg(QString(strerror(errno))));  
    6.         return -1;  
    7.     }  
    8.     return 0;  
    9. }  
    这就是完整的采集视频的流程,当然可以多增加配置采集的视频格式的代码。
    展开全文
  • 基于V4L2摄像头采集图片程序设计

    千次阅读 2016-09-20 23:47:14
    //该头文件定义的是摄像头在屏幕上显示的宽度和高度 #include #include #include #include #include typedef unsigned char U8; typedef unsigned int U32; typedef unsigned short U16; #define
    #ifndef __COMMON_H
    #define __COMMON_H
    //该头文件定义的是摄像头在屏幕上显示的宽度和高度
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<errno.h>
    #include <stdint.h>
    
    typedef unsigned char U8;
    typedef unsigned int U32;
    typedef unsigned short U16;
    
    
    #define WIDTH  800
    #define HEIGHT 600
    
    
    #endif	//__COMMON_H
    
    #ifndef __VIDEOCAPTURE_H
    #define __VIDEOCAPTURE_H
    
    #include"common.h"
    #include<sys/mman.h>
    #include<fcntl.h>
    #include<linux/videodev2.h>
    
    #define VIDEODEVNAME ("/dev/video0")		
    #define COUNT  4
    //需要调用的摄像头相关的接口,包括初始化,开始,结束,采取一帧的数据并保存
    int initCamera();
    void unInitCamera();
    int startCamera();
    int stopCamera();
    int getOneFrame(U8* pcYuvBuffer);
    
    #endif	//__VIDEOCAPTURE_H
    
    #include"videoCapture.h"
    
    static U8* pcYuv[COUNT]={NULL};
    static int vidDevFd = -1;
    static int nLength = 0;
    static struct v4l2_buffer dequeBuffer;
    static struct v4l2_buffer queueBuffer;
    
    //初始化摄像头程序
    int initCamera()
    {
    	//open /dev/video*
    	//open video device
    	vidDevFd = open(VIDEODEVNAME, O_RDONLY);
    	if (vidDevFd < 0)
    	{
    		fprintf(stderr, "open %s failed %s\n",VIDEODEVNAME, strerror(errno));			
    		return -1;
    	}
    
    	//printf("vidDevFd = %d!\n", vidDevFd);			
    
    	//设置视频格式
    	//set video device format
    	struct v4l2_format vidDevFmt;
    	vidDevFmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    	vidDevFmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    	vidDevFmt.fmt.pix.width = WIDTH;
    	vidDevFmt.fmt.pix.height = HEIGHT;
    	
    	if (0 != ioctl(vidDevFd, VIDIOC_S_FMT, &vidDevFmt))
    	{
    		fprintf(stderr, "VIDIOC_S_FMT failed %s\n", strerror(errno));			
    		unInitCamera();
    		return -1;
    	}
    	
    	//request buffers
    	//max count need to be considered
    	struct v4l2_requestbuffers reqBuffer;
    	reqBuffer.count = COUNT;
    	reqBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    	reqBuffer.memory = V4L2_MEMORY_MMAP;
    
    	if (0 != ioctl(vidDevFd, VIDIOC_REQBUFS, &reqBuffer))
    	{
    		fprintf(stderr, "VIDIOC_REQBUFS failed %s\n", strerror(errno));			
    		unInitCamera();
    		return -1;
    	}
    
    	//query buffers
    	int i = 0;
    	struct v4l2_buffer qryBuffer;
    	qryBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    	qryBuffer.memory = V4L2_MEMORY_MMAP;
    
    	for (i = 0; i < COUNT; i++)
    	{
    		qryBuffer.index = i;
    		
    		if (0 != ioctl(vidDevFd, VIDIOC_QUERYBUF, &qryBuffer))
    		{
    			fprintf(stderr, "VIDIOC_QUERYBUF failed %s\n", strerror(errno));			
    			unInitCamera();
    			return -1;
    		}
    
    		printf("qryBuffer.m.offset=%d, qryBuffer.lenght=%d\n", qryBuffer.m.offset, qryBuffer.length);
    		//mmap video device memory allocated by VIDIOC_REQBUFS
    		pcYuv[i] = mmap(NULL, qryBuffer.length, PROT_READ, MAP_SHARED, vidDevFd, qryBuffer.m.offset);
    		nLength = qryBuffer.length;
    
    		//queue buffers
    		struct v4l2_buffer queBuffer;
    		queBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    		queBuffer.memory = V4L2_MEMORY_MMAP;
    		queBuffer.index = qryBuffer.index;
    		if (0 != ioctl(vidDevFd, VIDIOC_QBUF, &queBuffer))
    		{
    			fprintf(stderr, "init VIDIOC_QBUF failed %s\n", strerror(errno));			
    			unInitCamera();
    			return -1;
    		}
    
    	}
    
    	dequeBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    	dequeBuffer.memory = V4L2_MEMORY_MMAP;
    	queueBuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    	queueBuffer.memory = V4L2_MEMORY_MMAP;
    
    	return 0;	
    }
    
    //取消摄像头
    void unInitCamera()
    {
    	int i = 0;
    
    	for (i = 0; i < COUNT; i++)
    	{
    		if (NULL != pcYuv[i])			
    		{
    			if (-1 == munmap(pcYuv[i], nLength));
    			{
    				//fprintf(stderr,"munmap error:%s!\n",strerror(errno));
    			}
    			pcYuv[i] = NULL;
    		}
    	}
    
    	if (vidDevFd >= 0)
    		close(vidDevFd);
    }
    //摄像头开始
    int startCamera()
    {
    	//start camera		
    
    	int nArg = 1;
    	if (0 != ioctl(vidDevFd, VIDIOC_STREAMON, &nArg))
    	{
    		fprintf(stderr, "VIDIOC_STREAMON failed %s\n", strerror(errno));			
    		unInitCamera();
    		return -1;
    	}
    
    	return 0;
    }
    
    //停止摄像头
    int stopCamera()
    {
    	//stop camera		
    
    	int nArg = 1;
    	if (0 != ioctl(vidDevFd, VIDIOC_STREAMOFF, &nArg))
    	{
    		fprintf(stderr, "VIDIOC_STREAMOFF failed %s\n", strerror(errno));			
    		unInitCamera();
    		return -1;
    	}
    
    	return 0;
    }
    
    //获取Frame
    int getOneFrame(unsigned char* pcYuyvBuffer)
    {
    	if (0 != ioctl(vidDevFd, VIDIOC_DQBUF, &dequeBuffer))
    	{
    		fprintf(stderr, "VIDIOC_DQBUF failed %s\n", strerror(errno));			
    		unInitCamera();
    		return -1;
    	}
    
    	//get frame
    	memcpy(pcYuyvBuffer, pcYuv[dequeBuffer.index], dequeBuffer.length);
    	printf("len=%d\n",dequeBuffer.length);
    
    	//queue
    	queueBuffer.index = dequeBuffer.index;
    	if (0 != ioctl(vidDevFd, VIDIOC_QBUF, &queueBuffer))
    	{
    		fprintf(stderr, "VIDIOC_QBUF failed %s\n", strerror(errno));			
    		unInitCamera();
    		return -1;
    	}
    	return 0;
    }
    
    #include"videoCapture.h"
    
    int main(void )
    {
    	int nRet = 0;
    	//char yuyv[WIDTH*HEIGHT*2];
    	char* pcYuvBuffer = NULL; 
    
    	if(-1 == initCamera())	
    	{
    		printf("initCamera failed!\n");			
    		goto ERR;
    	}
    
    	if (-1 == startCamera())
    	{
    		printf("startCamera failed!\n");			
    		goto ERR;
    	}
    
    	pcYuvBuffer = (char*)malloc((WIDTH*HEIGHT*2)*sizeof(char));
    	if (NULL == pcYuvBuffer)
    	{
    		printf("malloc YUYV buffer failed!\n");			
    		goto ERR;
    	}
    
    	int nDstFd = open("mytest.yuv", O_CREAT|O_EXCL|O_RDWR|O_TRUNC, 0777);
    	if (nDstFd == -1)
    	{
    		fprintf(stderr, "open mytest.yuv failed:%s\n", strerror(errno));		
    	}
    
    	int nFrameNum = 0;
    
    	while(1)
    	{
    		if (20 == nFrameNum)
    			break;
    
    		memset(pcYuvBuffer, 0, WIDTH*HEIGHT*2);
    
    		//if (-1 == getOneFrame(yuyv))
    		if (-1 == getOneFrame(pcYuvBuffer))
    		{
    			printf("getOneFrame error!\n");			
    			goto ERR;
    		}
    
    		//if (-1 == write(nDstFd, yuyv, WIDTH*HEIGHT*2))
    		if (-1 == write(nDstFd, pcYuvBuffer, WIDTH*HEIGHT*2))
    		{
    			fprintf(stderr, "write error:%s\n", strerror(errno));		
    			goto ERR;
    		}
    
    		nFrameNum++;
    	}
    
    	
    	if (-1 == stopCamera())
    	{
    		printf("stopCamera error!\n");			
    	}
    
    
    ERR:
    	if (NULL != pcYuvBuffer)
    	{
    		free(pcYuvBuffer);			
    		pcYuvBuffer = NULL;
    	}
    			
    	unInitCamera();
    	
    	close(nDstFd);
    	nDstFd = -1;
    		
    	return 0;
    }
    




    展开全文
  • ARM Cortex-A8平台Linux下V4l2摄像头采集图片程序,实现yuyv转RGB,RGB转BMP保存,RGB缩放等功能。利用jpeglib实现RGB转JPEG,并且压缩结果保存至内存中,无需再用文件操作来保存JPEG图片,JPEG经UDP发送至远程服务器...
  • V4L2写了程序来测试这两个摄像头,两者都支持YUYV格式输出,前者(罗技C210)测试完全没问题,取出来的帧数15FPS;而后者(监控摄像机)取出来的视频只有2-3FPS(320*240分辨率),我详细的看了一下V4L2,有个可以...
  • 同时也发现很多博客都只包含一个小部分,感觉如果有一个篇完整的介绍可能对新手会有帮助,因此在此简单介绍摄像头采集整个流程。第一次发博客,恳请各位大神多多指教,如有不妥之处,还请见谅。 废话少说,直接..
  • 3、v4l2 摄像头采集并输出到yuv文件 gst-launch-0.10 v4l2src ! ffmpegcolorspace ! video/x-raw-yuv, format=/(fourcc/)I420, width=352,height=288 ! filesink location=v4l2.yuv1 shallon@shallon-...
  • 基于QT开发的V4L2摄像头视频采集,并使用QLable实现摄像头图像的刷新显示。
  • Linux V4L2 摄像头视频采集

    千次阅读 2012-10-30 10:41:51
    Linux V4L2 摄像头视频采集 分类: ZoneMinder 2011-06-27 09:30 217人阅读 评论(0) 收藏 举报 本文转自:http://blog.csdn.net/jiang_dlut/archive/2010/09/07/5868636.aspx   一,什么是 video4...
  • v4l2 摄像头信息采集

    2017-06-29 17:25:00
    首先我们必须要弄清楚自己使用的USB摄像头的输出格式 网上说利用ffmpeg的命令,可以打印信息:但是我没有事成功,只好插拔摄像机查看信息 1 [root/]# [ 157.840000] usb 1-2.2: USB disconnect, device number 3...
  • LINUX下采集V4L2摄像头数据,并保存成文件,为确保读取摄像头数据不丢失,采样多线程,队列缓冲方式,实现,保存的文件可以直接作为H264编码的源,百分百OK
  • V4L2摄像头视频采集

    2013-04-11 16:46:15
    前言:目前正在忙于ARM平台的Linux应用程序的开发(其实是刚刚起步学习啦)。底层的东西不用考虑了,开发板子提供了NAND ...正文:要做的任务是,把一块板子上的摄像头采集的图像和声卡采集的声音(貌似很啰嗦哈)

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 481
精华内容 192
关键字:

v4l2摄像头采集