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 语言的接口设计是非侵入式的,接口编写者无须知 ...
随机推荐
- 【重构】AndroidStudio中代码重构菜单Refactor功能详解
代码重构几乎是每个程序员在软件开发中必须要不断去做的事情,以此来不断提高代码的质量.Android Stido(以下简称AS)以其强大的功能,成为当下Android开发工程师最受欢迎的开发工具,也是A ...
- 在VMware下的Linux中的RAID10校验位算法下的磁盘管理
988年由加利福尼亚大学伯克利分校发表的文章首次提到并定义了RAID,当今CPU性能每年可提升30%-50%但硬盘仅提升7%,渐渐的已经成为计算机整体性能的瓶颈,并且为了避免硬盘的突然损坏导致数据丢失 ...
- 暑期集训20190726 跳动(skip)
[题目描述] 福州三中的操场上有着数不尽的跳动的小朋友. 当然善于思考的你总能从中发掘出不一样的问题 福州三中的跑道是一个n个格子围成的圆形,从0~n-1编号,有m个同学,第i个同学步长为a[i], ...
- [考试反思]0910csp-s模拟测试42:追求
显而易见的暴力骗分. T1想到了bitset但是发现MLE后弃了,部分分都没拿. T2想到正解贪心打暴力过不了大样例弃了. T3牛逼题暴力. 考场没什么大失误,还可以. 不要轻易放弃每一个思路,可能再 ...
- NOIP模拟测试33
这次考试很失败. T1sb题,40分钟切了,当我打完对拍全过去上厕所的时候,碰到了yxm. yxm:我又自闭了,没有一点进展. 我:…… yxm:你会做几个? 我(思考再三):T1只会暴力. (我这么 ...
- Kubernetes4-web管理界面
一.简介 1.环境 环境还是前面的环境 2.Kubernetes Dashboard web界面 kubernetes dashboard (仪表盘)是一个将通用的基于web的监控和操作界面加入kub ...
- python之变量名
在python中,变量不需要提前声明,创建时直接对其赋值即可,变量类型由赋给变量的值决定.值得注意的是,一旦创建了一个变量,就需要给该变量赋值. 变量名应严格遵守以下规则: 1.变量名只能包含:字母/ ...
- 基于docker搭建Jenkins+Gitlab+Harbor+Rancher架构实现CI/CD操作
一.各个组件的功能描述: Docker 是一个开源的应用容器引擎. Jenkis 是一个开源自动化服务器. (1).负责监控gitlab代码.gitlab中配置文件的变动: (2).负责执行镜像文件的 ...
- jvm与程序的生命周期
yls 2019/11/5 java虚拟机结束生命周期的情况: 执行了System.exit(); 程序正常运行结束 程序在执行过程中遇到异常或错误而异常终止 由于操作系统出现错误而导致jvm进程终止 ...
- Docker学习-Spring Boot on Docker
1.创建spring boot项目 https://start.spring.io/ pom.xml文件新增docker支持 <build> <plugins> <plu ...