V4L2读取摄像头资源

news2025/4/4 16:37:26

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;//30fps
    
    if (0 > ioctl(v4l2_fd, VIDIOC_S_PARM, &streamparm))
    {    //设置参数
        fprintf(stderr, "ioctl error: VIDIOC_S_PARM: %s\n", strerror(errno));
        return -1;
    }
}
else
    fprintf(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.coloradmin.cn/o/1847078.html

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

相关文章

飞速(FS)S5850-24XMG多速率交换机如何实现降本增速

在当今网络环境快速发展的背景下&#xff0c;以太网带宽呈现出快速增长的趋势&#xff0c;降低网络迭代成本成为影响企业决策的关键因素。飞速&#xff08;FS&#xff09;S5850-24XMG多速率交换机可提供无缝连接不同数据速率设备的解决方案&#xff0c;本文将探讨飞速&#xff…

day01-Numpy的安装

numpy的安装 同样&#xff0c;anaconda内置有Numpy包 Numpy是用c语言实现的&#xff0c;运算速度比python快得多 import numpy as np np.__version__out: 1.18.5使用Jupyter编辑器打印numpy包的版本 NumPy ndarray对象 NumPy定义了一个n维数组对象&#xff0c;简称ndarra…

vue 登录

1.创建项目 Set-ExecutionPolicy RemoteSigned npm install -g yarn yarn add axios yarn add element-pluspackage.json {"name": "tom6","version": "0.1.0","private": true,"scripts": {"serve": &…

乾元通渠道商中标金昌市自然灾害应急能力提升项目

近日&#xff0c;乾元通渠道商中标甘肃省金昌市自然灾害应急能力提升项目&#xff0c;乾元通作为设备厂家&#xff0c;为项目提供通信指挥类装备&#xff08;多链路聚合设备&#xff09; QYT-X1 。 随着万亿国债项目的全面铺开&#xff0c; 青岛乾元通数码科技有限公司 作为国家…

Databend 开源周报第 149 期

Databend 是一款现代云数仓。专为弹性和高效设计&#xff0c;为您的大规模分析需求保驾护航。自由且开源。即刻体验云服务&#xff1a;https://app.databend.cn 。 Whats On In Databend 探索 Databend 本周新进展&#xff0c;遇到更贴近你心意的 Databend 。 支持递归公共表…

2024 Testing Expo China – Automotive I 风丘与您相约上海世博馆

2024汽车测试及质量监控博览会&#xff08;中国&#xff09;——&#xff08;Testing Expo China – Automotive&#xff09;是面向整车、零部件和系统开发的各种技术和服务的盛会&#xff0c;展示了汽车测试、开发和验证技术的各个方面&#xff0c;每年在上海举行&#xff0c;…

使用Scala爬取安居客房产信息并存入CSV文件

使用Scala爬取安居客房产信息并存入CSV文件 本篇博客中&#xff0c;我们将介绍如何使用Scala语言编写一个简单的程序&#xff0c;来爬取安居客&#xff08;Anjuke&#xff09;网站上的房产信息&#xff0c;并将这些信息存储到CSV文件中。这个示例将涵盖HTTP请求、HTML解析、数…

Elasticsearch-高CPU优化

ES 高CPU会导致&#xff1a; 吞吐量下降查询响应时间增加慢查询数增加 谁占用了CPU us&#xff1a;user time&#xff0c;表示 CPU 执行用户进程的时间。&#xff08;各种逻辑运算&#xff0c;函数&#xff0c;排序&#xff0c;复杂相关性计算&#xff0c;密集数据插入等等&am…

CTF-pwn-虚拟化-qemu前置知识

文章目录 参考地址相关交互相关配置相关调试待完善&#xff08;以后做题用到啥再加吧&#xff09; 参考 https://xz.aliyun.com/t/6562?time__1311n4%2bxnD0DRDBAiGkDgiDlhjmYh2xuCllx7whD&alichlgrefhttps://www.bing.com/#toc-3 地址相关 每个qemu虚拟机都是宿主机上…

springboot3 连接 oceanbase + logproxy数据同步到redis

我这用的是 社区版的 单机&#xff0c; rocky liunx 安装oceanbase 注意事项&#xff1a; logproxy 是 CDC 模式 &#xff0c; springboot 可以直接订阅 canal 是 binlog模式&#xff0c; canal 订阅 logproxy&#xff0c; springboot 订阅 canal logproxy 也可以转 bi…

学校教育为什么要选择SOLIDWORKS教育版?

在数字化和智能化时代&#xff0c;学校教育正面临着挑战与机遇。为了培养具备创新能力和实践技能的新时代人才&#xff0c;学校教育需要引入先进的教学工具和资源。SOLIDWORKS教育版作为一款专为教育和培训目的而设计的软件&#xff0c;以其全方面的功能、友好的用户界面、丰富…

在自托管基础设施上使用 GitOps 部署 MinIO

基于MinIO Weaviate Python GitOps探索的见解&#xff0c;本文探讨了如何增强软件部署流程的自动化。 通过将 GitHub Actions 与 Docker Swarm 集成而产生的协同作用&#xff0c;以自托管基础架构的稳健性为基础&#xff0c;标志着 CI/CD 实践的关键进步。这种方法不仅利用了软…

索尼MXF文件断电变2G恢复方法(PXW-Z280V)

PXM-Z280V算是索尼比较经典的机型&#xff0c;也是使用MXF文件格式的机型之一。近期接到很多例索尼MXF量突然不正常的案例&#xff08;如变成512字节或者2G&#xff09;&#xff0c;下面来看下这个案例。 故障存储: 128G存储卡 /文件系统&#xff1a;exFAT 故障现象: 客户反…

《数据结构与算法基础》——1.2基本概念和术语

一、本章结构 二、四个数据相关专业名词的解释 两者的区别 三、数据结构相关内容 四、逻辑结构的分类 五、存储结构的分类及四种基本存储结构 六、数据类型和抽象数据类型

跑通并使用Yolo v5的源代码并进行训练—目标检测

跑通并使用Yolo v5的源代码并进行训练 摘要&#xff1a;yolo作为目标检测计算机视觉领域的核心网络模型&#xff0c;虽然到24年已经出到了v10的版本&#xff0c;但也很有必要对之前的核心版本v5版本进行进一步的学习。在学习yolo v5的时候因为缺少论文所以要从源代码入手来体验…

JavaScript的学习之旅之基本数据类型

目录 一、字面量&#xff08;常量&#xff09;和变量 二、标识符 三、数据类型 1.String类型 2.Number类型 四、布尔值类型 五、Null和Undefined类型 一、字面量&#xff08;常量&#xff09;和变量 字面量&#xff1a;不可变的数据&#xff0c;一般位于等式的右边 变量&…

注册安全分析报告:PingPong

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞 …

深度剖析现阶段的多模态大模型做不了医疗

导读 在人工智能的这波浪潮中&#xff0c;以ChatGPT为首的大语言模型&#xff08;LLM&#xff09;不仅在自然语言处理&#xff08;NLP&#xff09;领域掀起了一场技术革命&#xff0c;更是在计算机视觉&#xff08;CV&#xff09;乃至多模态领域展现出了令人瞩目的潜力。 这些…

芯片制作流程

1、系统需求-》设计-》光罩-》芯片制造-》检测-》封装-》测试。 光罩-》光阻涂布-》曝光-》显影和烘烤-》刻蚀-》等离子体去胶-》湿法刻蚀 化学机械研磨-》薄膜沉积-》制作金属薄膜-》化学气相沉积-》离子注入

探索序列到序列模型:了解编码器和解码器架构的强大功能

目录 一、说明 二、什么是顺序数据&#xff1f; 三、编码器解码器架构的高级概述&#xff1a; 3.1 编码器和解码器架构的简要概述&#xff1a; 3.2 训练机制&#xff1a;编码器和解码器架构中的前向和后向传播&#xff1a; 四、编码器解码器架构的改进&#xff1a; 4.1.…