ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

2019年12月4日Linux开发手记

2019-12-04 21:53:12  阅读:330  来源: 互联网

标签:12 V4L2 void errno 2019 Linux fd buf buffers


OK,经过昨天对V4L2工作流程的学习,现在已经大体了解了V4L2的工作原理,现在开始对V4L2的API的学习,目标:1、打开摄像头 2、储存图像 3、关闭摄像头,API网址:Linux Media Infrastructure userspace API — The Linux Kernel documentation https://linuxtv.org/downloads/v4l-dvb-apis/media_uapi.html

具体流程如下:

1、打开设备:

static void open_device()

{

dev_name = "/dev/video0";

fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);

}

2、初始化设备:

static void init_device()

介于初始化设备函数过于复杂,这里就直接copy官方例程中的init_device()函数,此处就不多做叙述了,例程:https://blog.csdn.net/snow_rain_1314/article/details/85072669 。在初始化设备时主要完成了对用户空间的获取,图像格式以及I/O模式的确定等,这里我们的I/O模式为内存映射即Memory Mapping(MMAP)模式。

3、捕获图像:

static void start_capturing(void)

{

      unsigned int i;

      enum v4l2_buf_type type;

      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");

}

4、主循环

static void mainloop(void)

    {

          unsigned int count;

 

          count = frame_count;//帧数70

 

          while (count-- > 0) {

                 for (;;) {/*select()机制中提供一fd_set的数据结构,实际上是一long类型的数组,

                           每一个数组元素都能与一打开的文件句柄(不管是socket句柄,还是其他文件或命名管道或设备句柄)建立联系,

                           当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一socket或文件可读*/

                        fd_set fds; 

                          

                        struct timeval tv;//时间值

                        int r;

 

                        FD_ZERO(&fds); /*将set清零使集合中不含任何fd*/

                        FD_SET(fd, &fds);/*将fd加入set集合*/

 

                        /* Timeout. */

                        tv.tv_sec = 2; //2s

                        tv.tv_usec = 0;//0微妙

 

                        r = select(fd + 1, &fds, NULL, NULL, &tv);//select操作,用于确定一个或多个套接口的状态,返回满足条件的套接口的数目,最多只等待两秒,

 

                        if (-1 == r) { //所有描述符集清零

                               if (EINTR == errno)//如果错误类型为4(中断系统呼叫)

                                      continue;

                               errno_exit("select");

                        }

 

                        if (0 == r) { //超时

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

                               exit(EXIT_FAILURE);

                        }

 

                        if (read_frame())//读取帧

                               break;

                        /* EAGAIN - continue select loop. */

                 }

          }

    }

5、在主循环的过程中读取帧

static int read_frame(void)

    {

   struct v4l2_buffer buf;//v4l2中临时缓冲器

     unsigned int i;

     CLEAR(buf);

               buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

               buf.memory = V4L2_MEMORY_MMAP;

               if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {

                      switch (errno) {

                      case EAGAIN:

                             return 0;

                      case EIO:

                             /* Could ignore EIO, see spec. */

                             /* fall through */

                      default:

                             errno_exit("VIDIOC_DQBUF");

                      }

               }

               assert(buf.index < n_buffers);//断言,索引小于缓冲区个数

               process_image(buffers[buf.index].start, buf.bytesused);//进程映射

               if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))

                      errno_exit("VIDIOC_QBUF");

}

6、读取帧时开始存储图像

static void process_image(const void *p, int size)

    {

            FILE *fp = fopen("a.jpg","w");

 

           if (out_buf)

              {

                  fwrite(p, size, 1, fp);

                    fclose(fp);

                  //printf("1");

              }

 

           fflush(stderr);

           fprintf(stderr, "Can not open it!\n");

           fflush(stdout);

    }

7、停止捕获

static void stop_capturing(void)

    {

           enum v4l2_buf_type type;

 

           switch (io) {

           case IO_METHOD_READ:

                  /* Nothing to do. */

                  break;

 

           case IO_METHOD_MMAP:

           case IO_METHOD_USERPTR:

                  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

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

                         errno_exit("VIDIOC_STREAMOFF");

                  break;

           }

    }

8、释放内存

static void uninit_device(void)

    {

           unsigned int i;

           switch (io) {

           case IO_METHOD_READ:

                  free(buffers[0].start);

                  break;

           case IO_METHOD_MMAP:

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

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

                                errno_exit("munmap");

                  break;

           case IO_METHOD_USERPTR:

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

                         free(buffers[i].start);

                  break;

           }

           free(buffers);

    }

9、关闭设备

static void close_device(void)

    {

           if (-1 == close(fd))

                  errno_exit("close");

 

           fd = -1;

    }

10、输出异常

fprintf(stderr, "\\n");

 

使用V4L2打开摄像头获取图像的流程就是这样,下一步就是使用python调用这个程序,取代cv2.imwrite。

标签:12,V4L2,void,errno,2019,Linux,fd,buf,buffers
来源: https://www.cnblogs.com/lvfengkun/p/11985882.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有