2019年12月4日Linux开发手记
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开发手记的更多相关文章
- 2019年12月2日Linux开发手记
开始学习在Linux下视频源捕获驱动框架,也就是V4L2(video4linux),本次关于v4l2的知识准备主要在于其的官方例程,理解官方例程也就差不多掌握了v4l2的基本内容.例程在:http:/ ...
- 2019年12月18日Linux开发手记
安装idle3: 1.端输入apt install idle3 以安装 2.安装完成后在终端输入idle以启动 配置pip: 1.终端输入apt install python3-pip 使用pip配置 ...
- 2019年12月1日Linux开发手记
配置ubuntu摄像头: 1.设置→添加→usb控制器→兼容usb3.0 2.虚拟机→可移动设备→web camera→连接(断开主机) 3.查看是否配置成功,打开终端,输入: susb ls /de ...
- 2019年12月4日 Linux总结
System V init运行级别 systemd目标名称 作用 0 runlevel0.target,poweroff.target 关机 1 runlevel1.target,poweroff.t ...
- 20.Nodejs基础知识(上)——2019年12月16日
2019年12月16日18:58:55 2019年10月04日12:20:59 1. nodejs简介 Node.js是一个让JavaScript运行在服务器端的开发平台,它让JavaScript的触 ...
- 36.React基础介绍——2019年12月24日
2019年12月24日16:47:12 2019年10月25日11:24:29 主要介绍react入门知识. 1.jsx语法介绍 1.1 介绍 jsx语法是一种类似于html标签的语法,它的作用相当于 ...
- 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语法转换器 ...
- 22.Express框架——2019年12月19日
2019年12月19日14:16:36 1. express简介 1.1 介绍 Express框架是后台的Node框架,所以和jQuery.zepto.yui.bootstrap都不一个东西. Exp ...
- 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 语言的接口设计是非侵入式的,接口编写者无须知 ...
随机推荐
- 详细讲解CSS中相对定位relative和绝对定位absolute
很多朋友问过我absolute与relative怎么区分,怎么用?我们都知道absolute是绝对 定位,relative是相对定位,但是这个绝对与相对是什么意思呢?绝对是什么地方的绝对,相对又是相对 ...
- 设计模式C++描述----17.备忘录(Memento)模式
一. 备忘录模式 定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可将该对象恢复到原先保存的状态. 结构图: 使用范围: Memento 模式比较适用于功能 ...
- javadoc的使用
在进行项目开发过程中,项目接口文档是很重要的一块内容,在java项目中我们可以用swagger,asciidoc,javadoc等方式来生产文档,而其中最基本的文档生成方式就是javadoc,它一般用 ...
- 学习笔记32_EF查询优化
*如果有 var temp = from m in dbContext.Model1 where m.属性1 == value select m; foreach(var m1 in temp)//这 ...
- JavaSE(下)
11.抽象的(abstract)方法是否同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized? 都不能. 抽象方法需要子类重写,而静态的方法是无法被 ...
- NOIP模拟测试9
又考崩了咕咕咕... T1:随 好题标记 前置芝士: 原根:质数P的原根g满足1<=rt<P,且rt的1次方,2次方…(P-1)次方在模P意义下可以取遍1到(P-1)的所有整数. ...
- 使用Typescript重构axios(十七)——增加axios.create接口
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 爬虫学习--Urllib库基本使用 Day1
一.Urllib库详解 1.什么是Urllib Python内置的HTTP请求库 urllib.request 请求模块(模拟实现传入网址访问) urllib.error ...
- 百度艾尼(ERNIE)常见问题汇总及解答
一.ERNIE安装配置类问题 Q1:最适合ERNIE2.0的PaddlePaddle版本是?A1:PaddlePaddle版本建议升级到1.5.0及以上版本. Q2:ERNIE可以在哪些系统上使用?A ...
- 使用requests实现人人网登录,并做cookie维持
import requests import re,time s = requests.Session() def doLogin(): login_url = 'http://www.renren. ...