v4l2子系统学习(一)V4L2应用程序编程

文章目录

  • 1、声明
  • 2、前言
  • 3、数据采集流程
    • 3.1、buffer的管理
    • 3.2、完整的使用流程
  • 4、应用程序编写
  • 5、测试

1、声明

本文是在学习韦东山《驱动大全》V4L2子系统时,为梳理知识点和自己回看而记录,全部内容高度复制粘贴。

韦老师的《驱动大全》:商品详情

其对应的讲义资料:https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git

2、前言

本章只从应用的角度去介绍如何使用v4l2的接口来获取图像。在v4l2应用编程中,主要都是通过ioctl命令来完成一系列任务,如查询设备能力使用VIDIOC_QUERYCAP,申请buffer使用VIDIOC_REQBUFS等等。

3、数据采集流程

3.1、buffer的管理

使用摄像头时,核心是"获得数据"。所以先讲如何获取数据,即如何得到buffer。

摄像头采集数据时,是一帧又一帧地连续采集。所以需要申请若干个buffer,驱动程序把数据放入buffer,APP从buffer得到数据。这些buffer可以使用链表来管理。

驱动程序周而复始地做如下事情:

  • 从硬件采集到数据。
  • 把"空闲链表"取出buffer,把数据存入buffer。
  • 把含有数据的buffer放入"完成链表"。

APP也会周而复始地做如下事情:

  • 监测"完成链表",等待它含有buffer。
  • 从"完成链表"中取出buffer。
  • 处理数据。
  • 把buffer放入"空闲链表"

链表操作示意图如下:

3.2、完整的使用流程

下面列出一个获取图像的完成流程:

  • open:打开设备节点/dev/videoX。
  • ioctl VIDIOC_QUERYCAP:查询能力,比如
    • 确认它是否是"捕获设备",因为有些节点是输出设备。
    • 确认它是否支持mmap操作,还是仅支持read/write操作。
  • ioctl VIDIOC_ENUM_FMT:枚举所支持的图像格式。
  • ioctl VIDIOC_S_FMT:在上面枚举出来的格式里,选择一个来设置格式。
  • ioctl VIDIOC_REQBUFS:通知驱动程序申请buffer,APP中可以表明需要申请多少个buffer,但驱动程序不一定能申请到。
  • ioctl VIDIOC_QUERYBUF和mmap:查询驱动程序中所申请到的buffer的信息,并在用户空间进行映射。
    • 如果申请到了N个buffer,这个ioctl就应该执行N次。
    • 执行mmap后,APP就可以直接读写这些buffer。
  • ioctl VIDIOC_QBUF:通知驱动程序,把buffer放入"空闲链表"。
    • 如果申请到了N个buffer,这个ioctl就应该执行N次。
  • ioctl VIDIOC_STREAMON:启动摄像头。这里是一个循环,使用poll/select监测buffer,然后从"完成链表"中取出buffer,处理后再放入"空闲链表"
    • poll/select
    • ioctl VIDIOC_DQBUF:从"完成链表"中取出buffer。
    • 处理:前面使用mmap映射了每个buffer的地址,处理时就可以直接使用地址来访问buffer。
    • ioclt VIDIOC_QBUF:把buffer放入"空闲链表"。
  • ioctl VIDIOC_STREAMOFF:停止摄像头。

4、应用程序编写

/* v4l2_test.c */#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <linux/types.h>          /* for videodev2.h */
#include <linux/videodev2.h>
#include <poll.h>
#include <sys/mman.h>int main(int argc, char **argv)
{int fd;struct v4l2_fmtdesc fmtdesc;struct v4l2_frmsizeenum fsenum;int fmt_index = 0;int frame_index = 0;void *bufs[32];int buf_cnt;struct pollfd fds[1];int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;char filename[32];int file_cnt = 0;int i;if(argc != 2){printf("Usage : %s </dev/videoX>\n", argv[0]);return -1;}/* 1、打开vedio设备节点 */fd = open(argv[1], O_RDWR);if (fd < 0){printf("can not open %s\n", argv[1]);return -1;}/* 2、查询能力 */ struct v4l2_capability cap;memset(&cap, 0, sizeof(struct v4l2_capability));if (0 == ioctl(fd, VIDIOC_QUERYCAP, &cap)){if((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {fprintf(stderr, "Error opening device %s: video capture not supported.\n",argv[1]);return -1;}if((cap.capabilities & V4L2_CAP_STREAMING) == 0) {fprintf(stderr, "%s does not support streaming i/o\n", argv[1]);return -1;}}else{printf("can not get capability\n");return -1;}while(1){/* 3、枚举格式 */fmtdesc.index = fmt_index;	// 从0开始枚举fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;if(0 != ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))break;frame_index = 0;printf("format %s,%d\n", fmtdesc.description, fmtdesc.pixelformat);while(1){/* 4、枚举这种格式所支持的帧大小 */memset(&fsenum, 0, sizeof(struct v4l2_frmsizeenum));fsenum.pixel_format = fmtdesc.pixelformat;fsenum.index = frame_index;if (ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &fsenum) == 0){printf("\tframesize %d: %d x %d\n", frame_index, fsenum.discrete.width, fsenum.discrete.height);}else{break;}frame_index++;}fmt_index++;}/* 5、设置格式 */struct v4l2_format fmt;memset(&fmt, 0, sizeof(struct v4l2_format));fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;fmt.fmt.pix.width = 1280;fmt.fmt.pix.height = 720;fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;fmt.fmt.pix.field = V4L2_FIELD_ANY;if (0 == ioctl(fd, VIDIOC_S_FMT, &fmt)){printf("set format ok: %d x %d\n", fmt.fmt.pix.width, fmt.fmt.pix.height);}else{printf("can not set format\n");return -1;}/* 6、申请buffer */struct v4l2_requestbuffers rb;memset(&rb, 0, sizeof(struct v4l2_requestbuffers));rb.count = 32;rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;rb.memory = V4L2_MEMORY_MMAP;if (0 == ioctl(fd, VIDIOC_REQBUFS, &rb))	// 向驱动程序申请32个buffer,只是申请,不一定成功{/* 7、申请完成后,mmap这些buffer */buf_cnt = rb.count;for (i = 0; i < rb.count; i++) 			// 枚举这32个buffer{struct v4l2_buffer buf;memset(&buf, 0, sizeof(struct v4l2_buffer));buf.index = i;buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;if (0 == ioctl(fd, VIDIOC_QUERYBUF, &buf))	// 查询第n个buffer的信息{bufs[i] = mmap(0, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);	// 使用mmap映射到用户空间if(bufs[i] == MAP_FAILED) 				// 映射失败{perror("Unable to map buffer");return -1;}}else{printf("can not query buffer\n");return -1;}            }printf("map %d buffers ok\n", buf_cnt);}else{printf("can not request buffers\n");return -1;}/* 8、把所有buffer放入空闲链表 */for (i = 0; i < buf_cnt; ++i) {struct v4l2_buffer buf;memset(&buf, 0, sizeof(struct v4l2_buffer));buf.index = i;buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;if (0 != ioctl(fd, VIDIOC_QBUF, &buf))	// 这里只是通知驱动程序,把buffer放入空闲链表。这里的buffer是驱动程序里的。{perror("Unable to queue buffer");return -1;}}printf("queue buffers ok\n");/* 9、启动摄像头 */if (0 != ioctl(fd, VIDIOC_STREAMON, &type)){perror("Unable to start capture");return -1;}printf("start capture ok\n");while (1){/* 10、使用poll监听是否有buffer可以取出 */memset(fds, 0, sizeof(fds));fds[0].fd = fd;fds[0].events = POLLIN;if (poll(fds, 1, -1) > 0){/* 11、把buffer取出队列 */struct v4l2_buffer buf;memset(&buf, 0, sizeof(struct v4l2_buffer));buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP;if (0 != ioctl(fd, VIDIOC_DQBUF, &buf))		// 这里只是通知驱动程序,把buffer从完成链表中取出。这里的buffer是驱动程序里的。{perror("Unable to dequeue buffer");return -1;}/* 12、把buffer的数据存为文件 */sprintf(filename, "video_raw_data_%04d.jpg", file_cnt++);int fd_file = open(filename, O_RDWR | O_CREAT, 0666);if (fd_file < 0){printf("can not create file : %s\n", filename);}printf("capture to %s\n", filename);write(fd_file, bufs[buf.index], buf.bytesused);	// 前面已经对驱动程序里申请的buffer进行了mmap,所以这里将用户空间的buffer写入文件中close(fd_file);/* 13、重新把buffer放入空闲队列 */if (0 != ioctl(fd, VIDIOC_QBUF, &buf)){perror("Unable to queue buffer");return -1;}}}if (0 != ioctl(fd, VIDIOC_STREAMOFF, &type)){perror("Unable to stop capture");return -1;}printf("stop capture ok\n");close(fd);return 0;
}

5、测试

编译应用程序,插入usb摄像头,执行应用程序:

# 1、编译应用程序
gcc -o v4l2_test v4l2_test.c# 2、插入摄像头# 3、执行应用程序
./v4l2_test /dev/video10

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/21026.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NAC网络接入控制三种认证方式802.1X认证、MAC认证和Portal认证

NAC网络接入控制三种认证方式802.1X认证、MAC认证和Portal认证 1.NAC简介2.802.1X认证3. MAC认证4. Portal认证 1.NAC简介 NAC&#xff08;Network Access Control&#xff09;称为网络接入控制&#xff0c;通过对接入网络的客户端和用户的认证保证网络的安全&#xff0c;是一…

vscode远程报错:Remote host key has changed,...

重装了Ubuntu系统之后&#xff0c;由20.04改为22.04&#xff0c;再用vscode远程&#xff0c;就出现了以上报错。 亲测有效的办法 gedit ~/.ssh/known_hosts 打开这个配置文件 删掉与之匹配的那一行&#xff0c;不知道删哪一行的话&#xff0c;就打开第一行这个 /.ssh/confi…

多个 JDK 版本(Java 8、Java 17、Java 21)下载和切换

文章目录 多个 JDK 版本&#xff08;Java 8、Java 17、Java 21&#xff09;下载和切换1. 下载 JDK2. 配置环境变量3. JDK 版本切换4. 测试5. 在 IDEA 中切换 JDK注意&#xff1a; 多个 JDK 版本&#xff08;Java 8、Java 17、Java 21&#xff09;下载和切换 随着 Spring Boot …

深度解析:使用 Headless 模式 ChromeDriver 进行无界面浏览器操作

一、问题背景&#xff08;传统爬虫的痛点&#xff09; 数据采集是现代网络爬虫技术的核心任务之一。然而&#xff0c;传统爬虫面临多重挑战&#xff0c;主要包括&#xff1a; 反爬机制&#xff1a;许多网站通过检测请求头、IP地址、Cookie等信息识别爬虫&#xff0c;进而限制…

【Vue+python】Vue调用python-fastApi接口实现数据(数值、列表类型数据)渲染

前言&#xff1a;之前做的一直都是SpringBootVue的应用&#xff0c;但现在需要实现一个能将python实现的算法应用展示在前端的界面。想法是直接Vue调用python-fastApi接口实现数据渲染~ 文章目录 1. 变量定义2. axios调用python3. 跨域问题解决4. 数据渲染4.1 数值数据渲染4.2 …

SOME/IP--协议英文原文讲解8

前言 SOME/IP协议越来越多的用于汽车电子行业中&#xff0c;关于协议详细完全的中文资料却没有&#xff0c;所以我将结合工作经验并对照英文原版协议做一系列的文章。基本分三大块&#xff1a; 1. SOME/IP协议讲解 2. SOME/IP-SD协议讲解 3. python/C举例调试讲解 4.2 Speci…

禁止WPS强制打开PDF文件

原文网址&#xff1a;禁止WPS强制打开PDF文件_IT利刃出鞘的博客-CSDN博客 简介 本文介绍如何避免WPS强制打开PDF文件。 方法 1.删除注册表里.pdf的WPS绑定 WinR&#xff0c;输入&#xff1a;regedit&#xff0c;回车。找到&#xff1a;HKEY_CLASSES_ROOT\.pdf删除KWPS.PDF…

Pytorch深度学习教程_3_初识pytorch

欢迎来到《PyTorch深度学习教程》系列的第三篇&#xff01;在前面的两篇中&#xff0c;我们已经介绍了Python及numpy的基本使用。今天&#xff0c;我们将深入探索PyTorch的核心功能&#xff0c;帮助你更好地理解和使用这个强大的深度学习框架。 欢迎订阅专栏&#xff1a; 深度…

Windows桌面系统管理5:Windows 10操作系统注册表

Windows桌面系统管理0&#xff1a;总目录-CSDN博客 Windows桌面系统管理1&#xff1a;计算机硬件组成及组装-CSDN博客 Windows桌面系统管理2&#xff1a;VMware Workstation使用和管理-CSDN博客 Windows桌面系统管理3&#xff1a;Windows 10操作系统部署与使用-CSDN博客 Wi…

web入侵实战分析-常见web攻击类应急处置实验1

场景说明&#xff1a; 某天运维人员发现在/opt/tomcat8/webapps/test/目录下&#xff0c;多出了一个index_bak.jsp这个文件&#xff0c; 并告诉你如下信息 操作系统&#xff1a;ubuntu-16.04业务&#xff1a;测试站点中间件&#xff1a;tomcat开放端口&#xff1a;22&#x…

Bio-ORACLE数据分享[decade 2010-2020] [Surface layers]

Bio-ORACLE数据分享[decade 2010-2020] [Surface layers] 文章目录 Bio-ORACLE数据分享[decade 2010-2020] [Surface layers]前言一、文件分享&#xff08;主要&#xff09;二、相关代码&#xff08;选看&#xff09;总结 Bio-ORACLE数据分享[decade 2010-2020] [Surface layer…

换服务器需要做的工作(记录一下)

1.Nginx开启OCSP 加快Let’s Encrypt免费证书 HTTPS网站访问速度 https://blog.csdn.net/wx23986/article/details/141722669 2.添加伪静态规则 location / {rewrite ^([^\.]*)/topic-(.)\.html$ $1/portal.php?modtopic&topic$2 last;rewrite ^([^\.]*)/article-([0-9…

c++作业

练习题&#xff1a; #include <iostream> #include <cstring> using namespace std;class mystring {char* p;int len; public:mystring();mystring(const char* p);~mystring();void copy(const mystring& str);void append(const mystring& str);void sh…

网络爬虫学习:借助DeepSeek完善爬虫软件,实现模拟鼠标右键点击,将链接另存为本地文件

一、前言 最近几个月里&#xff0c;我一直在学习网络爬虫方面的知识&#xff0c;每有收获都会将所得整理成文发布&#xff0c;不知不觉已经发了7篇日志了&#xff1a; 网络爬虫学习&#xff1a;从百度搜索结果抓取标题、链接、内容&#xff0c;并保存到xlsx文件中 网络爬虫学…

leetcode203.移除链表元素

目录 问题描述示例提示 具体思路思路一思路二 代码实现 问题描述 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 题目链接&#xff1a;移除链表元素 示例 提示 列表中的节点数目在范围…

全球直播新标杆:DeepSeek融合全平台AI无人直播,构建直播流量永动机!

全球直播新标杆&#xff1a;DeepSeek融合全平台AI无人直播&#xff0c;构建直播流量永动机&#xff01; 在科技日新月异的今天&#xff0c;直播行业正经历一场前所未有的变革。在这场变革中&#xff0c;DeepSeek凭借其创新的AI无人直播系统&#xff0c;正逐步树立起全球直播的新…

postgres源码学习之简单sql查询

postgres源码学习之sql查询 sql查询的主流程读取sql解析sql重写sql获得执行计划执行查询操作结果返回 sql查询的主流程 参考postgres的处理流程 由上一节&#xff0c;我们可以看到&#xff0c;当有新的连接通过权限认证之后&#xff0c;将进入等待接收sql语句&#xff0c;并执…

【AI实践】阿里百炼文本对话Agent安卓版搭建

环境&#xff1a;安卓手机运行环境&#xff1b;WinsurfAI编程工具&#xff1b;阿里百炼提前创建Agent应用&#xff1b; 耗时&#xff1a;2小时&#xff1b; 1&#xff0c;新建安卓项目 完成文本输入&#xff0c;并将输入的文字显示出来。 2&#xff0c;安装SDK 参考文档 安…

[论文阅读] SeeSR: Towards Semantics-Aware Real-World Image Super-Resolution

文章目录 一、前言二、主要贡献三、Introduction四、Methodology4.1 Motivation &#xff1a;4.2Framework Overview.** 一、前言 通信作者是香港理工大学 & OPPO研究所的张磊教授&#xff0c;也是图像超分ISR的一个大牛了。 论文如下 SeeSR: Towards Semantics-Aware Rea…

探秘 DeepSeek R1 模型:跨越多领域的科技奇迹,引领智能应用新浪潮

DeepSeek R1 模型功能强大&#xff0c;应用广泛。在自然语言处理、计算机视觉、推荐系统和医疗等领域都能发挥作用。本文介绍了其在各领域的应用场景和代码示例&#xff0c;助你深入了解它。 目录 ​编辑 一、本篇背景&#xff1a; 二、DeepSeek R1 模型概述&#xff1a; …