Linux中V4L2框架介绍—V4L2 Core

V4L2框架简介

V4L2(Video for Linux 2)框架是 Linux 内核中的一个子系统,专门用于处理视频设备的管理和控制。它提供了统一的 API 和抽象层,使得开发者可以编写通用的视频驱动程序,同时使用户空间的应用程序能够轻松地访问和控制视频设备。

V4L2 框架的主要功能

  1. 设备抽象:

    • V4L2 框架将各种视频设备(如摄像头、电视调谐器、视频捕捉卡等)抽象为通用的接口。无论底层硬件如何,用户空间应用程序都可以通过统一的方式访问这些设备。
  2. 视频捕捉:

    • 支持视频流的捕捉,包括图像采集和视频录制。典型的用例包括从摄像头获取视频帧,或从视频卡中获取信号。
  3. 图像处理:

    • 提供各种图像处理功能,如缩放、格式转换、色彩空间转换等。这些操作可以在硬件或软件中实现。
  4. 控制接口:

    • V4L2 提供了一系列标准化的控制接口,如调整亮度、对比度、饱和度等。设备驱动可以定义这些控制,并且用户空间应用程序可以通过标准化的方式进行访问和调整。
  5. 媒体控制器框架的集成:

    • 对于复杂的多媒体设备,V4L2 与媒体控制器框架集成,管理设备间的连接和数据流。这对于处理多个输入输出的设备(如视频传感器阵列)非常有用。
  6. 子设备框架:

    • V4L2 引入了子设备(sub-device)概念,允许将设备的某些功能模块化。这使得驱动程序可以更加灵活地处理复杂的设备组合,如多个摄像头传感器与单个处理器连接的情况。

V4L2 框架的组成部分

V4L2框架,主要包括v4l2-coremeida frameworkvideobuf2等模块,本篇主要重点介绍v4l2-core

从应用角度看如何使用V4L2框架

在这里插入图片描述

进行视频采集的步骤如左侧所示

  1. 打开设备文件/dev/videoX
  2. 根据打开的设备,查询设备能力集;
  3. 设置视频数据的格式、参数等;
  4. 分配buffer,这个buffer可以是用户态分配的,也可以是从内核中获取的;
  5. 开始视频流采集工作;
  6. 将buffer enqueue到v4l2框架,底层负责将视频数据填充后,应用层再将buffer dequeue以便获取数据,然后再将buffer enqueue,如此循环往复;

右侧为V4L2 Core 大体框架

V4L2 Core 中相关对象

video_device

结构体的主要作用是将 V4L2 设备(如摄像头、视频捕捉卡等)和内核空间中的驱动程序接口暴露给用户空间的应用程序。每个 video_device 实例对应一个设备节点,应用程序可以通过标准的 V4L2 API 访问这些设备节点。

v4l2_device

v4l2_device 是 V4L2(Video for Linux 2)框架中的一个核心结构体,用于表示和管理一个 V4L2 设备。它通常是一个设备的顶层管理对象,用于在驱动程序中协调多个 video_devicev4l2_subdev 和其他相关对象。

v4l2_subdev

依附在v4l2_device之下,并表示一个v4l2设备的子设备,一个v4l2_devide下可以有多个sub_device

video buf 2

Videobuf2(简称 VB2)是 Linux 内核中的一个框架,专门用于处理视频设备的缓冲区管理。它是 Videobuf 的第二代版本,因此得名 Videobuf2VB2 被广泛应用于 V4L2(Video for Linux 2)驱动程序中,特别是在视频捕捉、视频输出等需要高效缓冲区管理的场景中。

V4L2 子设备介绍

v4l2_subdev的设计之初,便是为了提高代码的复用率。提供多路复用,以自动驾驶中 GMSL 传输协议下的CMOS摄像头举例:

在这里插入图片描述

比如上述相机模组中有传感器(i2c设备) 有串行器(i2c设备),右侧的MAX96712为解串器(i2c设备) ,为了实现四路环视系统,需要控制多个摄像头,就是多路复用

简化一下流程可得

在这里插入图片描述

其中相机传感器和ISP模块,CSI模块都可以看成一个V4L2的子设备 v4l2_subdev,而相机模组便是用v4l2_device 代表整个输入设备

V4L2 Core 中相关数据结构

【原创】Linux v4l2框架分析 - LoyenWang - 博客园 (cnblogs.com) 这篇博客图画的很清晰,借鉴一下

用具体源码来分析相关数据结构

v4l2_device 结构体在 V4L2(Video for Linux 2)框架中扮演着重要角色,主要用于管理和协调一个视频设备及其相关的子设备(sub-devices)。它充当了设备驱动程序的核心结构,用于处理多个组件的交互和资源管理。以下是对 v4l2_device 结构体中各个成员的详细分析:

v4l2_device 结构体
struct v4l2_device {
	struct device *dev;
#if defined(CONFIG_MEDIA_CONTROLLER)
	struct media_device *mdev;
#endif
	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;
	/* BKL replacement mutex. Temporary solution only. */
	struct mutex ioctl_lock;
	struct kref ref;
	void (*release)(struct v4l2_device *v4l2_dev);
};
  1. struct device *dev;

    • 描述: 指向 Linux 设备模型中的 device 结构体。device 结构体代表了一个通用的设备,这使得 v4l2_device 能够与 Linux 的设备模型和驱动程序框架集成。
    • 用途: 通过这个指针,v4l2_device 可以访问和操作与该设备相关的通用资源和接口,如电源管理、设备树节点等。
  2. #if defined(CONFIG_MEDIA_CONTROLLER) struct media_device *mdev; #endif

    • 描述: 当内核配置启用了媒体控制器(CONFIG_MEDIA_CONTROLLER)时,mdev 指向 media_device 结构体。
    • 用途: media_device 用于管理复杂多媒体设备中的媒体实体(如视频设备、音频设备等)。它在一个多媒体设备中提供了一个统一的抽象层,允许跨设备和跨子设备的协作。
  3. struct list_head subdevs;(重点)

    • 描述: 这是一个链表,保存了与该 v4l2_device 关联的所有 v4l2_subdev 结构体(子设备)。
    • 用途: 通过这个链表,驱动程序可以管理和遍历与该视频设备相关的所有子设备,方便进行子设备之间的协调与资源共享。
  4. spinlock_t lock;

    • 描述: 这是一个自旋锁,用于保护 v4l2_device 结构体中的数据,防止在多核环境中并发访问导致的数据竞争。
    • 用途: 在需要对 v4l2_device 进行短时间的、高频率的访问时,自旋锁提供了轻量级的同步机制。
  5. char name[V4L2_DEVICE_NAME_SIZE];

    • 描述: 用于存储设备的名称,V4L2_DEVICE_NAME_SIZE 是名称字符串的最大长度。
    • 用途: 名称用于标识设备,通常在调试、日志记录和设备识别时使用。
  6. void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg);

    • 描述: 这是一个函数指针,用于在特定事件发生时通知子设备。sd 是指向触发事件的子设备的指针,notification 是通知的类型,arg 是传递给通知处理函数的额外参数。
    • 用途: 通过这个通知机制,v4l2_device 可以协调不同子设备之间的操作。例如,当某个子设备的状态发生变化时,它可以通知其他相关设备。
  7. struct v4l2_ctrl_handler *ctrl_handler;

    • 描述: 指向 v4l2_ctrl_handler 结构体的指针。v4l2_ctrl_handler 管理设备的控制接口,用于处理设备的各种控制命令(如调整亮度、对比度等)。
    • 用途: 这个控制处理器简化了设备控制的实现,提供了一个统一的接口来管理设备的控制功能。
  8. struct v4l2_prio_state prio;

    • 描述: 这是一个优先级状态结构体,用于管理设备的操作优先级。
    • 用途: 该结构体允许设备在处理多个操作请求时,基于优先级来调度请求。这对于需要处理实时视频流的设备尤为重要。
  9. struct mutex ioctl_lock;

    • 描述: 这是一个互斥锁(mutex),用于保护 ioctl 调用的访问。
    • 用途: 由于 ioctl 调用可能涉及复杂的操作和长时间的阻塞操作,使用互斥锁可以确保在执行这些操作时不会发生并发冲突。
  10. struct kref ref;

    • 描述: 这是一个内核引用计数结构体,用于跟踪 v4l2_device 结构体的引用计数。
    • 用途: 引用计数用于管理 v4l2_device 的生命周期,确保在没有引用时释放相关资源,防止内存泄漏。
  11. void (*release)(struct v4l2_device *v4l2_dev);

    • 描述: 这是一个函数指针,用于在 v4l2_device 释放时调用。
    • 用途: 当引用计数达到 0 时,调用 release 函数释放 v4l2_device 结构体和相关资源。
v4l2_subdev结构体

子设备通常指的是视频设备的一个组成部分,如摄像头传感器、编解码器、调谐器等。v4l2_subdev 结构体提供了子设备的抽象,并定义了子设备如何与其他组件和核心设备交互。

struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER)
	struct media_entity entity;
#endif
	struct list_head list;
	struct module *owner;
	bool owner_v4l2_dev;
	u32 flags;
	struct v4l2_device *v4l2_dev;
	const struct v4l2_subdev_ops *ops;
	const struct v4l2_subdev_internal_ops *internal_ops;
	struct v4l2_ctrl_handler *ctrl_handler;
	char name[V4L2_SUBDEV_NAME_SIZE];
	u32 grp_id;
	void *dev_priv;
	void *host_priv;
	struct video_device *devnode;
	struct device *dev;
	struct fwnode_handle *fwnode;
	struct list_head async_list;
	struct v4l2_async_subdev *asd;
	struct v4l2_async_notifier *notifier;
	struct v4l2_subdev_platform_data *pdata;
};

成员详细分析

  1. #if defined(CONFIG_MEDIA_CONTROLLER) struct media_entity entity; #endif

    • 描述: 如果启用了媒体控制器(CONFIG_MEDIA_CONTROLLER)配置选项,entity 将代表子设备在媒体控制器框架中的实体。
    • 用途: 媒体控制器框架用于管理复杂多媒体设备的媒体实体(如视频设备、音频设备等)。media_entity 提供了与其他实体连接和交互的接口。
  2. struct list_head list;

    • 描述: 这是一个链表节点,用于将子设备链接到一个 v4l2_devicesubdevs 链表中。
    • 用途: 通过这个链表,子设备可以被管理和遍历,使得设备驱动程序可以轻松地处理多个子设备。
  3. struct module *owner;

    • 描述: 指向该子设备所属的内核模块。
    • 用途: 该指针用于管理内核模块的引用计数,确保模块在被使用时不会被卸载。
  4. bool owner_v4l2_dev;

    • 描述: 表示这个子设备是否是 v4l2_device 的拥有者。
    • 用途: 这个布尔值用于区分子设备是否应该负责管理 v4l2_device 的生命周期。
  5. u32 flags;

    • 描述: 这是一个 32 位的标志字段,用于存储与子设备相关的状态标志。
    • 用途: 标志位可以用于配置子设备的行为或表示其状态,例如使能或禁用某些功能。
  6. struct v4l2_device *v4l2_dev;

    • 描述: 指向该子设备所属的 v4l2_device 结构体。
    • 用途: 通过这个指针,子设备可以访问并与它所属的 v4l2_device 进行交互,确保与主设备的协同工作。
  7. const struct v4l2_subdev_ops *ops;

    • 描述: 指向子设备操作函数集的指针,这些操作定义了子设备的行为。
    • 用途: ops 包含多个操作集,如核心操作(core ops)、视频操作(video ops)、音频操作(audio ops)等,用于处理子设备的不同功能。
  8. const struct v4l2_subdev_internal_ops *internal_ops;

    • 描述: 指向内部操作函数集的指针,用于处理子设备内部的操作。
    • 用途: 这些操作通常由子设备自身或驱动程序内部使用,不对外公开。例如,用于初始化或释放子设备。
  9. struct v4l2_ctrl_handler *ctrl_handler;

    • 描述: 指向控制处理器(v4l2_ctrl_handler)的指针,用于管理子设备的控制接口。
    • 用途: 控制处理器提供了一种机制,用于处理和管理子设备的各种控制,如调整图像属性(亮度、对比度等)。
  10. char name[V4L2_SUBDEV_NAME_SIZE];

    • 描述: 用于存储子设备的名称,V4L2_SUBDEV_NAME_SIZE 是名称字符串的最大长度。
    • 用途: 名称用于标识子设备,常用于调试、日志记录和设备识别。
  11. u32 grp_id;

    • 描述: 这是一个组标识符,用于将多个子设备分组。
    • 用途: grp_id 可以用于设备驱动程序中,方便同时管理和控制一组相关联的子设备。
  12. void *dev_priv;

    • 描述: 指向与子设备关联的私有数据。
    • 用途: 驱动程序可以使用这个指针来存储子设备的特定上下文或状态信息。
  13. void *host_priv;

    • 描述: 指向主机设备(通常是 v4l2_device)的私有数据。
    • 用途: 用于存储与主设备交互时需要的上下文信息。
  14. struct video_device *devnode;

    • 描述: 指向与子设备关联的视频设备节点(video_device)结构体。 当然子设备不是独立的视频设备节点,video_device结构体可以为空
    • 用途: 这个指针用于创建和管理视频设备节点,使得子设备可以作为一个独立的视频设备被用户空间访问。
  15. struct device *dev;

    • 描述: 指向与子设备关联的 device 结构体,表示一个通用的设备。
    • 用途: dev 提供了与 Linux 设备模型的集成,允许子设备使用通用的设备接口,如电源管理、设备树配置等。
  16. struct fwnode_handle *fwnode;

    • 描述: 指向固件节点(fwnode_handle),用于处理与设备树或 ACPI(高级配置和电源接口)相关的子设备配置。
    • 用途: 通过 fwnode,子设备可以解析其固件描述信息,如设备树中的节点,获取配置数据。
  17. struct list_head async_list;

    • 描述: 用于异步通知的链表节点,通常用于异步注册的子设备。
    • 用途: 这个链表节点用于管理子设备的异步通知,确保子设备可以在不同时间点被正确地初始化和注册。
  18. struct v4l2_async_subdev *asd;

    • 描述: 指向异步子设备(v4l2_async_subdev)的指针,用于异步注册子设备。
    • 用途: 在系统启动过程中,子设备可能需要异步地初始化和注册,asd 用于处理这种场景。
  19. struct v4l2_async_notifier *notifier;

    • 描述: 指向异步通知器(v4l2_async_notifier),用于管理子设备的异步通知。
    • 用途: notifier 负责跟踪和通知异步注册的子设备,确保在系统准备好时正确注册这些设备。
  20. struct v4l2_subdev_platform_data *pdata;

    • 描述: 指向平台数据(v4l2_subdev_platform_data),包含与子设备相关的特定平台数据。
    • 用途: 平台数据用于在不同硬件平台上配置子设备,提供特定于硬件的初始化和配置信息。
video_device 结构体

直接与用户空间交互的设备节点,它代表了用户空间程序可以访问的具体视频设备,如 /dev/video0video_device 结构体与字符设备密切相关,并且提供了字符设备的功能

  1. struct media_entity entity;

    • 用途: 表示媒体实体,用于与媒体控制器框架集成,使设备能够在复杂媒体管道中与其他实体连接和交互。
  2. const struct v4l2_file_operations *fops;

    • 用途: 指向与该设备相关的文件操作集,用于处理文件系统中的设备节点操作,如打开、关闭、读写。
  3. u32 device_caps;

    • 用途: 设备的功能和能力标志,表示该设备支持的功能,例如视频输入、输出、视频处理等。
  4. struct device dev;

    • 用途: 通用 Linux 设备结构,用于表示设备并将其集成到 Linux 设备模型中,支持 sysfs、设备树等功能。
  5. struct v4l2_device *v4l2_dev;

    • 用途: 指向与该 video_device 关联的 v4l2_device 结构,便于管理和与其他 V4L2 设备交互。
  6. struct vb2_queue *queue;

    • 用途: 指向 videobuf2 队列结构,用于管理视频缓冲区队列,是视频数据流处理的核心。
  7. char name[32];

    • 用途: 设备名称,用于识别和标识设备节点,常用于调试和用户空间应用程序中。
  8. int vfl_type;

    • 用途: 设备节点的类型(如视频输入、视频输出),用于标识设备的功能。
  9. spinlock_t fh_lock; struct list_head fh_list;

    • 用途: 用于保护和管理打开的文件句柄(file handles),确保文件操作的线程安全性。
  10. void (*release)(struct video_device *vdev);

    • 用途: 设备释放回调函数,当设备不再使用时调用,以释放资源和清理设备。
  11. const struct v4l2_ioctl_ops *ioctl_ops;

    • 用途: 指向设备的 IO 控制操作集,定义了用户空间对设备进行控制的接口。
三者之间的关系
  • 层次结构:
    • v4l2_device 是最高层次的管理结构,它管理和协调多个 v4l2_subdev(子设备)和 video_device(视频设备节点)。
    • v4l2_subdevv4l2_device 的子结构,代表了具体的硬件组件,如传感器或编解码器。
    • video_device 是用户空间可见的设备节点,通过 v4l2_devicev4l2_subdev 提供的操作接口实现功能。
  • 协作方式:
    • v4l2_subdevv4l2_device 之间的关系类似于子模块与主模块的关系。v4l2_device 负责整体的设备管理,而 v4l2_subdev 提供具体的硬件控制功能。
    • video_device 使用 v4l2_devicev4l2_subdev 提供的操作接口来完成对硬件的操作,并将这些功能暴露给用户空间。

总结来说,v4l2_device 是设备的顶层管理者,v4l2_subdev 代表具体的子设备,而 video_device 则是用户空间与这些设备交互的接口。它们通过明确的层次关系协同工作,共同实现复杂视频设备的管理和操作。

————————————————————————————————————————————

参考文章:

深入学习Linux摄像头(二)v4l2驱动框架-CSDN博客 例子举的很不错

【原创】Linux v4l2框架分析 - LoyenWang - 博客园 (cnblogs.com) 流程图画的很清晰

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Trump. yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值