V4L2-框架

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://xiahunao.cn/news/1383387.html

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

相关文章

vue2(2)

目录 天气案例 监视属性watch 深度监视 监视简写属性 watch对比computed 绑定class样式 条件渲染 列表渲染 天气案例 绑定事件的时候&#xff0c;xxx"yyy" yyy可以写一些简单的语句 <!DOCTYPE html> <html lang"en"> <head>…

积分代换和周期函数

昨晚上看书&#xff0c;有一个稳定随机过程的例题&#xff0c;涉及积分上下限代换、周期函数的微积分性质等知识点。这种题型以前肯定接触过&#xff0c;当下遇到了&#xff0c;思维仍然迷迷糊糊&#xff0c;像是一团乱麻&#xff0c;纠缠不清&#xff0c;照着答案思考了半天&a…

BOE(京东方)赋能荣耀Magic V2系列新品

7月12日&#xff0c;在荣耀举办的全场景新品发布会上&#xff0c;重磅推出了“革命性”折叠旗舰Magic V2系列以及首款MagicPad平板产品&#xff0c;荣耀Magic V2系列搭载BOE&#xff08;京东方&#xff09;全新一代柔性OLED折叠屏解决方案&#xff0c;以超强硬件护眼防护、超清…

开源数据库 就是免费 ,我白嫖我光荣 荣耀V2

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

荣耀Magic V2折叠旗舰发布,内外双屏均支持手写笔

7月12日&#xff0c;荣耀全新一代折叠旗舰荣耀Magic V2正式发布。通过深入洞察消费者需求&#xff0c;根植于强大的技术研发实力&#xff0c;荣耀以打破边界的思维创新重新定义折叠屏手机&#xff0c;荣耀MagicV2系列实现了9.9mm的闭合态厚度&#xff0c;引领折叠屏手机进入毫米…

sip语音对讲终端怎么样?

sip语音对讲终端怎么样&#xff1f; IP语音对讲终端是一种通过网络进行语音通信的设备&#xff0c;具有以下特点&#xff1a; 1. 便捷性&#xff1a;IP语音对讲终端可以通过互联网实现远程通信&#xff0c;用户可在任何地点与他人进行语音交流&#xff0c;无需受到距离的限制…

IDEA提示:StringBuffer xxx‘ may be declared as ‘StringBuilde

如图所示&#xff0c;编写代码时遇见了如下IDEA警告&#xff1a; 原因&#xff1a;StringBuilder是线程不安全的&#xff0c;但是其效率高&#xff0c;而StringBuffer则相反&#xff0c;虽然其线程安全&#xff0c;但是效率低下。 由于 StringBuilder 相较于 StringBuffer 有速…

jenkins自动化构建保姆级教程(持续更新中)

1.安装 1.1版本说明 访问jenkins官网 https://www.jenkins.io/&#xff0c;进入到首页 点击【Download】按钮进入到jenkins下载界面 左侧显示的是最新的长期支持版本&#xff0c;右侧显示的是最新的可测试版本&#xff08;可能不稳定&#xff09;&#xff0c;建议使用最新的…

【Linux】Reactor模式

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《学会Linux》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录 &#x1f449;Reactor …

如何练习打字/盲打(作者的感想与建议)

18年12月底的时候还不会盲打&#xff0c;在阅读了一些关于练习打字的文章之后&#xff0c;开始了自己的练字路途 打字会‘上瘾’&#xff01;在练习过程中一定要注意劳逸结合 一些基础的准备 typingclub https://www.typingclub.com/ typingclub是在线练习的网站 里面的图形…

使用metalink下载文件——以Sentinel-1数据为例

1、下载aria2&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1cqTBtKgmi3CGHkPl9pHfNw?pwd01g5 提取码&#xff1a;01g5 2、软件进行解压&#xff0c;进入ASF官网选取要下载的数据&#xff1a; 点击右下角“metalink”文件 3、将该文件放入aria2安装包内&#xff0c;…

文件(图片)上传下载(项目必备)

引入upload.html文件&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&quo…

[转]TLM通信

一、概述 在芯片开发流程中&#xff0c;系统原型和芯片验证对项目的助推起到了关键作用。系统原型一般是通过硬件功能描述文档来模拟硬件行为&#xff0c;而行为要求不同于RTL模型。系统原型可以提供一个准确到硬件比特级别、按照地址段访问、不依赖于时钟周期的模型&#xff…

TLM通信(transaction level modle)

一、概述 在芯片开发流程中&#xff0c;系统原型和芯片验证对项目的助推起到了关键作用。系统原型一般是通过硬件功能描述文档来模拟硬件行为&#xff0c;而行为要求不同于RTL模型。系统原型可以提供一个准确到硬件比特级别、按照地址段访问、不依赖于时钟周期的模型&#xff…

TLM通信

一、概述 在芯片开发流程中&#xff0c;系统原型和芯片验证对项目的助推起到了关键作用。系统原型一般是通过硬件功能描述文档来模拟硬件行为&#xff0c;而行为要求不同于RTL模型。系统原型可以提供一个准确到硬件比特级别、按照地址段访问、不依赖于时钟周期的模型&#xff…

Typora如何把图片上传到图床smms.app

Typora 下载地址&#xff1a;百度云 官方下载 PicGo 下载地址&#xff1a;百度云 官方下载 免费图床 smms.app 访问地址&#xff1a;https://smms.app/ 用Typora平时做笔记挺好用&#xff0c;但是插入图片后&#xff0c;在公司保存好的md文件拿到家里的电脑打开的时候&a…

HM和VTM的下载与安装

一、HM安装及使用 1.下载HM 需要手动cmake&#xff1a; jvet / HM GitLab (fraunhofer.de) &#xff08;建议&#xff09;直接下载包含解决方案的代码&#xff08;用SVN下载&#xff09; svn_HEVCSoftware - Revision 4998: /tags (fraunhofer.de) SVN下载界面如下图&…

【雕爷学编程】Arduino动手做(09)---火焰传感器模块3

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

mybatis-plus逻辑删除的坑

一旦在逻辑字段上加了TableLogic逻辑删除的配置&#xff0c;并且使用mybatis-plus自带的方法时&#xff08;如果自己用xml写SQL不会出现下面的情况&#xff09; 查询、修改时会自动排除逻辑删除的数据 当使用mybatis-plus自带的查询方法时&#xff0c;就不用每次查询的时候跟…

在Linux,误删磁盘分区怎么恢复呢【转】

在我们运维工作中&#xff0c;频繁的操作&#xff0c;可能命令写入错误&#xff0c;造成磁盘分区的删除&#xff0c;那么应该怎么办呢&#xff1f;怎么恢复磁盘分区呢&#xff1f; 一不小心删除了磁盘分区。如下图&#xff0c;删除了sda磁盘的第一个分区&#xff0c;为系统boot…