四川住房建设厅网站增项查询爱站网长尾关键词

当前位置: 首页 > news >正文

四川住房建设厅网站增项查询,爱站网长尾关键词,做个网站 多少钱,做网站约需要多少钱和你一起终身学习#xff0c;这里是程序员Android 经典好文推荐#xff0c;通过阅读本文#xff0c;您将收获以下知识点: 一、概览二、流程简介三、关键结构体四、模块初始化五、处理用户空间请求 一、概览 相机驱动层位于HAL Moudle与硬件层之间#xff0c;借助linux内核驱… 和你一起终身学习这里是程序员Android 经典好文推荐通过阅读本文您将收获以下知识点: 一、概览二、流程简介三、关键结构体四、模块初始化五、处理用户空间请求 一、概览 相机驱动层位于HAL Moudle与硬件层之间借助linux内核驱动框架以文件节点的方式暴露接口给用户空间让HAL Module通过标准的文件访问接口从而能够将请求顺利地下发到内核中而在内核中为了更好的支持视频流的操作早先提出了v4l视频处理框架但是由于操作复杂并且代码无法进行较好的重构难以维护等原因之后便衍生出了v4l2框架。 按照v4l2标准它将一个数据流设备抽象成一个videoX节点从属的子设备都对应着各自的v4l2_subdev实现并且通过media controller进行统一管理整个流程复杂但高效同时代码的扩展性也较高。 而对高通平台而言高通整个内核相机驱动是建立在v4l2框架上的并且对其进行了相应的扩展创建了一个整体相机控制者的CRM它以节点video0暴露给用户空间主要用于管理内核中的Session、Request以及与子设备同时各个子模块都实现了各自的v4l2_subdev设备并且以v4l2_subdev节点暴露给用户空间与此同时高通还创建了另一个video1设备Camera SYNC该设备主要用于同步数据流保证用户空间和内核空间的buffer能够高效得进行传递。 再往下与相机驱动交互的便是整个相机框架的最底层Camera Hardware了驱动部分控制着其上下电逻辑以及寄存器读取时序并按照I2C协议进行与硬件的通信和根据MIPI CSI协议传递数据从而达到控制各个硬件设备并且获取图像数据的目的。 V4L2英文是Video for Linux 2该框架是诞生于Linux系统用于提供一个标准的视频控制框架其中一般默认会嵌入media controller框架中进行统一管理v4l2提供给用户空间操作节点media controller控制对于每一个设备的枚举控制能力于此同时由于v4l2包含了一定数量的子设备而这一系列的子设备都是处于平级关系但是在实际的图像采集过程中子设备之间往往还存在着包含于被包含的关系所以为了维护并管理这种关系media controller针对多个子设备建立了的一个拓扑图数据流也就按照这个拓扑图进行流转。 二、流程简介 整个对于v4l2的操作主要包含了如下几个主要流程 程序员Android 转于网络 a) 打开video设备在需要进行视频数据流的操作之前首先要通过标准的字符设备操作接口open方法来打开一个video设备并且将返回的字符句柄存在本地之后的一系列操作都是基于该句柄而在打开的过程中会去给每一个子设备的上电并完成各自的一系列初始化操作。 b) 查看并设置设备在打开设备获取其文件句柄之后就需要查询设备的属性该动作主要通过ioctl传入VIDIOC_QUERYCAP参数来完成其中该系列属性通过v4l2_capability结构体来表达除此之外还可以通过传入VIDIOC_ENUM_FMT来枚举支持的数据格式通过传入VIDIOC_G_FMT/VIDIOC_S_FMT来分别获取和获取当前的数据格式通过传入VIDIOC_G_PARM/VIDIOC_S_PARM来分别获取和设置参数。 c) 申请帧缓冲区完成设备的配置之后便可以开始向设备申请多个用于盛装图像数据的帧缓冲区该动作通过调用ioctl并且传入VIDIOC_REQBUFS命令来完成最后将缓冲区通过mmap方式映射到用户空间。 d) 将帧缓冲区入队申请好帧缓冲区之后通过调用ioctl方法传入VIDIOC_QBUF命令来将帧缓冲区加入到v4l2 框架中的缓冲区队列中静等硬件模块将图像数据填充到缓冲区中。 e) 开启数据流将所有的缓冲区都加入队列中之后便可以调用ioctl并且传入VIDIOC_STREAMON命令来通知整个框架开始进行数据传输其中大致包括了通知各个子设备开始进行工作最终将数据填充到V4L2框架中的缓冲区队列中。 f) 将帧缓冲区出队一旦数据流开始进行流转了我们就可以通过调用ioctl下发VIDIOC_DQBUF命令来获取帧缓冲区并且将缓冲区的图像数据取出进行预览、拍照或者录像的处理处理完成之后需要将此次缓冲区再次放入V4L2框架中的队列中等待下次的图像数据的填充。 整个采集图像数据的流程现在看来还是比较简单的接口的控制逻辑很清晰主要原因是为了提供给用户的接口简单而且抽象这样方便用户进行集成开发其中的大部分复杂的业务处理都被V4L2很好的封装了接下来我们来详细了解下V4L2框架内部是如何表达以及如何运转的。 三、关键结构体 程序员Android 转于网络 从上图不难看出v4l2_device作为顶层管理者一方面通过嵌入到一个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框架都是围绕着以上几个主要结构体来进行的接下来我们依次简单介绍下v4l2_device 源码如下 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。 v4l2_subdev源码如下 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变量中。 video_device源码如下 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来描述。 media_device源码如下: 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按照一定的顺序连接起来实现了数据流向的整体控制。 vb2_queue源码如下 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。 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中来实现枚举、连接子设备同时控制数据流走向的目的。 四、模块初始化 整个v4l2框架是在linux内核中实现的所以按照内核驱动的运行机制会在系统启动的过程中通过标准的module_init方式进行初始化操作而其初始化主要包含两个方面一个是v4l2_device的初始化一个是子设备的初始化首先我们来看下v4l2_device的初始化动作的基本流程。 由于驱动的实现都交由各个平台厂商进行实现所有内部逻辑都各不相同这里我们抽离出主要方法来进行梳理 首先对于v4l2_device的初始化而言在系统启动的过程中linux内核会找到module_init声明的驱动调用其probe方法进行探测相应设备一旦探测成功便表示初始化工作完成。 而在probe方法内部主要做了以下操作 获取dts硬件信息初始化部分硬件设备。创建v4l2_device结构体填充信息通过v4l2_device_register方法向系统注册并且创建video设备节点。创建media_device结构体填充信息通过media_device_register向系统注册并创建media设备节点并将其赋值给v4l2_device中的mdev。创建v4l2_device的media_entity,并将其添加到media controller进行管理。 类似于v4l2_device的初始化工作子设备的流程如下 获取dts硬件信息初始化子设备硬件模块创建v4l2_subdev结构体填充信息通过v4l2_device_register_subdev向系统注册并将其挂载到v4l2_device设备中创建对应的media_entity并通过media_device_register_entity方法其添加到media controller中进行统一管理。最后调用v4l2_device_register_subdev_nodes方法为所有的设置了V4L2_SUBDEV_FL_HAS_DEVNODE属性的子设备创建设备节点。 五、处理用户空间请求 系统启动之后初始化工作便已经完成现在一旦用户想要使用图像采集功能便会触发整个视频采集流程会通过操作相应的video节点来获取图像数据一般来讲标准的V4L2框架只需要通过操作video节点即可但是由于现在的硬件功能越来越复杂常规的v4l2_controller已经满足不了采集需求所以现在的平台厂商通常会暴露子设备的设备节点在用户空间直接通过标准的字符设备控制接口来控制各个设备而现在我们的目的是梳理V4L2框架所以暂时默认不创建子设备节点简单介绍下整个流程。 在操作之前还有一个准备工作需要做那就是需要找到哪些是我们所需要的设备而它的设备节点是什么此时便可以通过打开media设备节点并且通过ioctl注入MEDIA_IOC_ENUM_ENTITIES参数来获取v4l2_device下的video设备节点该操作会调用到内核中的media_device_ioctl方法而之后根据传入的命令进而调用到media_device_enum_entities方法来枚举所有的设备。 整个采集流程主要使用三个标准字符设备接口来完成分别是用于打开设备的open方法、用于控制设备的ioctl方法以及关闭设备的close方法。 1. 打开设备(open) 一旦确认了我们需要操作的video节点是哪一个便可以通过调用字符设备标准接口open方法来打开设备而这个方法会首先陷入内核空间然后调用file_operations中的open方法再到v4l2_file_operations中的open方法而该方法由驱动自己进行实现其中主要包括了给各个硬件模块上电并且调用vb2_queue_init方法创建并初始化一个vb2_queue用于数据缓冲区的管理。 2. 控制设备(ioctl) 在打开设备之后接下来的大部分操作都是通过ioctl方法来完成的而在该方法中会首先陷入到内核空间之后调用字符设备的v4l2_fops中的v4l2_ioctl方法而在该方法中又会去调用video_device的video_ioctl2方法video_ioctl2方法定义了一系列video标准的方法通过不同的命令在v4l2_ioctls中找到相应的标准方法实现同时为了满足用户自定义命令的实现在video_ioctl2方法中会去调用到之前注册video_device时赋予的ioctl_ops中的vidioc_default方法在该方法中加入用户自己的控制逻辑。 在整个控制流程中首先通过命令VIDIOC_QUERYCAP来获取设备所具有的属性通过VIDIOC_G_PARM/VIDIOC_S_PARM来分别获取和设置设备参数在这一系列操作配置完成之后便需要向内核申请用于数据流转的缓冲区(Buffer)该操作通过命令VIDIOC_REQBUFS来完成在内核部分主要调用了标准方法vb2_reqbufs进而调用vb2_queue_alloc来向内核申请已知个数的Buffer并且将其存入之前创建的vb2_queue中进行管理。 申请好了Buffer之后便可以通过传入VIDIOC_QBUF命令将申请的Buffer入队具体操作最终会调用vb2_qbuf方法而在该方法中会从vb2_queue的bufs数组中取出Buffer将其加入queued_list链表中并且更新Buffer状态等待数据的填充或者来自用户空间的出队操作。 在完成上面的操作后整个数据流并没有开始流转起来所以需要下发VIDIOC_STREAMON命令来通知整个框架开始出数据在驱动中主要会去调用vb2_streamon方法进而调用vb2_start_streaming方法其中该方法会去将队列中的的Buffer放入到相应的驱动中等待被填充紧接着会去调用vb2_queue.ops.start_streaming方法来通知设备开始出图而该方法一般由驱动自己实现最后会调用v4l2_subdev_call(subdev, video, s_stream, mode)方法通知各个子设备开始出图。 当有图像产生时会填充到之前传入的buffe中并且调用vb2_buffer_done方法通知vb2_queue将buffer加入到done_list链表中并更新状态为VB2_BUF_STATE_DONE。 在整个数据流开启之后并不会自动的将图像传入用户空间必须通过VIDIOC_DQBUF命令来从设备中读取一个帧图像数据具体操作是通过层层调用会调用到vb2_dqbuf方法而在该方法中会调用vb2_get_done_vb方法去从done_list中获取Buffer如果当前链表为空则会等待最终数据准备好如果有准备好的buffer便直接从done_list取出并且将其从queued_list中去掉最后通过__vb2_dqbuf方法将Buffer返回用户空间。 获取到图像数据之后便可以进行后期的图像处理流程了在处理完成之后需要下发VIDIOC_QBUF将此次buffer重新加入queued_list中等待下一次的数据的填充和出队操作。 但不需要进行图像的采集时可以通过下发VIDIOC_STREAMOFF命令来停止整个流程具体流程首先会调用v4l2_subdev_call(subdev, video, s_stream, 0)通知所有子设备停止出图操作其次调用vb2_buffer_done唤醒可能的等待Buffer的线程同时更新Buffer状态为VB2_BUF_STATE_ERROR然后调用vb2_streamoff取消所有的数据流并更新vb2_queue.streaming的为disable状态。 3. 关闭设备(close) 但确认不使用当前设备进行图像采集操作之后便可以调用标准方法close来关闭设备。其中主要包括了调用vb2_queue_release方法释放了vb2_queue以及设备下电操作和相关资源的释放。 通过上面的介绍我相信我们已经对整个V4L2框架有了一个比较深入的认识 然而对于一个优秀的软件架构而言仅仅是支持现有的功能是远远不够的随着功能的不断完善势必会出现需要进行扩展的地方而v4l2在设计之初便很好的考虑到了这一点所以提供了用于扩展的方法集开发者可以通过加入自定的命令来扩充整个框架高通在这一点上做的非常好在v4l2框架基础上设计出了一个独特的KMD框架提供给UMD CSL进行访问的接口。 原文链接https://blog.csdn.net/u012596975/article/details/107137555 【腾讯文档】Camera学习知识库https://docs.qq.com/doc/DSWZ6dUlNemtUWndv 友情推荐 Android 开发干货集锦 至此本篇已结束。转载网络的文章小编觉得很优秀欢迎点击阅读原文支持原创作者如有侵权恳请联系小编删除欢迎您的建议与指正。同时期待您的关注感谢您的阅读谢谢 点击阅读原文为大佬点赞