视频输入设备-V4L2的开发流程简述
一、摄像头的工作原理与应用
基本概念
V4L2的全称是Video For Linux Two,其实指的是V4L的升级版,是linux系统关于视频设备的内核驱动,同时V4L2也包含Linux系统下关于视频以及音频采集的接口,只需要配合对应的视频采集设备就可以实现对视频以及音频进行采集。

Linux下包含V4L2的接口资源(宏定义、枚举、请求码等),这些资源被包含在一个头文件中,头文件名字叫做videodev2.h,头文件路径:/usr/include/linux/videodev2.h,用户需要在程序中使用该头文件 #include <linux/videodev2.h>
在这个头文件的末尾部分有很多关于视频采集的请求码,这些请求码通过一个系统调用中的ioctl()函数,通过发送不同请求码给内核驱动,内核驱动会返回对应的信息。

ioctl函数使用说明
头文件:#include <sys/ioctl.h>
函数原型:int ioctl(int fd, unsigned long request, ...); 变参函数
函数参数
参数一:fd 需要操作的文件的描述符 open函数的返回值
参数二:request 传递给设备驱动的对应请求
.....
返回值 成功 返回0 失败 返回-1
注意:ioctl是专门作为设备输入输出操作的系统调用,需要传入对应设备的命令码,不同的设备会定义不同的命令码

开发流程
Video for Linux Two是一套针对不同类型视频设备及相关数据的关联驱动规范。设备的类型决定了通过read()和write()传递的数据类型,以及驱动支持的ioctl命令集。已经定义或计划定义几种设备类型如下图:

由于需要使用摄像头捕捉画面,所以需要调用open函数打开摄像头,插入摄像头之后Linux系统提供的摄像头的设备节点是 /dev/video7。(每个人插入摄像头之后提供的设备节点可能不一样,需要注意)

以下代码都是对V4L2原码的解读以及注释:
(1) 使用视频采集设备之前需要提前打开设备,利用Linux系统的open函数打开设备文件!

(2)根据用户需求设置摄像头采集画面的格式,利用v4l2提供的struct v4l2_format结构体!
现在市面的摄像头的采集画面的格式有多种,如果购买的摄像头价格比较便宜,则一般采集的画面的格式都是YUV4:2:2格式,YUYV(YUV4:2:2)格式指的是每4个字节代表两个像素点,所以YUYV格式的图像一个像素点大小为2个字节,并且Y和UV交替存储。
YUV是一种常用的颜色编码格式,主要用在电视系统和模拟视频领域,也是使用3个分量表示颜色,Y指的是亮度,U和V指的是色度,用来描述影像色彩和饱和度。YUV格式大体上分为两大类:平面格式(YUV分量分开存)和打包格式(YUV分量合在一起按照一定的编码格式存)。
主流的采样方式有三种:YUV4:2:2 、YUV4:2:0、YUV4:4:4
YUV4:2:0 : 对于每4个像素(2*2的块),共享一组U和Y值,每个像素都有独立的Y值
YUV4:4:4 :对于每个像素,Y、U、V都有独立的采样值
YUV4:2:2 :对于每2个水平相邻的像素,共享一组U和V值,而每个独立的像素都有一个Y值

如果想要把YUV格式的图像显示到LCD屏幕上就要做相应的转换,如下图。

在摄像头采集画面之前,需要设置摄像头采集画面的参数,比如帧宽度、帧高度、图像格式等,要通过一个结构体struct v4l2_format进行设置,注意,当前使用的摄像头只支持YUYV格式的采集(这里我的摄像头只支持YUYV格式的采集)。

V4L2设备以流的形式处理多媒体数据,流由包含格式化数据的缓冲区组成。一个设备可以有多个同时的流。大多数流是视频图像,但也可能存在其他类型。v4l2_format结构包含一个联合体,用于处理不同的格式结构,以便以后可以添加更多。应用程序必须始终设置类型字段,用于指示正在使用的格式类型以及它适用于哪个流。
(3)向v4l2驱动申请帧缓存区,利用帧缓存循环存储摄像头捕获到的图像,一般申请4个!
需要定义struct v4l2_requestbuffers结构体变量,在这个结构体中可以设置需要申请的帧缓存的数量,一般申请4个帧缓存,这样每个帧缓存都会存储一帧图像,循环调用就可以提高视频采集的效率。

内存映射方式:有以下三种
直接读取:利用read、write,直接对内存数据不断拷贝,占用大量内存空间(不推荐)
内存映射:利用mmap函数把驱动的帧缓存映射到应用程序的内存中,效率高(推荐)
用户指针:内存片段由应用程序自己分配,需要设置V4L2_MEMORY_USERPTR(不推荐)

(4)获取申请成功的每个帧缓存的参数信息,并且为每个帧缓存申请捕获图像大小的堆内存
想要从帧缓存中得到采集到的数据,需要知道从驱动中申请的每个缓存块的信息(缓存块地址、缓存块的大小),所以需要定义struct v4l2_buffer结构体变量存储,并把缓存进行内存映射。

(5)为了让摄像头可以把采集的图像存储在申请的帧缓存中,所以需要把申请的帧缓存入队

(6)缓存区入队之后,用户可以启动图像捕捉,然后摄像头就可以循环的把图像存入缓存区

(7)依次把缓存区出队,然后用户对缓存区存储的图像数据进行处理,但是要实现超时处理

把缓存块按照索引依次出队,然后保存缓存块中的数据后,再把缓存块重新入队,但是需要使用select()函数实现多路复用检测是否采集到数据,实现超时处理。
select函数一般用于网络编程,该函数可以帮用户监听多个文件描述符的状态,如果监听的多个文件中的某个文件的描述符发生的改变(读写或异常),select函数可以及时通知进程。

(8)把出队的缓存区中的YUYV格式的颜色分量转换为RGB格式的颜色分量并显示在LCD上

本次使用的摄像头只支持采集YUYV格式的图像,而在LCD屏上显示的是RGB数据,所以需要把采集到的图像转换成RGB。RGB对于大家来说并不陌生,看到的光就是由RGB三种颜色按一定比例混合得到,是使用红、绿、蓝三原色的亮度来表示颜色,三种颜色互相叠加实现混色,所以适用于显示屏等器件。在LCD屏中每个像素点的颜色都是由RGB组成的,LCD屏中一个像素点4个字节,RGB分别占用一个字节,每个字节的取值范围都是0~255,不过又加入了透明度,所以LCD屏中一个像素点就是由ARGB构成的。
下面的代码不是V4L2的原码,是我写的将一个YUV格式的像素点转换为RGB格式的函数
===============================================

如果可以实现一个像素点的格式转换,则只需要根据摄像头采集画面的宽和高把所有的像素点依次进行转换。
如果一帧YUV格式的图像已经转换为一帧RGB格式的图像,则只需要把RGB格式图像的像素点拷贝到LCD屏的像素点中即可。

提示:如果需要项目原码可以在我的项目专栏中找到
相关文章:
视频输入设备-V4L2的开发流程简述
一、摄像头的工作原理与应用 基本概念 V4L2的全称是Video For Linux Two,其实指的是V4L的升级版,是linux系统关于视频设备的内核驱动,同时V4L2也包含Linux系统下关于视频以及音频采集的接口,只需要配合对应的视频采集设备就可以实…...
【Manus资料合集】激活码内测渠道+《Manus Al:Agent应用的ChatGPT时刻》(附资源)
DeepSeek 之后,又一个AI沸腾,冲击的不仅仅是通用大模型。 ——全球首款通用AI Agent的破圈启示录 2025年3月6日凌晨,全球AI圈被一款名为Manus的产品彻底点燃。由Monica团队(隶属中国夜莺科技)推出的“全球首款通用AI…...
Mybatis集合嵌套查询,三级嵌套
三个表:房间 玩家 玩家信息 知识点:Mybatis中级联有关联(association)、集合(collection)、鉴别器(discriminator)三种。其中,association对应一对一关系、collectio…...
thinkphp5.1 在fetch模版就超时
场景 当被渲染模版不存在,请求不响应任何内容,过一会就timeout 排查过程 使用xdebug,追踪代码,发现走到D:\temporary_files\m40285_mini\40285_mini\thinkphp\library\think\exception\Handle.php,进入死循环,一直…...
Dockerfile 深入浅出:从基础到进阶全解析
Dockerfile 深入浅出:从基础到进阶全解析 各位同学,大家好!欢迎来到今天的 Dockerfile 课程。Docker 技术在当今的软件开发和部署领域可以说是非常热门,而 Dockerfile 作为构建 Docker 镜像的关键文件,掌握它对于我们…...
CAD2025电脑置要求
Windows 系统 操作系统:64 位 Microsoft Windows 11 和 Windows 10 version 1809 或更高版本。 处理器 基本要求:2.5-2.9GHz 处理器,不支持 ARM 处理器。 推荐配置:3GHz 以上处理器(基础),4GHz …...
android App主题颜色动态更换
如何在Android开发中更换主题颜色,现在他们又问了关于动态更换应用主题颜色的问题。看来他们可能在实现过程中遇到了困难,或者需要更详细的动态切换指导。首先,我需要回顾之前的回答,看看是否已经覆盖了动态切换的部分,…...
微服务,服务治理nacos,负载均衡LOadBalancer,OpenFeign
1.微服务 简单来说,微服务架构风格[1]是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在 自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并 且可通过全自动部署机制独立部署。这…...
浅论数据库聚合:合理使用LambdaQueryWrapper和XML
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、数据库聚合替代内存计算(关键优化)二、批量处理优化四、区域特殊处理解耦五、防御性编程增强 前言 技术认知点:使用 XM…...
FastGPT 引申:混合检索完整实例
文章目录 FastGPT 引申:混合检索完整实例1. 各检索方式的初始结果2. RRF合并过程3. 合并后的结果4. Rerank重排序后5. 最终RRF合并6. 内容总结 FastGPT 引申:混合检索完整实例 下边通过一个简单的例子说明不同检索方式的分值变化过程,假设我…...
Socket.IO聊天室
项目代码 https://github.com/R-K05/Socket.IO- 创建项目 服务端项目和客户端项目 安装Socket依赖 服务端 npm i socket.io 客户端 npm i socket.io-client 客户端添加聊天页面 源码 服务端 app.js const express require("express") const app express()co…...
MySQL表中数据基本操作
1.表中数据的插入: 1.insert insert [into] table_name [(column [,column]...)] values (value_list) [,(value_list)] ... 创建一张学生表: 1.1单行指定列插入: insert into student (name,qq) values (‘张三’,’1234455’); values左…...
可狱可囚的爬虫系列课程 16:爬虫重试机制
一、retrying模块简介 在爬虫中,因为我们是在线爬取内容,所以可能会因为网络、服务器等原因导致报错,那么这类错误出现以后,我们想要做的肯定是在报错处进行重试操作,Python提供了一个很好的模块,能够直接帮…...
第十五届蓝桥杯----B组cpp----真题解析(小白版本)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 必看前言!!!!!一、试题A:握手问题1.题意分析2.代码解答 二、试题B:小球反弹1.题意…...
软考架构师笔记-数据库系统
1.7 数据库系统 三级模式-两级映射 三级模式 外模式:用户视图概念模式:只涉及描述内模式:存储方式的描述 两级映射 外模式-概念模式映射概念模式-内模式映射 数据库的设计 步骤 需求分析 输出为需求分析、数据流图(Data FLow Diagram-DF…...
Spring AI 1.0.0-M6 快速开始(一)
Spring AI 1.0.0-M6 入门一、存储库二、依赖管理完整maven 入门 Spring 是JAVA中我们经常使用的框架之一,Spring AI不断的发展迭代目前已经到M6版本据说上半年会出一个稳定版本。 本节提供了如何开始使用Spring AI的M6。 一、存储库 1.0 M6 -添加Spring存储库 需…...
go 分布式redis锁的实现方式
go 语言以高并发著称。那么在实际的项目中 经常会用到锁的情况。比如说秒杀抢购等等场景。下面主要介绍 redis 布式锁实现的两种高并发抢购场景。其实 高并发 和 分布式锁 是一个互斥的两个状态: 方式一 setNX: 使用 redis自带的API setNX 来实现。能解决…...
Unity中Stack<T>用法以及删除Stack<GameObject>的方法
Unity中Stack用法以及删除Stack的方法 介绍Stack<T>的APIStack<T> 常用方法创建和初始化 Stack<T>Push 和 Pop 操作Stack<T>遍历清空栈检查栈是否包含某个元素 栈的典型应用场景撤销操作深度优先搜索(DFS)注意事项 总结 介绍 因…...
Vue进阶之Vue3源码解析(二)
Vue3源码解析 运行runtime-coresrc/createApp.tssrc/vnode.ts.tssrc/renderer.ts runtime-domsrc/index.ts 总结 运行 runtime-core src/createApp.ts vue的创建入口 import { createVNode } from "./vnode";export function createAppAPI(render) {return funct…...
linux的文件系统及文件类型
目录 一、Linux支持的文件系统 二、linux的文件类型 2.1、普通文件 2.2、目录文件 2.3、链接文件 2.4、字符设备文件: 2.5、块设备文件 2.6、套接字文件 2.7、管道文件 三、linux的文件属性 3.1、关于权限部分 四、Linux的文件结构 五、用户主目录 5.1、工作目录…...
接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
