V4L2系列 之 V4L2驱动框架(1)

news2024/11/19 23:16:20

目录

  • 前言
  • 一、V4L2驱动框架概览
    • 1、应用层 -》中间层-》驱动层
    • 2、主要代码文件(Linux 4.19版本内核)
  • 二、怎么写V4L2驱动
    • 1、如何写一个设备的驱动?
    • 2、Video设备主要结构体
    • 3、怎么写V4L2驱动
  • 三、V4L2的调试工具
    • 1、v4l2-ctl
    • 2、dev_debug
    • 3、v4l2-compliance

前言

  本篇文章主要介绍Linux内核中的V4L2框架,本篇文章所用内核版本:linux-4.19

  v4L2 (Video for Linux 2),是linux的一套视频框架,共主体位于内核,可以理解为是整个linux系统上面的视频源捕获驱动框架。其广泛应用在嵌入式设备、移动端以及个人电脑设备上面,市而上使用视频图像采集的设备如:手机、IPC、行车记录仪都会用到这个框架来进行视频采集。

  v4L2允许 应用程序 控制图像传感器以及传输格式,应用程序 借此完成拍照、预览、视频记录等图像传感器数据应用。

  之前,Linux还存在第一版的V4L2,该版本在内核2.6.38版中放弃支持。

一、V4L2驱动框架概览

1、应用层 -》中间层-》驱动层

  linux采用多层次的驱动架构来对接口进行统一与抽象,最低层次的驱动总是直接面向硬件的,而最高层次的驱动被划分为字符、块、网络设备三大类,前两类驱动在文件系统中形成类似文件的“虚拟文件”,又称为“节点node",这些节点拥有不同的名称代表不同的设备,在目录/dev下进行统一管理,系统调用函数如open、close、read等也与普通文件的操作有相似之处,这种接口的一致性是由VFS(虚拟文件系统层)抽象完成的。

  V4L2是关于视频设备的中间驱动层,向上 为 应用程序 访问 视频设备提供了通用接口,向下为设备驱动程序开发提供了统一的V4L2框架。其视频设备节点路径通常为/dev中的videoX。V4L2驱动对用户空间提供“字符设备”的形式,主设备号为81,在用户空间通过各种ioctl调用进行控制,并且可以使用mmap进行内存映射。

V4L2支持多种设备,有以下接口:
√视频采集接口(video capture interface)
√视频输出接口(video output interface)
√直接传输视频接口(video overlay interface) 
√视频间隔消隐信号接口(VBI interface)
√收音机接口(radio interface).

在这里插入图片描述

	应用通过open、ioctl等系统调用操作video设备。在内核空间,Video设备的具体操作
方法由驱动中的struct video_device提供。

	驱动使用video_register_device函数将struct video_device注册到V4L2的核心
层,然后V4L2的核心层再向上注册一个字符设备。这样应用就可以使用系统调用访问虚拟
文件系统中Video设备提供的方法,然后进一步访问V4L2核心层提供的v4l2_fops方法集
合,最后通过struct video_device结构休中的fops和ioctl_ops方法集合访问Video
主设备。

	Video主设备通过V4L2_subdev_call方法访问Video从设备,同时Video从设备可以
通过notify回调方法通知主设备发生了事件。

在这里插入图片描述

2、主要代码文件(Linux 4.19版本内核)

  v4L2的驱动源码在kernel/drivers/media/v4l2-core目录下,主要代码文件有:

(1)v4l2-dev.c //视频设备硬件的操作,包含video_device的注册、释放等,主要包括
//以下函数:
	videodev_init
		register_chrdev_region
		class_register
	videodev_exit
		class_unregister
		unregister_chrdev_region
	__video_register_device
	video_unregister_device
	
(2)v4l2-common.c //一些通用操作,V4l2的子设备一般是摄像头和摄像头控制器,
//它们和主机的控制操作是通过i2c总线完成的。V4l2驱动框架中跟i2c相关的代码在
//v4l2_common.c中
	v4l2_ctrl_query_fill
	v4l2_i2c_subdev_init
	v4l2_i2c_new_subdev_board
	v4l2_i2c_new_subdev
	v4l2_i2c_subdev_addr
	v4l2_i2c_tuner_addrs
	v4l2_spi_subdev_init
	v4l2_spi_new_subdev
	clamp_align
	v4l_bound_align_image
	__v4l2_find_nearest_size
	v4l2_get_timestamp
	v4l2_g_parm_cap
	v4l2_s_parm_cap
	
(3)v4l2-device.c //V4L2的设备支持,主要是注册v4I2_device,包括以下函数:
	v4l2_device_register
	v4l2_device_unregister
	
	v4l2_device_put
	v4l2_device_release
	
	v4l2_device_register_subdev
	v4l2_device_unregister_subdev
	
	v4l2_device_register_subdev_nodes
	v4l2_device_release_subdev_node	

(4)v4l2-ioctl.c  //处理V4L2的ioctl命令的一个通用的框架。

(5)v412-subdev.c //v4l2子设备

(6)v4l2-mem2mem.c //使用videobuf缓冲区的设备辅助函数。

V4L2缓冲区管理

	V4L2维护着两个缓冲队列:一个用于驱动(INPUT队列),另一个用于用户程序
(OUTPUT队列)。
	缓冲区(由VIDIOC_REQBUFS命令申请)被用户空间的应用程序放入驱动的队
列中(通过VIDIOC_QBUF ioctl命令)以便填充数据。驱动按顺序填充缓冲区后,
缓冲区由INPUT队列放入OUTPUT队列。

	当用户程序调用VIDIOC_DQBUF命令后,驱动会在OUTPUT队列中寻找可用的
缓冲,如果可用则推送到用户程序,不可用则等待直到有可用缓冲后再推送给用
户程序。缓冲区使用完后,必须调用VIDIOC_QBUF将缓冲区重新加入INPUT队列
以便再次填充数据。

	注意驱动程序会独立自主的填充INPUT队列中的缓冲区,如果用户程序对缓
冲数据使用不及时,INPUT队列被填满,驱动暂停等待,会产生丢帧。

二、怎么写V4L2驱动

1、如何写一个设备的驱动?

  以字符设备驱动为例,请阅读我之前所写的一篇文章:字符设备驱动的三种实现方法

2、Video设备主要结构体

  struct v4l2_device:一个硬件设备可能包含多个子设备,比如一个电视除了有capture设备,可能还有VBI设备或者FM tunner。而v4l2_device就是所有这些设备的根节点,负责管理所有的子设备。

/ * *
*struct v4l2_device -用于V4L2设备驱动程序的主结构
*
* @dev:指向设备结构体的指针。
* @mdev:指向结构体media_device的指针,可以为NULL* @subdevs:用于跟踪已注册的子设备
* @lock:锁定这个结构体;如果该结构嵌入到一个更大的结构中,驱动程序也可以使用
* 该结构。
* @name:唯一的设备名称,默认为驱动器名称+总线ID
* @notify:通知进行了某个操作(某些子设备被调用)
* @ctrl_handler:控制处理程序。可能是NULL* @prio:设备的优先级状态
* @ref:跟踪对这个结构体的引用。
* @release:当ref计数变为0时调用的释放函数。
*
* V4L2设备的每个实例都应该创建v4l2_device结构体,无论是独立的还是嵌入到
* 更大的结构体中。
*
*它允许轻松访问子设备(参见V4L2 -subdev.h),并提供基本的V4L2设备级支持。
*
* . .注意::
*
* #) @dev->driver_data指向该结构体。
* #)如果没有父设备,@dev可能是%NULL
* /
struct v4l2_device {
	struct device *dev;
	struct media_device *mdev;
	struct list_head subdevs;
	spinlock_t lock;
	char name[V4L2_DEVICE_NAME_SIZE];
	void (*notify)(struct v4l2_subdev *sd,
			unsigned int notification, void *arg);
	struct v4l2_ctrl_handler *ctrl_handler;
	struct v4l2_prio_state prio;
	struct kref ref;
	void (*release)(struct v4l2_device *v4l2_dev);
};

  struct video_device:这个结构体的主要作用时提供/dev/videoX或/dev/v4l-subdevx设备节点,同时对捕获接口进行抽象,用来描述一个出帧的设备。另外,Video子设备也是继承自该结构体。该结构体包含指向v4l2_file_operations、v4l2_ioctl_ops等的操作对象指针。

/ * *
* struct video_device——用于创建和管理V4L2设备节点的结构。
*
* @entity: &struct media_entity
* @intf_devnode:指向&struct media_intf_devnode的指针
* @pipe: &struct media_pipeline
* @fops:指向视频设备的&struct v4l2_file_operations的指针
* @device_caps: v4l2_capabilities中使用的设备能力
* @dev: &struct设备用于视频设备
* @cdev:字符设备
* @v4l2_dev:指向struct v4l2_device父设备的指针
* @dev_parent:指向&结构设备父设备的指针
* @ctrl_handler:与该设备节点关联的控制处理程序。可能为NULL* @queue: &struct vb2_queue与该设备节点相关联。可能为NULL* @prio:指向带有设备优先级状态的struct v4l2_prio_state的指针。
* 如果为NULL,则使用v4l2_dev->prio。
* @name:视频设备名称
* @vfl_type: V4L设备类型,由&enum vfl_devnode_type定义
* @vfl_dir: V4L接收器、发射器或m2m
* @minor:设备节点“minor”。如果注册失败,则设置为-1
* @num:视频设备节点编号
* @flags:视频设备标志。使用bitops来设置/清除/测试标志。
* 包含一组&enum v4l2_video_device_flags* @index:属性用于区分一个物理设备上的多个索引
* @fh_lock:对所有v4l2_fhs进行锁
* @fh_list: struct v4l2_fh的列表
* @dev_debug:内部设备调试标志,驱动程序不使用
* @tvnorm:支持的电视规范
*
* @release:视频设备release()回调函数
* @ioctl_ops:带有ioctl回调函数的指向&struct v4l2_ioctl_ops的指针
*
* @valid_ioctls:该设备有效的ioctl的位图
* @lock:指向& &struct mutex 序列化锁的指针
*
* . .注意::
*只有在无法从@v4l2_dev推导出@dev_parent时才设置它。
* /
* 
struct video_device
{
#if defined(CONFIG_MEDIA_CONTROLLER)
	struct media_entity entity;
	struct media_intf_devnode *intf_devnode;
	struct media_pipeline pipe;
#endif
	const struct v4l2_file_operations *fops;

	u32 device_caps;

	/* sysfs */
	struct device dev;
	struct cdev *cdev;

	struct v4l2_device *v4l2_dev;
	struct device *dev_parent;

	struct v4l2_ctrl_handler *ctrl_handler;

	struct vb2_queue *queue;

	struct v4l2_prio_state *prio;

	/* device info */
	char name[32];
	enum vfl_devnode_type vfl_type;
	enum vfl_devnode_direction vfl_dir;
	int minor;
	u16 num;
	unsigned long flags;
	int index;

	/* V4L2 file handles */
	spinlock_t		fh_lock;
	struct list_head	fh_list;

	int dev_debug;

	v4l2_std_id tvnorms;

	/* callbacks */
	void (*release)(struct video_device *vdev);
	const struct v4l2_ioctl_ops *ioctl_ops;
	DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);

	struct mutex *lock;
};

3、怎么写V4L2驱动

(1)分配/设置/注册v4l2_device(调用函数注册v4l2_device_register),有辅助作用,提供自旋锁以及引用计数
(2)分配video_device:video_device_alloc()kzalloc()(3)设置video_device:.fops、.ioctl_ops、dev;
(4)注册video_device: video_register_device()

参考阅读:https://blog.csdn.net/seiyaaa/article/details/120199720
Video设备注册时的执行流程可总结如下:
1.设置设备注销时资源释放回调和v4l2_device结构体。

2.检查设备类型并确定设备节点基本名称。

3.设置设备类型、次设备号及设备节点数量。

4.将video_device结构体指针保存到全局video_device数组中。

5.根据设备类型验证哪那些ioctl函数可以使用。

6.分配字符设备结构体。

7.设置字符设备的操作函数集合为v4l2_fops。

8.将video设备注册为字符设备,并注册设备;

9.设置设备引用计数为0时的回调函数,该函数主要的工作是删除注册的字符设备,
回调v4l2_device中的release函数(通常是video_device_release函数)释放
video_device结构体内存,最后减少v4l2_device的引用计数;

10.增加video_device所属v4l2_device的引用计数。

11.设置已注册标志V4L2_FL_REGISTERED。

Video设备访问流程

(1)首先通过系统调用访问/dev/videox用户空间设备节点。

(2)进入到内核空间,访问字符设备struct file_operations中的方法。对于Video
设备,该操作集合被v4L2子系统初始化为v4l2_fops集合。

(3)通过v4L2子系统提供的v4l2_fops集合,可直接调用底层驱动实现的Video主设备
struct v4l2_file_operations方法,对于ioctl方法,则需要借助中间函数
__video_do_ioctl调用底层驱动实现的struct v4l2_ioctl_ops中的ioctl功能。
struct v4l2_file_operations方法和struct v4l2_ioctl_ops方法属于主设备
方法,需要主设备的驱动实现。

( 4) struct v4l2_file_operationsstruct v4l2_ioctl_ops中的函数都可以
通过v4l2_subdev_call调用video从设备struct v4l2_subdev_core_opsstruct
v4l2_subdev_video_opsstruct v4l2_subdev_pad_ops等方法,这些方法都要在
从设备驱动中实现。

三、V4L2的调试工具

1、v4l2-ctl

  为便于开发,常见的Linux发行版会附带一个v4l2-ctl的命令行工具,可以用来测试摄像头子系统。该工具可以列出系统内的设备列表,查询设备能力,调整设备属性以及设置像素格式、分辨率、帧率等,同时也可以执行捕捉图像等动作。

  参考阅读:v4l2-ctl基本使用方法

2、dev_debug

V4L2调试
由丁video系统的配置较复杂,为便于调试,V4L2提供了简单但庞大的用户空间调试手段,用于跟踪框架或用户空间API的信息。
椎架的调试信息可通过下述命令开启(通过dmesg查看):
# echo 0x3 > /sys/module/videobuf2_v4l2/parameters/debugt
# echo 0x3 > /sys/module/videobuf2_common/parameters/debug

V4L2的用户空问API跟踪通过下述命令开启:
# echo 0x3 >/sys/class/video4linux/video0/dev_debug

在这里插入图片描述

3、v4l2-compliance

  Video设备要工作正常,驱动兼容性是一个重要的方面,v4l2-compliance 工具可以通过测试V4L2设备的各个方面来判断其驱动兼容性。

  使用方法请阅读:v4l-utils之v4l2-compliance

  初步了解V4L2的驱动框架后,下一篇将以《虚拟摄像头驱动:drivers\media\platform\vivid》进行详细分析解读,进一步深入理解,敬请期待.

本文内容主要来自百度百科以及韦东山老师的课程笔记,如有侵权,联系删除!欢迎各位在评论区指导交流!!!

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

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

相关文章

00后卷王的自述,我真有同事口中说的那么卷?

前言 前段时间去面试了一个公司,成功拿到了offer,薪资也从14k涨到了20k,对于工作都还没几年的我来说,还是比较满意的,毕竟一些工作5、6年的可能还没我高。 我可能就是大家口中的卷王,感觉自己年轻&#xf…

一文读懂Redis哨兵

Redis哨兵(sentinel) 哨兵是什么? 吹哨人巡查监控后台master主机是否故障,如果故障了根据投票数自动将某一个从库转换为新主库,继续对外服务。 俗称,无人值守运维。 干什么? 主从监控&…

Win10系统下VS2019编译Qt的Ribbon控件 -- SARibbon

Win10系统下VS2019编译Qt的Ribbon控件 -- SARibbon 一、源码下载二、源码编译三、封装成库四、Qt配库五、运行测试 原文链接:https://blog.csdn.net/m0_51204289/article/details/126431338 一、源码下载 【1】https://gitee.com/czyt1988/SARibbon/tree/master/s…

Python开发工具PyCharm v2023.1正式发布——推出全新的用户界面

JetBrains PyCharm是一种Python IDE,其带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具。此外,该IDE提供了一些高级功能,以用于Django框架下的专业Web开发。 PyCharm v2023.1正式版下载 更新日志如下: 推出新的…

【UE】三步创建自动追踪自爆可造成伤害的敌人

效果 可以看到造成伤害时在右上角打印玩家当前的生命值 步骤 1. 首先拖入导航网格体边界体积 2. 首先复制一份“ThirdPersonCharacter”,命名为“ExplodingAI” 打开“ExplodingAI”,删除事件图表中所有节点 添加一个panw感应组件 在事件图表中添加如…

机器学习实战:Python基于PCA主成分分析进行降维分类(七)

文章目录 1 前言1.1 主成分分析的介绍1.2 主成分分析的应用[](https://chat.openai.com/ "openai") 2 Mushroom分类数据演示2.1 导入函数2.2 导入数据2.3 PCA可视化2.4 PCA散点图2.5 PCA散点图 3 讨论 1 前言 1.1 主成分分析的介绍 主成分分析(Principa…

Consistency Models

Consistency Models- 理解 问题定义研究动机本文中心论点 相关工作和进展Consistency Models创新点review扩散模型 Consistency Model-Definition一致性模型的定义一致性模型参数化一致性模型采样 Training Consistency Models via DistillationTraining Consistency Models in…

ChatGPT on Notes/Domino

大家好,才是真的好。 随着春节过去,小盆友也开始陆续到幼儿园报到,我们又回来和大家一起继续Notes/Domino传奇之旅。 去年年底ChatGPT横空出世,让大家震惊了一把。 可能有些老Notes/Domino人,还不知道ChatGPT是什么…

MySQL_第11章_数据处理之增删改

第11章_数据处理之增删改 讲师:尚硅谷 - 宋红康(江湖人称:康师傅) 官网: http://www.atguigu.com 1. 插入数据 1.1 实际问题 解决方式:使用 INSERT 语句向表中插入数据。 1.2 方式1:VA…

在OpenHarmony 开发者大会2023,听见百业同鸣

加强开源,助推中国科技强国战略,已经成为中国科技繁荣的必要条件,“十四五”规划中首次提到了“开源”两个字,并明确指出,支持数字技术开源社区等创新联合体的发展。 在中国发展开源,有着拓荒的色彩&#x…

Springsecurity笔记14-18章JWT+Spring Security+redis+mysql 实现认证【动力节点】

15 SpringSecurity 集成thymeleaf 此项目是在springsecurity-12-database-authorization-method 的基础上进行 复制springsecurity-12-database-authorization-method 并重命名为springsecurity-13-thymeleaf 15.1 添加thymeleaf依赖 | <groupId>org.springframewor…

西门子s7-300/400PLC-MMC密码解密

西门子s7-300/400-MMC密码解密 简介西门子加密工具及操作密码验证 简介 目前&#xff0c;市面上或网络上有很多针对s7-200&#xff0c;300&#xff0c;400&#xff0c;1200&#xff0c;1500的密码解密破解软件&#xff0c;但很多时候只能解数字或英文密码&#xff0c;对设置了…

Linux-初学者系列——篇幅5_系统目录相关命令

系统目录相关命令-目录 一、系统目录层级1、目录绝对路径2、目录相对路径3、目录层级结构查看-tree不带任何参数获取目录结构数据信息以树形结构显示目录下的所有内容&#xff08;包含隐藏信息&#xff09;只列出根目录下第一层的目录结构信息只显示目录结构信息中的所有目录信…

ThingsBoard如何自定义topic

1、背景 业务需要,mqtt设备,他们协议和topic都定义好了,想使用tb的mqtt直接接入设备,但是设备的topic和tb规定的不一致,该如何解决呢? 2、要求 设备的topic要求规则是这样的 首先第二点是满足的,网关的发布主题是可以通过tb的设备配置来自定义遥测和属性的topic,问题…

qiankun应用级缓存-多页签缓存

需求&#xff1a; A&#xff1a;主应用 B&#xff1a;子应用 项目框架&#xff1a;vue2 全家桶 qiankun 应用间切换需要保存页面缓存&#xff08;多页签缓存&#xff09;&#xff0c;通过vue keep-alive只能实现页面级缓存&#xff0c;在单独打开的应用里能实现缓存&#xf…

德国申请专利,发明,实用,外观专利申请详细步骤

一、德国专利申请途径 申请人可以向德国专利商标局直接递交申请。要求优先权的情况下根据《保护工业产权巴黎公约》需要在递交中国在先申请的12个月之内向德国专利商标局递交申请。 另外&#xff0c;通过PCT&#xff08;“Patent Cooperation Treaty”&#xff0c;即《专利合作…

【分享】免费的AI绘画网站(5个)

哈喽&#xff0c;大家好&#xff0c;我是木易巷~ 随着人工智能技术的不断发展&#xff0c;越来越多的AI绘画软件开始涌现&#xff0c;如果你想要免费享受AI绘画的乐趣&#xff0c;那你可要好好看下面的内容~ Vega AI创作平台 入口&#xff1a;https://rightbrain.art 一款专业的…

AIGC+RPA丨大语言模型赋能实在智能数字员工“超进化”

前不久&#xff0c;全球最大上市咨询公司埃森哲发布2023年技术愿景《When Atoms meet Bits》报告&#xff0c;并在当中深度解析到&#xff1a;生成式AI成为2023年四大技术发展趋势之一。 大型语言模型&#xff08;Large Language Model, LLM&#xff09;领域的研发和布局在国内…

如何科学判断研发团队是否在健康工作?(内附量表)

研发效能管理覆盖了交付速度、质量和价值三个维度&#xff0c;但文化建设、团队氛围和客户协作等其他因素对团队工作的影响又该如何度量和管理呢&#xff1f; LigaAI 在 John Cutler 的一篇分享中找到了答案&#xff1a;团队健康度评分。就像我们都很关心自己的身体健康一样&a…

《程序员面试金典(第6版)》面试题 16.02. 单词频率(哈希法,C++)

题目描述 设计一个方法&#xff0c;找出任意指定单词在一本书中的出现频率。 你的实现应该支持如下操作&#xff1a; WordsFrequency(book)构造函数&#xff0c;参数为字符串数组构成的一本书get(word)查询指定单词在书中出现的频率 示例&#xff1a; WordsFrequency word…