V4L2读取摄像头资源

1.V4L2

它是Linux内核中标准的关于视频驱动程序,Video for Linux 2,简称V4L2。

它为Linux下的视频驱动提供了统一的接口,使得应用程序可以使用统一的API操作不同的视频设备。

V4L2支持三类设备:视频输入输出设备VBI设备radio设备,分别会在/dev目录下产生video*、radio*和vbi设备节点。应用程序通过对 videoX 设备文件进行 I/O 操作来配置、使用设备类设备。

2.整体流程

3.V4L2读取摄像头流程

从流程图中可以看到,几乎对摄像头的所有操作都是通过 ioctl() 来完成,搭配不同的 V4L2 指令( request 参数)请求不同的操作,这些指令定义在头文件 linux/videodev2.h 中,在摄像头应用程序代码中,需要包含 头文件 linux/videodev2.h,它 提供了很多ioctl宏来和应用层交互。

每一个不同的指令宏就表示向设备请求不同的操作,调用 ioctl()时需要传入的第三个参数的类型;调用 ioctl()前,定义一个该类型变量,调用 ioctl()时、将变量的指针作为 ioctl()的第三个参数传入
###define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability)struct v4l2_capability cap;
……
ioctl(fd, VIDIOC_QUERYCAP, &cap);

下面列出来一些比较常用的:

在进行V4L2开发中,常用的命令标识符如下:
(1) VIDIOC_REQBUFS:  分配内存;
(2) VIDIOC_QUERYBUF: 把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址;
(3) VIDIOC_QUERYCAP: 查询驱动功能;
(4) VIDIOC_ENUM_FMT: 获取当前驱动支持的视频格式;
(5) VIDIOC_S_FMT:    设置当前驱动的视频捕获格式;
(6) VIDIOC_G_FMT:    读取当前驱动的视频捕获格式;
(7) VIDIOC_TRY_FMT:  验证当前驱动的显示格式;
(8) VIDIOC_CROPCAP:  查询驱动的修剪功能;
(9) VIDIOC_S_CROP:   设置视频信号的边框;
(10)VIDIOC_G_CROP:   读取视频信号的边框;
(11)VIDIOC_QBUF:     把数据从缓存中读取出来;
(12)VIDIOC_DQBUF:    把数据放回缓存队列;
(13)VIDIOC_STREAMON: 开始视频显示函数;
(14)VIDIOC_STREAMOFF:结束视频显示函数;
(15)VIDIOC_QUERYSTD: 检查当前视频设备支持的标准,例如PAL或NTSC;

3.1 打开视频文件设备

  • 视频类设备对应的设备节点为/dev/videoX, X 为数字编号,通常从 0 开始 ,使用open打开节点, 应用程序能够使用阻塞模式非阻塞模式打开视频设备,如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。
  • //阻塞模式
    fd = open("/dev/video0", O_RDWR);
    //非阻塞模式
    fd = open("/dev/video0", O_RDWR | O_NOBLOCK);if (0 > fd) {
    fprintf(stderr, "open error: %s: %s\n", "/dev/video0", strerror(errno));
    return -1;
    }
    

3.2  查询属性、功能

  • 查询设备的属性, 使用的指令为 VIDIOC_QUERYCAP,需要传入一个表示属性的结构体
  • /* 查询设备功能 */
    struct v4l2_capability vcap;
    ioctl(fd, VIDIOC_QUERYCAP, &vcap);/* 判断是否是视频采集设备 */
    /*capabilities字段必须包含 V4L2_CAP_VIDEO_CAPTURE,表示它支持视频采集功能*/
    if (!(V4L2_CAP_VIDEO_CAPTURE & vcap.capabilities)) {
    fprintf(stderr, "Error: No capture video device!\n");
    return -1;
    }
    

3.3设置设备参数

  • 在设置格式之前,要先枚举出所有的格式,看一看是否支持要设置的格式,然后再进一步设置 。
  • a)枚举出摄像头支持的所有像素格式:VIDIOC_ENUM_FMT

ioctl(int fd, VIDIOC_ENUM_FMT, struct v4l2_fmtdesc *fmtdesc);

/* 枚举出摄像头所支持的所有像素格式以及描述信息 */
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while (0 == ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc)) {
printf("fmt: %s <0x%x>\n", fmtdesc.description, fmtdesc.pixelformat);
fmtdesc.index++;
}
  • b)枚举出摄像头支持的所有像素格式:VIDIOC_ENUM_FMT
ioctl(int fd, VIDIOC_ENUM_FRAMESIZES, struct v4l2_frmsizeenum *frmsize);
struct v4l2_frmsizeenum frmsize;
frmsize.index = 0;
frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
frmsize.pixel_format = V4L2_PIX_FMT_RGB565;
while (0 == ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize)) {
printf("frame_size<%d*%d>\n", frmsize.discrete.width, frmsize.discrete.height);
frmsize.index++;
}
  • c)枚举摄像头所支持的所有视频采集帧率:VIDIOC_ENUM_FRAMEINTERVALS

同理,略

d)设置当前的格式:VIDIOC_S_FMT 像素格式、视频帧大小以及视频采集帧率
int ioctl(int fd, VIDIOC_G_FMT, struct v4l2_format *fmt);//查看get,像素格式、视频帧大小
int ioctl(int fd, VIDIOC_S_FMT, struct v4l2_format *fmt);//设置set,像素格式、视频帧大小
/*使用摄像头设备时,type设置成V4L2_BUF_TYPE_VIDEO_CAPTURE ,使用struct v4l2_pix_format来描述摄像头属性*/
struct v4l2_format fmt
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = 800;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565;
if (0 > ioctl(fd, VIDIOC_S_FMT, &fmt)) { //设置格式perror("ioctl error");return -1;
}

ioctl(int fd, VIDIOC_G_PARM, struct v4l2_streamparm *streamparm);//设置帧率
struct v4l2_streamparm streamparm;streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(v4l2_fd, VIDIOC_G_PARM, &streamparm);/** 判断是否支持帧率设置 **/
if (V4L2_CAP_TIMEPERFRAME & streamparm.parm.capture.capability) {streamparm.parm.capture.timeperframe.numerator = 1;streamparm.parm.capture.timeperframe.denominator = 30;//30fpsif (0 > ioctl(v4l2_fd, VIDIOC_S_PARM, &streamparm)){    //设置参数fprintf(stderr, "ioctl error: VIDIOC_S_PARM: %s\n", strerror(errno));return -1;}
}
elsefprintf(stderr, "不支持帧率设置");

3.4申请帧缓存

读取摄像头数据的方式有两种,一种是 read 方式(对应设备功能返回的 V4L2_CAP_READWRITE );另一种则是 streaming 方式 (使用mmap,对应设备功能返回的 V4L2_CAP_STREAMING )

我们需要将设备申请帧缓冲,并将帧缓冲映射到应用程序的进程地址空间中。

ioctl(int fd, VIDIOC_REQBUFS, struct v4l2_requestbuffers *reqbuf);//申请缓冲帧
struct v4l2_requestbuffers reqbuf;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.count = 3; // 申请 3 个帧缓冲
reqbuf.memory = V4L2_MEMORY_MMAP;
if (0 > ioctl(fd, VIDIOC_REQBUFS, &reqbuf)) {
fprintf(stderr, "ioctl error: VIDIOC_REQBUFS: %s\n", strerror(errno));
return -1;
}

使用 VIDIOC_REQBUFS 指令申请帧缓冲,该缓冲区实质上是由内核所维护的, 应用程序不能直接读取该缓冲区的数据 ,我们需要将其映射到用户空间中,这样,应用程序读取映射区的数据实际上就是读取内核维护的帧缓冲中的数据。
/* 建立内存映射 */
struct v4l2_buffer buf
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
for (buf.index = 0; buf.index < 3; buf.index++) {ioctl(fd, VIDIOC_QUERYBUF, &buf);//查看帧缓冲信息frm_base[buf.index] = mmap(NULL, buf.length,PROT_READ | PROT_WRITE, MAP_SHARED,fd, buf.m.offset);if (MAP_FAILED == frm_base[buf.index]) {perror("mmap error");return -1;}
}

3.5入队,开始采集

使用 VIDIOC_QBUF 指令将帧缓冲放入到内核的帧缓冲队列,将三个帧缓冲放入内核的帧缓冲队列(入队操作)中:
struct v4l2_buffer buf;
/* 入队操作 */
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;/*入队前需先设置 struct v4l2_buffer 类型对象的 memory、type 字段*/
for (buf.index = 0; buf.index < 3; buf.index++) {if (0 > ioctl(fd, VIDIOC_QBUF, &buf)) {perror("ioctl error");return -1;}
}

开始采集:

ioctl(int fd, VIDIOC_STREAMON, int *type); //开启视频采集
ioctl(int fd, VIDIOC_STREAMOFF, int *type); //停止视频采集enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (0 > ioctl(fd, VIDIOC_STREAMON, &type)) {perror("ioctl error");return -1;
}

3.6出队

边采集边出队

struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
for ( ; ; ) {for(buf.index = 0; buf.index < 3; buf.index++) {ioctl(fd, VIDIOC_DQBUF, &buf); //出队// 读取帧缓冲的映射区、获取一帧数据// 处理这一帧数据do_something();// 数据处理完之后、将当前帧缓冲入队、接着读取下一帧数据ioctl(fd, VIDIOC_QBUF, &buf);}
}

帧缓冲出队之后,接下来便可读取数据了,然后对数据进行处理, 比如对数据进行转化,如RGB888转RGB565,将转换后的数据刷到FrameBuffer上进行显示。处理完后再入队继续采集。

3.7关闭采集

如果要结束视频采集,使用 VIDIOC_STREAMOFF 指令:
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (0 > ioctl(fd, VIDIOC_STREAMOFF, &type)) {perror("ioctl error");return -1;
}

3.8 摄像头采集到的图像数据显示到开发板 LCD 屏上

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

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

相关文章

LeetCode---402周赛

题目列表 3184. 构成整天的下标对数目 I 3185. 构成整天的下标对数目 II 3186. 施咒的最大总伤害 3187. 数组中的峰值 一、构成整天的下标对数目 I & II 可以直接二重for循环暴力遍历出所有的下标对&#xff0c;然后统计符合条件的下标对数目返回。代码如下 class So…

概率论与数理统计期末复习

概率论常考知识点汇总 总括 1. 基础概率论 概率定义&#xff1a;理解概率是事件发生的可能性度量&#xff0c;范围从0&#xff08;不可能&#xff09;到1&#xff08;必然发生&#xff09;。概率公理&#xff1a;掌握概率的三大公理&#xff0c;即非负性、规范性和可加性。条…

HTML静态网页成品作业(HTML+CSS)——美食火锅介绍网页(1个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有1个页面。 二、作品演示 三、代…

微信对话生成器2.0版本

微信对话生成器2.0版&#xff0c;这是一款革命性的通讯辅助工具&#xff0c;在数字通信领域带来了新的创新浪潮。这一升级版的生成器不仅囊括了从基本的文字编辑、格式调整到语音转换的多种功能&#xff0c;更重要的是&#xff0c;它提供了模拟真实对话的能力&#xff0c;使得用…

容器之对齐构件

代码&#xff1a; #include <gtk-2.0/gtk/gtk.h> #include <glib-2.0/glib.h> #include <gtk-2.0/gdk/gdkkeysyms.h> #include <stdio.h>int main(int argc, char *argv[]) {gtk_init(&argc, &argv);GtkWidget *window;window gtk_window_ne…

C++ 72 之 友元和类模版

#define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std; #include <string>// 写法2&#xff1a; // template<class T1, class T2> // class Students12;// 要提前用到Students12&#xff0c;需要在前面先让编译器见过Students12才可…

汇聚荣做拼多多运营口碑怎么样?

拼多多作为国内领先的电商平台&#xff0c;其运营口碑一直是业界和消费者关注的焦点。汇聚荣作为拼多多的运营服务商&#xff0c;其服务质量直接影响到拼多多平台的用户体验和品牌形象。那么&#xff0c;汇聚荣做拼多多运营口碑怎么样呢? 一、服务响应速度 汇聚荣在服务响应速…

树莓派4B学习笔记11:PC端网线SSH连接树莓派_网线连接请求超时问题解决

今日继续学习树莓派4B 4G&#xff1a;&#xff08;Raspberry Pi&#xff0c;简称RPi或RasPi&#xff09; 本人所用树莓派4B 装载的系统与版本如下: 版本可用命令 (lsb_release -a) 查询: Opencv 版本是4.5.1&#xff1a; 今日学习使用网线连接树莓派&#xff0c;网线可以提供更…

邮件推送服务商有哪些核心功能?怎么选择?

邮件推送服务商支持哪些营销工具&#xff1f;推送性能如何评估&#xff1f; 邮件推送服务商的核心功能可以帮助企业更高效地管理和优化其电子邮件营销活动&#xff0c;从而提升客户参与度和转化率。AokSend将详细介绍邮件推送服务商的一些核心功能。 邮件推送服务商&#xff…

弹窗‘xlive.dll没有被指定在Windows’要怎么解决?教你4种修复xlive.dll的方法

大家在使用电脑期间是否曾遭遇过一个弹窗警告&#xff0c;“xlive.dll没有被指定在Windows”&#xff1f;假如你确实碰到过这样的问题&#xff0c;当时你是如何应对xlive.dll文件缺失的状况呢&#xff1f;对于那些还不清楚如何处理此问题的朋友们&#xff0c;接下来所述的几种方…

用Python的Pygame包实现水果忍者小游戏

先上一下运行结果 长按鼠标左键出刀, 切割水果几分, 切割炸弹结束游戏, 漏掉的水果也会几分, 难度会随时间慢慢提高(水果的刷新频率变快) 初始化 帧率200帧/秒, 游戏窗口大小800600 # 游戏设置 pygame.init() FPS 200 fpsClock pygame.time.Clock() WIDTH, HEIGHT 800, 60…

【FPGA】静态分析与时序约束(持续更新

Reference&#xff1a; V2静态时序分析与时序约束文档 入门 无时序约束场景中&#xff0c;普通图像显示不清晰&#xff0c;千兆网口接收Ethernet package 数据不正常&#xff0c;红外场景中图像显示不正常 Definition&#xff1a; 我们提出一些特定的时序要求&#xff08;或…

文章MSM_metagenomics(七):分组马赛克图

欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 介绍 本教程是使用一个Python脚本来绘制马赛克图&#xff0c;用于可视化两个变量的频率分布。 数…

我的Mac疯了!居然可以生成这样的奇葩AI图片!

在当今人工智能领域&#xff0c;midjourney无疑是生成图片的王者&#xff0c;但是苦于付费才能使用&#xff0c;今天我就给大家分享一下midjourney平替stable diffusion&#xff0c;实现本地生成不逊色于midjourney的图片 效果图 先上一个我自己生成的效果(就是在我的Mac上用C…

【anaconda】本地永久设置镜像源

【anaconda】本地永久设置镜像源 可以通过命令行设置全局的 pip 配置&#xff1a; pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

python字符串的一些操作实例

已知字符串 a “aAsomr3idd4HGHbigs7Dlsf9YeAF”&#xff0c;要求如下 1. 请将a字符串的大写改为小写&#xff0c;小写改为大写。 2.将a字符串的数字取出&#xff0c;并输出成一个新的字符串。 3.将a字符串中的内容反向输出 4.打印a字符串中所有奇数位上的字符(下标是1&#x…

【已解决】手机进入fastboot无法退出

文章目录 报错及效果图报错代码效果图 解决方案必要的解决方法可能有用的解决方法 报错及效果图 报错代码 手机屏幕显示fastboot&#xff0c;长按电源键无法正常启动 效果图 解决方案 必要的解决方法 1.在电脑上下载并安装adb/fastboot驱动&#xff0c;可以在这里免费下载&…

【机器学习300问】129、RNN如何在情感分析任务中起作用的?

情感分析是自然语言处理&#xff08;NLP&#xff09;领域的一个重要分支&#xff0c;它的目标是自动检测和提取出非结构化文本数据中的主观信息&#xff08;比如&#xff1a;情绪、意见、评价等&#xff09; 一、情感分析任务案例 分析电商产品评论的情感倾向&#xff08;三分类…

MySQL之复制(九)

复制 复制管理和维护 确定主备是否一致 在理想情况下&#xff0c;备库和主库的数据应该是完全一样的。但事实上备库可能发生错误并导致数据不一致。即使没有明显的错误&#xff0c;备库同样可能因为MySQL自身的特性导致数据不一致&#xff0c;例如MySQL的Bug、网络中断、服务…

数据资产在供应链管理中担当核心角色:利用数据驱动,显著提升运营效率,有效降低潜在风险,实现决策优化,为企业的可持续发展奠定坚实基础

一、引言 在当今全球化和数字化的时代&#xff0c;供应链管理已成为企业竞争力的关键要素之一。随着信息技术的高速发展&#xff0c;数据资产在供应链管理中扮演着越来越重要的角色。通过有效地利用数据资产&#xff0c;企业能够显著提升运营效率&#xff0c;降低潜在风险&…