精华内容
下载资源
问答
  • linux V4L2编程拍照

    2019-05-21 15:48:12
    linux环境下基于V4L2实现的拍照程序,包括代码和说明文档,可编译通过
  • V4L2编程

    2011-07-07 17:23:28
    下面主要是一些资料的总结,并给出...什么是video4linuxVideo4linux2(简称V4L2),是linux中关于视频设备的内核驱动。在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video0下。 二

    下面主要是一些资料的总结,并给出一个可以结果测试的代码:

     

    一.什么是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;

    }

     

     
     
     
     
    展开全文
  • 手头有一个UVC(usb video class)摄像头(也称为免驱摄像头),就顺便学习了一下V4L2编程 ,写代码的过程中参考了前辈的博客,觉得写的非常的好,特将链接贴在这里 ... 关于V4L2讲解的可以学习前辈的博客,这里只是...

    手头有一个UVC(usb video class)摄像头(也称为免驱摄像头),就顺便学习了一下V4L2编程 ,写代码的过程中参考了前辈的博客,觉得写的非常的好,特将链接贴在这里

    http://www.linuxidc.com/Linux/2016-11/137067.htm


    关于V4L2讲解的可以学习前辈的博客,这里只是写了一个实例代码供看了知识点还无从下手写代码的新手作为参考。

    平台描述:
        OK210开发板。
        屏幕是开发板自带的800*480的RGB32格式屏幕。
        摄像头输出格式为 640*480 的 YUYV422格式
    

    关于YUYV格式请看这篇博客
    http://www.linuxidc.com/Linux/2016-11/137068.htm

    关于RGB32的
    rgb32 : low memory address —-> high memory address
    | pixel | pixel | pixel | pixel | pixel | pixel |…
    |——-|——-|——-|——-|——-|——-|…
    |B|G|R|A|B|G|R|A|B|G|R|A|B|G|R|A|B|G|R|A|B|G|R|A|..
    A表示透明度,0表示不透明,255表示透明度最高

    效果:

    全部代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <linux/fb.h>
    #include <linux/videodev2.h>
    #include <sys/ioctl.h>
    #include <sys/mman.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <pthread.h>
    
    
    int status = 1;   //停止标志位,1开始,0停止
    
    /* 监听线程 当启动摄像头后从键盘输入q,结束程序 */
    void * listen(void * arg) 
    {
        while(1) {
            char buf[20];
            scanf("%s", buf);
            if(strcmp("q", buf) == 0) {
                status = 0;
                break;
            }
            usleep(10);
        }
    }
    
    /* 屏幕初始化和销毁函数 */
    char * fb_init(char * devname, int * fd, int * len);
    void fb_destory(int fd, char * screen_bbf, int screenlen); 
    
    /* 
        函数功能:进行图像转换,将uvc输出的yuyv格式图像转换成RGB32格式的图像
        返回值:无
        参数: 
            yuv yuyv格式图像存储地址
            buf RGB32格式图像存储地址
            length 图像的大小(单位:字节)
    */
    void process_image(unsigned char * yuv, unsigned char *buf, int length);
    /*
        函数功能:向屏幕输出图像
        返回值:无
        参数 : screen_bbf  内存映射后屏幕在程序中的地址
                        buf                 RGB32格式的数据地址
                        width               图像的宽度
                        height          图像的高度
    */
    void show_image(char * screen_bbf, char *buf, int width, int height);
    
    
    /* 保存摄像头内存映射后的内存地址和数据长度 */
    struct buffer {
        char * start;
        unsigned int length;
    };
    
    int width,height;
    
    int main(int argc, char ** argv)
    {
        /* 摄像头采集的是YUYV格式的图像, 
            屏幕显示需要RGB32格式的图像,
            而且屏幕大小和摄像头的视野大小也不一样
            这里申请一块内存作为缓冲区,存储格式转换后的数据
         */
        unsigned char * bbf = (unsigned char *)malloc(640*480*4);  
        printf(" bbf address : %p\n", bbf);
        /**************** 设置屏幕 ****************/
        int fb_fd, screenlen;
        char * screen_bbf = fb_init("/dev/fb0", &fb_fd, &screenlen);
    
        /*************** 开始设置摄像头 ********************/
        /* 打开摄像头设备 */
        int cam_fd = open("/dev/video3", O_RDWR);
        if (cam_fd == -1) {
            printf("error : %s\n", strerror(errno));
            return -1;
        }
        /* 得到描述摄像头信息的结构体 */
        struct v4l2_capability cap;
        int rel = ioctl(cam_fd, VIDIOC_QUERYCAP, &cap);
        if ( rel == -1) {
            printf("error : %s\n", strerror(errno));
            goto ERROR;
        }
        /* 判断改设备支不支持捕获图像和流输出功能 */
        if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE) 
            printf("it's camer!\n");
        else {
            printf("it's not a camer!\n");
            goto ERROR;
        }
        if ((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING)
            printf("it's stream device!\n");
        else {
            printf("it's not a stream device!\n");
            goto ERROR;
        }
    
        printf("Driver Name : %s\n\
        Card Name : %s\nBus info : %s\n\
        Driver Version : %u.%u.%u\n ",\
        cap.driver, cap.card, cap.bus_info,\
         (cap.version>>16)&0xff, (cap.version>>8)&0xff, (cap.version)&0xff);
    
        /* 得到摄像头采集图像的格式信息 */
        struct v4l2_format fmt;
        memset(&fmt, 0, sizeof(fmt));
        fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        rel = ioctl(cam_fd, VIDIOC_G_FMT, &fmt);
        if (rel == -1) {
            printf("get fmt failed!\n");
            goto ERROR;
        }
    
        width = fmt.fmt.pix.width;
        height = fmt.fmt.pix.height;
    
        printf("width : %d  height : %d\n\
        pixelformat : %d\n\
        field : %d\n\
        bytesperline : %d\n\
        sizeimage : %d\n\
        colorspace : %d\n\
        priv : %d\n",\
        fmt.fmt.pix.width,\
         fmt.fmt.pix.height,\
        fmt.fmt.pix.pixelformat,\
         fmt.fmt.pix.field, \
         fmt.fmt.pix.bytesperline, \
         fmt.fmt.pix.sizeimage, \
         fmt.fmt.pix.colorspace, \
         fmt.fmt.pix.priv);
        /* 得到摄像头所支持的所有格式 */
        struct v4l2_fmtdesc fmtdesc;
        fmtdesc.index = 0;
        fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        printf(" Support format : \n");
        while (ioctl(cam_fd, VIDIOC_ENUM_FMT, &fmtdesc) != -1) {
            printf("\t%d.%s\n", fmtdesc.index+1, fmtdesc.description);
            fmtdesc.index++;
        }
    
    
        /* 向摄像头申请一个数据帧队列 */
        struct v4l2_requestbuffers req;
        req.count = 4;
        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        req.memory = V4L2_MEMORY_MMAP;
        rel = ioctl(cam_fd, VIDIOC_REQBUFS, &req);
        if(rel < 0) {
            printf("request buffers error : %s\n", strerror(errno));
            goto ERROR;
        } else 
            printf("request buffers successed!\n");
    
        /* 申请存储图像缓冲区地址和长度的数组内存 */
        struct buffer * buffers = (struct buffer *)malloc(4*sizeof(struct buffer *));
        if (buffers == NULL ) {
            printf("malloc buffers err : %s\n", strerror(errno));
            goto ERROR;
        }
        /* 将缓冲区的内存映射到用户空间 */
        int n_buffers = 0;
        for (; 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(cam_fd, VIDIOC_QUERYBUF, &buf)) {  //获取缓冲帧的地址
                printf("set buf error : %s\n", strerror(errno));
                goto ERROR;
            } else {
                printf("set buf success!\n");
            }
            buffers[n_buffers].length = buf.length;
            /* 映射内存空间 */
            buffers[n_buffers].start = mmap(NULL, buf.length, PROT_READ|PROT_WRITE, \
            MAP_SHARED, cam_fd, buf.m.offset);
            if (NULL == buffers[n_buffers].start) {
                printf("mmap error : %s\n", strerror(errno));
                goto MAP_ERROR;
            } else 
                printf("mmap success! address = %p\n",buffers[n_buffers].start);
                ioctl(cam_fd, VIDIOC_QBUF, &buf);
        }
    
        /* 开启视频流 */
            enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            if (-1 == ioctl(cam_fd, VIDIOC_STREAMON, &type))
                goto MAP_ERROR;
            else 
                printf("start stream!\n");
    
        /* 创建一个监听线程,用于停止程序 */
        pthread_t pd;
        pthread_create(&pd, NULL, listen, NULL);
    
        /* 开始捕获摄像头数据,并显示在屏幕上 */
        while(status) {
            /* 初始化select监听  */
            fd_set fds;
            FD_ZERO(&fds);
            FD_SET(cam_fd, &fds);
            struct timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = 125000;
            int ret = select(cam_fd+1, &fds, NULL, NULL, &tv);
            if (ret == -1) {
                printf(" error : listen failes\n");
            } else if (ret == 0) {
                printf(" time out !\n");
            } else {
                struct v4l2_buffer buf;
                memset(&buf, 0, sizeof(buf));
                buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                buf.memory = V4L2_MEMORY_MMAP;
                /* 得到一帧数据 */
                if (ioctl(cam_fd, VIDIOC_DQBUF, &buf) != -1) {
                    /* 进行格式转换 */
                    process_image(buffers[buf.index].start, bbf, buffers[buf.index].length);    
                    /* 显示在屏幕上 */
                    show_image(screen_bbf, bbf, width, height);
                    /* 将帧放回队列 */
                    if (-1 != (ioctl(cam_fd, VIDIOC_QBUF, &buf)))
                        printf(" put in success!\n");
                    else 
                        printf(" put in failed!\n");
                } else 
                    printf(" get frame failed!\n");
            }
        }
    
        /* 关闭视频流 */
        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        ioctl(cam_fd, VIDIOC_STREAMOFF, &type);
    
        /* 解除内存映射,关闭文件描述符,程序结束 */
        int i;
        for (i=0; i<4; i++) {
            if (buffers[i].start != NULL)
                munmap(buffers[i].start, buffers[i].length);
        }
        close(cam_fd);
        fb_destory(fb_fd, screen_bbf, screenlen);
        free(bbf);
        return 0;
    
    
    MAP_ERROR:  
        for (n_buffers=0; n_buffers<4; n_buffers++) {
            if (buffers[n_buffers].start != NULL)
                munmap(buffers[n_buffers].start, buffers[n_buffers].length);
        }
    ERROR:
        fb_destory(fb_fd, screen_bbf, screenlen);
        close(cam_fd);
        free(bbf);
        return -1;
    }
    /* 
        不知道为什么以YUVY格式转换的RGB32在屏幕上的效果比YUYV格式展开的还要好
        下边程序中的是以YUVY格式展开的程序,YUYV的转换程序应该是
                v0 = yuv[count*4+0];
            y0 = yuv[count*4+1];
            u0 = yuv[count*4+2];
            y1 = yuv[count*4+3];
    */
    void process_image(unsigned char * yuv, unsigned char * buf, int length)
    {
        int count;
        int y0,u0,y1,v0;
        for (count=0; count<length/4; count++) {
            y0 = yuv[count*4+0];
            u0 = yuv[count*4+1];
            y1 = yuv[count*4+2];
            v0 = yuv[count*4+3];
            buf[count*8+0] = 1.164*(y0-16) + 2.018*(u0-128); //b
            buf[count*8+1] = 1.164*(y0-16) - 0.380*(u0-128) + 0.813*(v0-128); //g
            buf[count*8+2] = 1.164*(y0-16) + 1.159*(v0-128); //r
            buf[count*8+3] = 0; //透明度
    
            buf[count*8+4] = 1.164*(y1-16) + 2.018*(u0-128); //b
            buf[count*8+5] = 1.164*(y1-16) - 0.380*(u0-128) + 0.813*(v0-128); //g
            buf[count*8+6] = 1.164*(y1-16) + 1.159*(v0-128); //r
            buf[count*8+7] = 0; //透明度
        }
    }
    
    void show_image(char * screen_bbf, char * buf, int width, int height)
    {
        int i,j;
        for (i=0; i<height; i++) {
                memcpy(screen_bbf+80*4+i*800*4 ,buf+i*width*4,width*4);
        }
    }
    
    char * fb_init(char * devname, int * fd, int * screenlen)
    {
        *fd = open(devname, O_RDWR);
        if (*fd == -1) {
            printf("error : %s\n", strerror(errno));
            return -1;
        }
        struct fb_var_screeninfo fbvs;
        int ret = ioctl(*fd, FBIOGET_VSCREENINFO, &fbvs);
        if (ret == -1) {
            printf("get screen info failed!\n");
            close(*fd);
            return NULL;
        } else {
            printf("screen info:\n\twidth : %d\thwight : %d\tbits_per_pixel : %d\n", \
            fbvs.xres, fbvs.yres,fbvs.bits_per_pixel);
        }
    
        *screenlen =  fbvs.xres*fbvs.yres*fbvs.bits_per_pixel/8;
        char *screen_bbf = (char *)mmap(NULL, *screenlen, PROT_WRITE | PROT_READ, MAP_SHARED, *fd,0);
        if (screen_bbf == NULL) {
            printf("screen mmap failed!\n");
            close(*fd);
            return NULL;
        } else {
            return screen_bbf;
        }
    }
    
    void fb_destory(int fd, char * screen_bbf, int screenlen) 
    {
        munmap(screen_bbf, screenlen);
        close(fd);
    }

    参考:https://www.linuxidc.com/linux/2016-11/137066.htm

    展开全文
  • 1. 什么是V4L2 V4L2(Video For Linux Two) 是内核提供给应用程序访问音、视频驱动的统一接口。2. 编程步骤 打开设备-> 检查和设置设备属性-> 设置帧格式-> 设置一种输入输出方法(缓冲 区管理)-> 循环获取数据...

    1. 什么是V4L2

    V4L2(Video For Linux Two) 是内核提供给应用程序访问音、视频驱动的统一接口。


    2. 编程步骤

    打开设备-> 检查和设置设备属性-> 设置帧格式-> 设置一种输入输出方法(缓冲 区管理)-> 循环获取数据-> 关闭设备。


    3. 设备的打开和关闭

    相关代码如下:


    4. 查询设备属性


    相关方法如下:

    int ioctl(int fd, int request, struct v4l2_capability *argp);

    VIDIOC_QUERYCAP -- Query device capabilities

    相关结构体如下:

    struct v4l2_capability
    {
    	u8 driver[16]; // 驱动名字
    	u8 card[32]; // 设备名字
    	u8 bus_info[32]; // 设备在系统中的位置
    	u32 version; // 驱动版本号
    	u32 capabilities; // 设备支持的操作
    	u32 reserved[4]; // 保留字段
    };
    

    相关参考代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/ioctl.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <linux/videodev2.h>  
    
    
    #if 0
    struct v4l2_capability
    {
    	__u8	driver[16];	/* i.e. "bttv" */
    	__u8	card[32];	/* i.e. "Hauppauge WinTV" */
    	__u8	bus_info[32];	/* "PCI:" + pci_name(pci_dev) */
    	__u32   version;        /* should use KERNEL_VERSION() */
    	__u32	capabilities;	/* Device capabilities */
    	__u32	reserved[4];
    };
    
    #endif
    
    int main(void)
    {
    
        int fd = -1; 
        int ret = -1;
    
        struct v4l2_capability cap;
    
        //open the device
        fd = open("/dev/video0", O_RDWR);
        if (-1 == fd)
        {
            perror("open"); 
            goto err0;
        }
    
        printf("fd = %d\n", fd);
    
        memset(&cap, 0, sizeof(cap));
        //query device capabilities
        ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
        if (-1 == ret)
        {
            perror("ioctl"); 
            goto err0;
        }
    
        printf("driver name: %s   device name: %s device location: %s\n", cap.driver, cap.card, cap.bus_info);
        printf("version: %u.%u.%u\n", (cap.version >> 16) & 0xff, (cap.version >> 8) & 0xff, cap.version & 0xff);
    
        if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
            printf("Is a video capture device\n");
        else
            printf("Is not a video capture device\n");
    
    
        //close device
        close(fd);
    
        return 0;
    err0:
        return -1;
    }
    
    


    执行结果如下:


    capabilities 常用值:

    V4L2_CAP_VIDEO_CAPTURE // 是否支持图像获取








    展开全文
  • V4L2编程模型简介

    2013-08-13 15:45:20
    简介:本文所附代码是根据v4l2官方文档以及demo(capture.c)修改而来,纯粹为学习交流之用,请勿使用在商用场合。 地址:由于官方网的域名有敏感词汇,所以请google一下。 一 、操作流程简单看 二、 ...

    简介:本文所附代码是根据v4l2官方文档以及demo(capture.c)修改而来,纯粹为学习交流之用,请勿使用在商用场合。

    地址:由于官方网的域名有敏感词汇,所以请google一下。

    一 、操作流程简单看

    二、 模块概要分析

    以下是所附代码所涉及到的全局变量,摆出来只是参考,具体修改的话请自行安排。

    #define CLEAR(x) memset (&(x), 0, sizeof (x))
            typedef enum {

    #ifdef IO_READ
                    IO_METHOD_READ,
            #endif
            #ifdef IO_MMAP
                    IO_METHOD_MMAP,
            #endif
            #ifdef IO_USERPTR
                    IO_METHOD_USERPTR,
            #endif
                    } io_method;

    struct buffer {
            void * start;
            size_t length;
            };

    static io_method io = IO_METHOD_MMAP;
            static int fd = -1;
            struct buffer * buffers = NULL;
            static unsigned int n_buffers = 0;
            // global settings
            static unsigned int width = 640;
            static unsigned int height = 480;
            static unsigned char jpegQuality = 70;
            static char* jpegFilename = NULL;
            static char* deviceName = "/dev/video0";

    1.deviceOpen

    主要就是打开你的设备文件,一般情况下就是,/dev/vedio0 取决于你的设备数量。前面提到的stat这个结构体主要是记录了文件的基本信息。通过这一点来校验文件的打开权限。

    2.deviceInit

    这个模块稍微复杂些,它主要是使用了v4l2中定义的4种相关的数据结构。以下列出每种结构的具体属性。
            struct v4l2_cropcap {
                    enum v4l2_buf_type type;
                    struct v4l2_rect bounds;
                    struct v4l2_rect defrect;
                    struct v4l2_fract pixelaspect; 
            };
            struct v4l2_crop {
                     enum v4l2_buf_type type;
                    struct v4l2_rect c;
            };
            struct v4l2_capability {
                     __u8 driver[16]; /* i.e. "bttv" */
                    __u8 card[32]; /* i.e. "Hauppauge WinTV" */
                    __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */
                    __u32 version; /* should use KERNEL_VERSION() */
                    __u32 capabilities; /* Device capabilities */
                    __u32 reserved[4];
            };
            struct v4l2_format {
                    enum v4l2_buf_type type;
                    union {
                            struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
                            struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
                            struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */
                            struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
                             __u8 raw_data[200]; /* user-defined */
                    } fmt;
            };

    这里不得不提醒一点,通常usb摄像头驱动,都会提供3种不同的数据传输方式,1,read IO 2,mmap内存映射 3,USERPTR(这一种是测试方法,具体可以去查询)

    本文暂且只讨论常见的操作方法,即mmap内存映射方式.

    通过一段时间的学习,才知道为什么只支持mmap,其实是我们所用的去架构是基于uvc.在uvc架构中,是不支持read/write io mode 以及用户扩展模式。
            static void deviceInit(void)
            {
                    struct v4l2_capability cap;
                    struct v4l2_cropcap cropcap; 
                    struct v4l2_crop crop;
                    struct v4l2_format fmt;
                    unsigned int min;
                    if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) { //get the capab info about
                    if (EINVAL == errno) {
                    fprintf(stderr, "%s is no V4L2 device\n",deviceName);
                    exit(EXIT_FAILURE);
                    } else {
                    errno_exit("VIDIOC_QUERYCAP");
                    }
            }
            if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { //check is it support capture mode ?
                    fprintf(stderr, "%s is no video capture device\n",deviceName);
                    exit(EXIT_FAILURE);
            }
            if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
                    fprintf(stderr, "%s does not support streaming i/o\n",deviceName);
                    exit(EXIT_FAILURE);
            }
            /* Select video input, video standard and tune here. */
            CLEAR(cropcap);// init -0 it is a initialize func about set 0 to parameter 
            cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
                    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                    crop.c = cropcap.defrect; /* reset to default */
                     if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
                            switch (errno) {
                            case EINVAL:
                            /* Cropping not supported. */
                            break;
                            default:
                             /* Errors ignored. */
                            break;
                            }
                    }
            } 
            CLEAR (fmt); 
            // v4l2_format
            fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //mode is capture 
            fmt.fmt.pix.width = width; //define pixee width
            fmt.fmt.pix.height = height; //define pixel height
            fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //define pixel format
            fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 
            if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) //set fmt 
            errno_exit("VIDIOC_S_FMT");
            /* Note VIDIOC_S_FMT may change width and height. */
             if (width != fmt.fmt.pix.width) {
                    width = fmt.fmt.pix.width;
                    fprintf(stderr,"Image width set to %i by device %s.\n",width,deviceName);
                    }
            if (height != fmt.fmt.pix.height) {
                    height = fmt.fmt.pix.height;
                    fprintf(stderr,"Image height set to %i by device %s.\n",height,deviceName);
                    }
            /* Buggy driver paranoia. */
            min = fmt.fmt.pix.width * 2;
            if (fmt.fmt.pix.bytesperline < min)
            fmt.fmt.pix.bytesperline = min;
            min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
             if (fmt.fmt.pix.sizeimage < min)
            fmt.fmt.pix.sizeimage = min;
            //this function is important to init mmap pre_work 
            mmapInit();
            }

    可以看到上面主要是初始化工作,具体的参数意义,请参看v4l2的specification 。

    static void mmapInit(void)
            {
                    struct v4l2_requestbuffers req;//apply for frame buffer
                    CLEAR (req);
                    req.count = 4;
                    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
                    req.memory = V4L2_MEMORY_MMAP;
                    if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
                            if (EINVAL == errno) {
                                    fprintf(stderr, "%s does not support memory mapping\n", deviceName);
                                    exit(EXIT_FAILURE);
                            } else {
                    errno_exit("VIDIOC_REQBUFS");
                    }
            }
            if (req.count < 2) {
                    fprintf(stderr, "Insufficient buffer memory on %s\n", deviceName);
                    exit(EXIT_FAILURE);
             }
             buffers = calloc(req.count, sizeof(*buffers));
            if (!buffers) {
                    fprintf(stderr, "Out of memory\n");
                    exit(EXIT_FAILURE);
            }
            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 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
                    errno_exit("VIDIOC_QUERYBUF");
                    buffers[n_buffers].length = buf.length;
                    buffers[n_buffers].start =
                    mmap (NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, fd, buf.m.offset);
                    if (MAP_FAILED == buffers[n_buffers].start)
                    errno_exit("mmap");
                    }
            }

    3.capture_start

    初始化以后就可以进行正题了,就是所谓的capture data.不过在此之前,应该打开数据流通道,重点在于最后那个ioctl函数的参数:VIDIOC_STREAMON

    static void captureStart(void) //grap after initialize
            {
                    unsigned int i;
                    enum v4l2_buf_type type; //page-68
                    #ifdef IO_MMAP
                    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 == xioctl(fd, VIDIOC_QBUF, &buf))
                            errno_exit("VIDIOC_QBUF");
                            }
            type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
            errno_exit("VIDIOC_STREAMON");
            #endif

    上面出现的两个结构体的分别定义如下:
            enum v4l2_buf_type {
            V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
            V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
            V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
            V4L2_BUF_TYPE_VBI_CAPTURE = 4,
            V4L2_BUF_TYPE_VBI_OUTPUT = 5,
            V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6,
            V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7,
            #if 1
            /* Experimental */
            V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
            #endif
            V4L2_BUF_TYPE_PRIVATE = 0x80,
            };
             struct v4l2_buffer {
                     __u32 index;
                     enum v4l2_buf_type type;
                     __u32 bytesused;
                     __u32 flags;
                    enum v4l2_field field;
                    struct timeval timestamp;
                    struct v4l2_timecode timecode;
                    __u32 sequence;
                    /* memory location */
                    enum v4l2_memory memory;
                    union {
                            __u32 offset;
                            unsigned long userptr;
                     } m;
                    __u32 length;
                    __u32 input;
                    __u32 reserved;
            };

    展开全文
  • V4L2编程模型简介(一) 作者:邹南,华清远见嵌入式学院讲师。 简介:本文所附代码是根据v4l2官方文档以及demo(capture.c)修改而来,纯粹为学习交流之用,请勿使用在商用场合。 地址:由于官方网的域名有敏感词汇...
  • 手头有一个UVC(usb video class)摄像头(也称为免驱摄像头),就顺便学习了一下V4L2编程 ,写代码的过程中参考了前辈的博客,觉得写的非常的好,特将链接贴在这里 ...关于V4L2讲解的可以学习前辈的博客,这里只是写...
  • 再看懂别人的每一行代码v4l2的每一个结构体,然后去消化它。2.细心一点,跟踪问题出在哪里,然后顺藤摸瓜,一定是可以调出来的。3.一定要相信,你是可以调出来的。4.规范命名,规范注释,规范写代码。嘿嘿,溜了溜...
  • V4L2编程笔记 (3)

    热门讨论 2010-04-18 08:58:00
    代码以出来,能转换成JPG图片格式,若有兴趣,可跟我联系!
  • V4L2视频编程 demo C++

    2009-12-24 13:59:54
    利用V4L2实现Linux平台下视频的初步Demo代码 对初学者有一定参考价值
  • 详细介绍使用mmap实现V4L2视频处理机制,包括具体流程,部分参考代码,原理讲解,相信对初学同学有一定帮助
  • v4l2采集图像

    2018-05-14 15:02:00
    用于v4l2编程框架下的普通USB摄像头图像采集代码,完成初始化摄像头,创建缓冲buf读取缓冲buf功能
  • 该文件是基于v4l2接口编程的从USB摄像头采集图像信息,并在LCD实时显示的代码,里面是纯c写的,由Makefile编译
  • 代码示例: 单平面示例: https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/capture.c.html 多平面示例: https://blog.csdn.net/airk000/article/details/25033269 https://github.com/FFmpeg/FFmpeg ...
  • 一、打开视频设备打开视频设备非常简单,在V4L2中,视频设备被看做一个文件。使用open函数打开这个设备:1. 用非阻塞模式打开摄像头设备int cameraFd;cameraFd = open("/dev/video0", O_RDWR | O_NONBLOCK);2...
  • Qt浅谈之四十Centos下Qt结合v4l2实现的视频显示

    千次阅读 热门讨论 2016-01-20 18:20:14
    v4l2是针对uvc免驱usb设备的编程框架,主要用于采集usb摄像头。 可从网上下载最新的源码(包括v4l2.c和v4l2.h两个文件),本文中修改过。 Qt运行界面如下(动态变化的): 二、详解 1、准备 (1)插入usb...
  • 还参考了imx6测试代码:Mxc_v4l2_tvin.c 对以上内容进行自己的总结 1.V4L2的定义 Video For Linux Two 是内核提供给应用程序访问音、视频驱动的统一接口,我们只需要利用其提供的API进行应用程序编程
  • RTP传输JPEG图片到VLC实时播放(代码)

    千次阅读 2015-01-08 11:31:02
    一、环境是ubuntu 二、采集视频。 我这里采集的是YUYV422,然后可以通过两种方式转化,1.yuyv422->yuv420->jpeg->rtp->vlc...V4L2编程可以参考:V4L2编程 YUYV422转RGB参考:YUYV2RGB 三、代码下载 包含jpeg-9a库,库安
  • RTP打包传输MJPEG码流

    千次阅读 2015-07-22 16:43:35
    一、环境是ubuntu 二、采集视频。 我这里采集的是YUYV422,然后可以通过两种方式转化,1.yuyv422->yuv420->jpeg->rtp->vlc(yuv...V4L2编程可以参考:V4L2编程 YUYV422转RGB参考:YUYV422TORGB 三、代码下载 包含jpeg-9a
  • Linux系统中提供的视频设备驱动程序V4L2编程可以提供我们操作视频设备,比如摄像头。同时我们可以用开源的ffmpeg库中的函数实现所采集的视频数据进行压缩编码,生成我们需要的视频格式。下面的代码,是将USB摄像头所...
  • mjpg-streamer源码分析

    2011-05-19 14:09:00
    作者:曹忠明,华清远见嵌入式培训中心讲师。 mjpg-streamer是... 这个代码里有三个部分是我们需要掌握的内容,第一是v4l2接口,第二个是socket编程,第三个是多线程编程。 一、 v4l2接口说明<br /
  • Mjpeg-streamer源码分析(一)

    千次阅读 2012-07-09 11:30:52
    mjpg-streamer是一个很好的开源项目,用来做视频服务器,使用的是v4l2的接口。前面我们说了它的移植过程,...这个代码里有三个部分是我们需要掌握的内容,第一是v4l2接口,第二个是socket编程,第三个是多线程编程
  • mjpg-streamer

    2011-12-10 20:59:19
    mjpg-streamer是一个很好的开源项目,用来做视频服务器,使用的是v4l2的接口。前面我们说了它的移植过程...这个代码里有三个部分是我们需要掌握的内容,第一是v4l2接口,第二个是socket编程,第三个是多线程编程。 一

空空如也

空空如也

1 2
收藏数 35
精华内容 14
关键字:

v4l2编程代码