V4L2-框架

article/2025/9/29 16:10:12

1.概述

V4L2 是专门为linux 设备设计的一套视频框架,其主体框架在linux内核,可以理解为是整个linux系统上面的视频源捕获驱动框架。
相机驱动层位于HAL Moudle 与硬件层之间,借助linux 内核驱动框架,以文件节点的方式暴露接口给用户空间,让hal Module 通过标准的文件访问接口,从而能够将请求顺利下发到内核中。
在这里插入图片描述

按照v4l2标准,他将一个数据流设备抽象成一个videoX节点,从属的子设备都对应着各自的v4l2_subdev实现,并且通过media controller 进行统一管理,整个流程复杂但高效。
而对高通平台而言,高通整个内核相机驱动是建立在v4l2框架上的,并且对其进行了相应的扩展,创建了一个整体相机控制者的CRM,它以节点video0暴露给用户空间,主要用于管理内核中的Session、Request以及与子设备,同时各个子模块都实现了各自的v4l2_subdev设备,并且以v4l2_subdev节点暴露给用户空间,与此同时,高通还创建了另一个video1设备Camera SYNC,该设备主要用于同步数据流,保证用户空间和内核空间的buffer能够高效得进行传递。

2.v4l2框架编写一个摄像头采集程序的流程

1.打开video 设备
在需要进行视频数据流的操作之前,首先要通过标准的字符设备操作接口open方法来打开一个video设备,并且将返回的字符句柄存在本地,之后的一系列操作都是基于该句柄,而在打开的过程中,会去给每一个子设备的上电,并完成各自的一系列初始化操作。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
…
int camera_fd;
camera_fd = open("/dev/video0", O_RDWR); // 阻塞打开
…
camera_fd = open("/dev/video0", O_RDWR | O_NONBLOCK); // 非阻塞打开`

2.查看并设置设备VIDIOC_QUERYCAP
在打开设备获取其文件句柄之后,就需要查询设备的属性,该动作主要通过ioctl传入VIDIOC_QUERYCAP参数来完成,其中该系列属性通过v4l2_capability结构体来表达

#include <sys/ioctl.h>
#include <linux/videodev2.h>
…
struct v4l2_capability cap = {0};
int ret = ioctl(camera_fd, VIDIOC_QUERYCAP, & capability);
…
// 判断是否支持某些功能
if(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
printf(“v4l2 device support video capture\n”);
if(cap.capabilities & V4L2_CAP_VIDEO_OUTPUT)
printf(“v4l2 device support video output\n”);

3.判断是否支持捕获功能 V4L2_CAP_VIDEO_CAPTURE
4.VIDIOC_ENUM_FMT来枚举支持的数据格式

#include <sys/ioctl.h>
#include <linux/videodev2.h>
struct v4l2_fmtdesc fmtdesc = {0};
…
// 获取支持的像素格式
while (!ioctl(camera_fd, VIDIOC_ENUM_FMT, &fmtdesc)) {undefined
printf(“fmt: %s\n”, fmtdesc.description);
fmtdesc.index++;
}
…

5.VIDIOC_G_FMT/VIDIOC_S_FMT来分别获取和获取当前的数据格式,通过传入VIDIOC_G_PARM/VIDIOC_S_PARM来分别获取和设置参数。
6.申请帧缓冲区VIDIOC_REQBUFS
完成设备的配置之后,便可以开始向设备申请多个用于盛装图像数据的帧缓冲区,该动作通过调用ioctl并且传入VIDIOC_REQBUFS命令来完成,最后将缓冲区通过mmap方式映射到用户空间。
7.将帧缓冲区入队VIDIOC_QBUF
申请好帧缓冲区之后,通过调用ioctl方法传入VIDIOC_QBUF命令来将帧缓冲区加入到v4l2 框架中的缓冲区队列中,静等硬件模块将图像数据填充到缓冲区中。
8.开启数据流VIDIOC_STREAMON
将所有的缓冲区都加入队列中之后便可以调用ioctl并且传入VIDIOC_STREAMON命令,来通知整个框架开始进行数据传输,其中大致包括了通知各个子设备开始进行工作,最终将数据填充到V4L2框架中的缓冲区队列中。

#include <sys/ioctl.h>
#include <linux/videodev2.h>
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
…
ret = ioctl(camera_fd, VIDIOC_STREAMON, &type);

9.将帧缓冲区出队VIDIOC_DQBUF
一旦数据流开始进行流转了,我们就可以通过调用ioctl下发VIDIOC_DQBUF命令来获取帧缓冲区,并且将缓冲区的图像数据取出,进行预览、拍照或者录像的处理,处理完成之后,需要将此次缓冲区再次放入V4L2框架中的队列中等待下次的图像数据的填充。
查看并设置设备

#include <sys/ioctl.h>
#include <linux/videodev2.h>
void* data = NULL;
size_t length = 0;
struct v4l2_buffer v4l2_buf = {0};
for (;😉 {undefined
ret = ioctl(camera_fd, VIDIOC_QBUF, &v4l2_buf); // 从环形队列中获取一个缓冲区
…
data = buf[v4l2_buf.index].start; // 缓冲区地址
length = buf[v4l2_buf.index].length // 缓冲区数据长度
…
ret = ioctl(camera_fd, VIDIOC_QBUF, &v4l2_buf); // 将缓冲区放入环形队列中
…
}

10.关闭数据流VIDIOC_STREAMOFF

#include <sys/ioctl.h>
#include <linux/videodev2.h>
…
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(camera_fd, VIDIOC_STREAMOFF, &type);

在这里插入图片描述

流程如下图:
在这里插入图片描述

整个采集图像数据的流程现在看来还是比较简单的,接口的控制逻辑很清晰,主要原因是为了提供给用户的接口简单而且抽象,这样方便用户进行集成开发,其中的大部分复杂的业务处理都被V4L2很好的封装了,接下来我们来详细了解下V4L2框架内部是如何表达以及如何运转的。

3.V4L2关键结构体

在这里插入图片描述
从上图不难看出,v4l2_device作为顶层管理者,v4l2 框架的入口

  • 一方面通过嵌入到一个video_device中,暴露video设备节点给用户空间进行控制
  • 另一方面,video_device内部会创建一个media_entity作为在media controller中的抽象体,被加入到media_device中的entitie链表中
  • 此外,为了保持对所从属子设备的控制,内部还维护了一个挂载了所有子设备的subdevs链表

而对于其中每一个子设备而言,统一采用了v4l2_subdev结构体来进行描述

  • 一方面通过嵌入到video_device,暴露v4l2_subdev子设备节点给用户空间进行控制
  • 另一方面其内部也维护着在media controller中的对应的一个media_entity抽象体,而该抽象体也会链入到media_device中的entities链表中。
  • 通过加入entities链表的方式,media_device保持了对所有的设备信息的查询和控制的能力,而该能力会通过media controller框架在用户空间创建meida设备节点,将这种能力暴露给用户进行控制。

由此可见,V4L2框架都是围绕着以上几个主要结构体来进行的,接下来我们依次简单介

3.1 v4l2_device

kernel/msm-4.19/include/media/v4l2-device.h
struct v4l2_device {struct device *dev;
#if defined(CONFIG_MEDIA_CONTROLLER)struct media_device *mdev;                                                                                                                         
#endifstruct 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);
};

该结构体代表了一个整个V4L2设备,作为整个V4L2的顶层管理者,内部通过一个链表管理着整个从属的所有的子设备,并且如果将整个框架放入media conntroller进行管理,便在初始化的时候需要将创建成功的media_device赋值给内部变量 mdev,这样便建立了于与media_device的联系,驱动通过调用v4l2_device_register方法和v4l2_device_unregister方法分别向系统注册和释放一个v4l2_device。

3.2 v4l2_subdev

kernel/msm-4.19/include/media/v4l2-subdev.h
struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER)struct media_entity entity;
#endifstruct 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;
};

该结构体代表了一个子设备,每一个子设备都需要在初始化的时候挂载到一个总的v4l2_device上,并且将该v4l2设备赋值给内部的v4l2_dev变量,之后将自身加入到v4l2_device中的子设备链表中进行统一管理,这种方式提高了遍历访问所有子设备的效率,同时为了表达不同硬件模块的特殊操作行为,v4l2_subdev定义了一个v4l2_subdev_ops 结构体来进行定义,其实现交由不同的硬件模块来具体完成。其中如果使能了CONFIG_MEDIA_CONTROLLER宏,便会在media_controller中生成一个对应的media_entity,来代表该子设备,而该entity便会存入子设备结构体中的entity变量中,最后,如果需要创建一个设备节点的话,通过video_device调用标准API接口进行实现,而相应的video_device便会存入其内部devnode变量中。

3.3 video_device

kernel/msm-4.19/include/media/v4l2-dev.h
struct video_device
{
#if defined(CONFIG_MEDIA_CONTROLLER)struct media_entity entity;struct media_intf_devnode *intf_devnode;struct media_pipeline pipe;
#endifconst 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];int vfl_type;int 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);DECLARE_BITMAP(disable_locking, BASE_VIDIOC_PRIVATE);struct mutex *lock;
};

如果需要给v4l2_device或者v4l2_subdev在系统中创建节点的话,便需要实现该结构体,并且通过video_register_device方法进行创建,而其中的fops便是video_device所对应的操作方法集,在v4l2框架内部,会将video_device嵌入到一个具有特定主设备号的字符设备中,而其方法集会在操作节点时被调用到。除了这些标准的操作集外,还定义了一系列的ioctl操作集,通过内部ioctl_ops来描述。

3.4 media_device

kernel/msm-4.19/include/media/media-device.h
struct media_device {/* dev->driver_data points to this struct. */struct device *dev;struct media_devnode *devnode;char model[32];char driver_name[32];char serial[40];char bus_info[32];u32 hw_revision;u64 topology_version;u32 id;struct ida entity_internal_idx;int entity_internal_idx_max;struct list_head entities;struct list_head interfaces;struct list_head pads;struct list_head links;/* notify callback list invoked when a new entity is registered */struct list_head entity_notify;/* Serializes graph operations. */struct mutex graph_mutex;struct media_graph pm_count_walk;void *source_priv;int (*enable_source)(struct media_entity *entity,struct media_pipeline *pipe);void (*disable_source)(struct media_entity *entity);const struct media_device_ops *ops;
};

如果使能了CONFIG_MEDIA_CONTROLLER宏,则当v4l2_device初始化的过程中便会去创建一个media_device,而这个media_device便是整个media controller的抽象管理者,每一个v4l2设备以及从属的子设备都会对应的各自的entity,并且将其存入media_device中进行统一管理,与其它抽象设备一样,media_device也具有自身的行为,比如用户可以通过访问media节点,枚举出所有的从属于同一个v4l2_device的子设备,另外,在开启数据流的时候,media_device通过将各个media_entity按照一定的顺序连接起来,实现了数据流向的整体控制。

3.5 vb2_queue

kernel/msm-4.19/include/media/videobuf2-core.h
struct vb2_queue {unsigned int            type;unsigned int            io_modes;struct device           *dev;unsigned long           dma_attrs;unsigned            bidirectional:1;unsigned            fileio_read_once:1;unsigned            fileio_write_immediately:1;unsigned            allow_zero_bytesused:1;unsigned           quirk_poll_must_check_waiting_for_buffers:1;struct mutex            *lock;void                *owner;const struct vb2_ops        *ops;const struct vb2_mem_ops    *mem_ops;const struct vb2_buf_ops    *buf_ops;void                *drv_priv;unsigned int            buf_struct_size;u32             timestamp_flags;gfp_t               gfp_flags;u32             min_buffers_needed;/* private: internal use only */struct mutex            mmap_lock;unsigned int            memory;enum dma_data_direction     dma_dir;struct vb2_buffer       *bufs[VB2_MAX_FRAME];unsigned int            num_buffers;struct list_head        queued_list;unsigned int            queued_count;atomic_t            owned_by_drv_count;struct list_head        done_list;spinlock_t          done_lock;wait_queue_head_t       done_wq;struct device           *alloc_devs[VB2_MAX_PLANES];unsigned int            streaming:1;unsigned int            start_streaming_called:1;unsigned int            error:1;unsigned int            waiting_for_buffers:1;unsigned int            is_multiplanar:1;unsigned int            is_output:1;unsigned int            copy_timestamp:1;unsigned int            last_buffer_dequeued:1;struct vb2_fileio_data      *fileio;struct vb2_threadio_data    *threadio;#ifdef CONFIG_VIDEO_ADV_DEBUG/** Counters for how often these queue-related ops are* called. Used to check for unbalanced ops.*/u32             cnt_queue_setup;u32             cnt_wait_prepare;u32             cnt_wait_finish;u32             cnt_start_streaming;u32             cnt_stop_streaming;
#endif
};

在整个V4L2框架运转过程中,最为核心的是图像数据缓冲区的管理,而这个管理工作便是由vb2_queue来完成的,vb2_queue通常在打开设备的时候被创建,其结构体中的vb2_ops可以由驱动自己进行实现,而vb2_mem_ops代表了内存分配的方法集,另外,还有一个用于将管理用户空间和内核空间的相互传递的方法集buf_ops,而该方法集一般都定义为v4l2_buf_ops这一标准方法集。除了这些方法集外,vb2_queue还通过一个vb2_buffer的数组来管理申请的所有数据缓冲区,并且通过queued_list来管理入队状态的所有buffer,通过done_list来管理被填充了数据等待消费的所有buffer。

3.6 vb2_buffer

struct vb2_buffer {struct vb2_queue    *vb2_queue;unsigned int        index;unsigned int        type;unsigned int        memory;unsigned int        num_planes;struct vb2_plane    planes[VB2_MAX_PLANES];u64         timestamp;/* private: internal use only** state:       current buffer state; do not change* queued_entry:    entry on the queued buffers list, which holds*          all buffers queued from userspace* done_entry:      entry on the list that stores all buffers ready*          to be dequeued to userspace*/enum vb2_buffer_state   state;struct list_head    queued_entry;struct list_head    done_entry;
};

该结构体代表了V4L2框架中的图像缓冲区,当处于入队状态时内部queued_entry会被链接到vb2_queue中的queued_list中,当处于等待消费的状态时其内部done_entry会被链接到vb2_queue 中的done_list中,而其中的vb2_queue便是该缓冲区的管理者

以上便是V4L2框架的几个核心结构体,从上面的简单分析不难看出,v4l2_device作为一个相机内核体系的顶层管理者,内部使用一个链表控制着所有从属子设备v4l2_subdev,使用vb2_queue来申请并管理所有数据缓冲区,并且通过video_device向用户空间暴露设备节点以及控制接口,接收来自用户空间的控制指令,通过将自身嵌入media controller中来实现枚举、连接子设备同时控制数据流走向的目的。


http://chatgpt.dhexx.cn/article/uhbvX6ZI.shtml

相关文章

V4L2学习笔记

首先附上&#xff0c;Linux内核网站&#xff1a; 入口 v4l2非常棒的一篇文章 入口 内核代码查看&#xff1a; 入口 一个博客文档&#xff1a; 入口 https://lwn.net/Articles/204545/ 别人整理 关于linux内核头函数&#xff1a; /usr/src/xxx 系列文 在其内部有media文件…

V4L2框架学习

V4L2框架 0 查看videodev2 0.1 头文件/usr/include/linux/videodev2.h 0.2 使用ioctl函数 使用ioctl函数 // 添加头文件 #include <unistd.h> #include <sys/ioctl.h> #include <linux/videodev2.h>int ioctl (int __fd, unsigned long int __request, ...…

V4L2介绍

V4L2介绍 V4L2介绍主要功能框架v4L2编程 V4L2介绍 V4L2是Video for linux2的简称,为linux中关于视频设备的内核驱动。在Linux中&#xff0c;视频设备是设备文件&#xff0c;可以像访问普通文件一样对其进行读写&#xff0c;摄像头在/dev/video*下&#xff0c;如果只有一个视频…

linux V4L2子系统——v4l2架构(7)之V4L2应用编程

linux V4L2子系统——v4l2架构&#xff08;7&#xff09;之V4L2应用编程 备注&#xff1a;   1. Kernel版本&#xff1a;5.4   2. 使用工具&#xff1a;Source Insight 4.0   3. 参考博客&#xff1a; &#xff08;1&#xff09;Linux V4L2子系统-应用层访问video设备&a…

[2022.8.15]v4l2-ctl基本使用方法

v4l2-ctl使用帮助可以参考&#xff1a;https://www.mankier.com/1/v4l2-ctl 1 v4l2-ctl --list-devices 列出所有设备 USB 2.0 Camera: USB Camera (usb-0000:00:14.0-9):/dev/video0/dev/video1 一个USB camera对应两个设备&#xff1a;一个是图像/视频采集&#xff0c;一…

V4L2应用层分析

V4L2应用层分析 一、总述二、例子 一、总述 V4L2&#xff0c;即Video for Linux 2&#xff0c;是第二代为Linux打造的音频、视频驱动。相比第一代V4L&#xff0c;V4L2支持更多的设备&#xff0c;同时更加稳定。现今的视频设备&#xff0c;如USB摄像头&#xff0c;基本都支持V4…

v4l2数据结构分析

v4l2数据结构分析 文章目录 v4l2数据结构分析Video4Linux2设备v4l2_device媒体设备media_deviceVideo4Linux2子设备v4l2_subdevVideo4Linux2子设备的操作集v4l2_subdev_opsVideo4Linux2子设备的内部操作集v4l2_subdev_internal_opsVideo4Linux2控制处理器v4l2_ctrl_handlerVide…

摄像头V4L2编程应用开发

1.V4L2简介 Video for Linux two(Video4Linux2)简称V4L2&#xff0c;是V4L的改进版。V4L2是linux系统操作系统下一套用于采集图片、视频、和音视频数据的通用API接口&#xff0c;配合适当的视频采集设备和相应的驱动程序&#xff0c;可以实现图片、视频、音频等的采集。 在linu…

V4L2框架

前言 在分析v4l2之前最好具有的知识&#xff1a; 1.字符设备,因为v4l2是被枚举为字符设备。 2.内存分配和映射,比如相关数据结构的分配和buffer。 3.DMA&#xff0c;因为v4l2的数据传输用到了DMA。 4.I2C&#xff0c;因为很多传感器都是用的i2c接口。 5.文件系统的基本操作&am…

V4L2系列 之 V4L2驱动框架

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

V4L2框架概述

原文链接 本文开启 linux 内核 V4L2 框架部分的学习之旅&#xff0c;本文仅先对 V4L2 的框架做一个综述性的概括介绍&#xff0c;然后接下来的文章中会对 V4L2 框架的各个子模块进行一个全面的介绍&#xff0c;包括每一部分的实现原理&#xff0c;如何使用&#xff0c;用在什么…

V4l2框架分析

Table of Contents 1.V4L2框架概述 1.1 v4l2设备应用层流程 1.2 内核V4L2模块 1.2.1 video_device 1.2.2 v4l2_subdev 1.2.3 videobuf2 2. video_device结构体 2.1 图像处理模块 2.2 video_device处理流程 2.2.1 video_device 结构体成员介绍: 3. video_buf2 3.1 …

V4L2

V4L2(video 4 linux 2) V4L2有一段历史了。大约在1998的秋天&#xff0c;它的光芒第一次出现在Bill Dirks 的眼中。经过长足的发展&#xff0c;它于2002年11 月&#xff0c;发布2.5.46 时&#xff0c;融入了内核主干之中。然而直到今天&#xff0c;仍有一部分内核驱不支持新的A…

V4L2简介

http://work-blog.readthedocs.org/en/latest/v4l2%20intro.html 第一章 V4L2简介 1.1、什么是v4l2 V4L2&#xff08;Video4Linux的缩写&#xff09;是Linux下关于视频采集相关设备的驱动框架&#xff0c;为驱动和应用程序提供了一套统一的接口规范。 V4L2支持的设备十分广泛&…

我们一起学linux之V4L2摄像头应用流程

一、概述 Video for Linuxtwo(Video4Linux2)简称V4L2&#xff0c;是V4L的改进版。V4L2是linux操作系统下用于采集图片、视频和音频数据的API接口&#xff0c;配合适当的视频采集设备和相应的驱动程序&#xff0c;可以实现图片、视频、音频等的采集。在远程会议、可视电话、视频…

深入学习Linux摄像头(一)v4l2应用编程

深入学习Linux摄像头&#xff08;一&#xff09;v4l2应用编程 一、什么是v4l2 二、v4l2 API介绍 2.1 Querying Capabilities 2.2 Application Priority 2.3 Device Inputs and Outputs 2.4 Video Standards 2.5 Camera Control Reference 2.6 Image Format 2.7 Cropping, compo…

V4L2驱动框架详解

1. V4L2框架概述 1.1 v4l2设备应用层流程 1.2 内核V4L2模块 2 2. video_device 2.1图像处理模块 2.2 video注册流程 3. videobuf2 3.1 与video device的关系: 3.2 buffer类型 3.3 vb2_ops回调函数 3.4 mmap 流程 4. Subdev 4.1 概念 4.2 subdev注册流程 5. media fra…

html背景自动适应,css背景图片如何自适应?

css可以使用background-size属性设置背景图片自适应&#xff0c;为背景图片设置background-size:cover;样式即可使背景图片自适应。 css可以使用background-size属性设置背景图片自适应。background-size属性规定背景图像的尺寸。 background-size属性&#xff1a; 语法&#x…

css实现图片自适应容器的几种方式

css实现图片自适应容器 经常有这样一个场景,需要让图片自适应容器的大小。 1、img标签的方式 我们马上就能想到,把width、height 设置为100%啊。来看一哈效果。 <div class=div1><img src="./peiqi.png" alt=""> </div>.div1 {widt…