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。

2019年12月4日Linux开发手记的更多相关文章

  1. 2019年12月2日Linux开发手记

    开始学习在Linux下视频源捕获驱动框架,也就是V4L2(video4linux),本次关于v4l2的知识准备主要在于其的官方例程,理解官方例程也就差不多掌握了v4l2的基本内容.例程在:http:/ ...

  2. 2019年12月18日Linux开发手记

    安装idle3: 1.端输入apt install idle3 以安装 2.安装完成后在终端输入idle以启动 配置pip: 1.终端输入apt install python3-pip 使用pip配置 ...

  3. 2019年12月1日Linux开发手记

    配置ubuntu摄像头: 1.设置→添加→usb控制器→兼容usb3.0 2.虚拟机→可移动设备→web camera→连接(断开主机) 3.查看是否配置成功,打开终端,输入: susb ls /de ...

  4. 2019年12月4日 Linux总结

    System V init运行级别 systemd目标名称 作用 0 runlevel0.target,poweroff.target 关机 1 runlevel1.target,poweroff.t ...

  5. 20.Nodejs基础知识(上)——2019年12月16日

    2019年12月16日18:58:55 2019年10月04日12:20:59 1. nodejs简介 Node.js是一个让JavaScript运行在服务器端的开发平台,它让JavaScript的触 ...

  6. 36.React基础介绍——2019年12月24日

    2019年12月24日16:47:12 2019年10月25日11:24:29 主要介绍react入门知识. 1.jsx语法介绍 1.1 介绍 jsx语法是一种类似于html标签的语法,它的作用相当于 ...

  7. 35.ES6语法介绍——2019年12月24日

    2019年12月24日16:22:24 2019年10月09日12:04:44 1. ES6介绍 1.1 新的 Javascript 语法标准 --2015年6月正式发布 --使用babel语法转换器 ...

  8. 22.Express框架——2019年12月19日

    2019年12月19日14:16:36 1. express简介 1.1 介绍 Express框架是后台的Node框架,所以和jQuery.zepto.yui.bootstrap都不一个东西. Exp ...

  9. 19.go语言基础学习(下)——2019年12月16日

    2019年12月16日16:57:04 5.接口 2019年11月01日15:56:09 5.1 duck typing 1. 2. 接口 3.介绍 Go 语言的接口设计是非侵入式的,接口编写者无须知 ...

随机推荐

  1. swift 手机号、邮箱、网址等正则表达式验证

    看到一个不错的swift的 手机号.邮箱.网址等正则表达式验证,分享给大家. 支持swift3,经过修改后,亲测可用! import Foundation enum Validate { case e ...

  2. Shiro笔记---身份验证

    1.shiro有哪些主要功能 2.搭建shiro环境(*) idea2018.2.maven3.5.4.jdk1.8   项目结构: pom.xml: <dependencies> < ...

  3. OV5640摄像头配置一些值得注意的关键点(三)

    一.字节标志的注意点 由于摄像头的输出是RGB56格式,所以需要将两帧的数据进行拼接,之后送到上位机进行显示. reg byte_flag; always@(posedge cmos_pclk_i) ...

  4. Pandas常用数据结构

    Pandas 概述 Pandas(Python Data Analysis Library)是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的.Pandas 纳入了大量库和一些标准的数 ...

  5. TCP/IP协议第一卷第一章

    1.链路层 链路层有时也称作数据链路层或网络接口层,通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡.它们一起处理与电缆(或其他任何传输媒介)的物理接口细节.把链路层地址和网络层地址联系起来 ...

  6. NOIP模拟 7

    考试最后半小时发现T1过不去任何样例,T飞,发现没调用solv函数,挽回40分 考试最后几分钟给T2测了一组自制样例,发现了bug,挽回20分 天- -检查这么重要的么(其实是我第一次打的时候就没验证 ...

  7. 【WPF on .NET Core 3.0】 Stylet演示项目 - 简易图书管理系统(3) - 使用Conductor切换页面

    前两章中, 我们已经实现了这个图书管理系统的登录窗口, 并实施了完善的单元测试. 该是时候回过头来关注我们的主窗口了. 一个功能丰富的系统一般会有多个页面, 我们图书管理系统虽然是"简易&q ...

  8. linux常用的命令解释

    1.man命令的操作按键: 按键 用处 空格键 向下翻一页. [Page Down] 向下翻一页. [Page Up] 向上翻一页. [HOME] 直接前往首页. [END] 直接前往尾页. /关键词 ...

  9. 基于typedef的用法详解【转】

    也许新手用这个关键字不多,但它却是一个很有用的关键字,可以使代码模块化程度更好(即与其它代码的关联较少),在C++中还是实现Traits技术的基础,也是模板编程的基本语法之一. 若说变量定义是为变量命 ...

  10. 每天3分钟操作系统修炼秘籍(14):IO操作和DMA、RDMA

    点我查看秘籍连载 I/O操作和DMA.RDMA 用户进程想要执行IO操作时(例如想要读磁盘数据.向磁盘写数据.读键盘的输入等等),由于用户进程工作在用户模式下,它没有执行这些操作的权限,只能通过发起对 ...