【原创】Linux v4l2框架分析

背景

  • Read the fucking source code! –By 鲁迅
  • A picture is worth a thousand words. –By 高尔基

说明:

  1. Kernel版本:4.14
  2. ARM64处理器,Contex-A53,双核
  3. 使用工具:Source Insight 3.5, Visio

  4. 概述

  5. V4L2(Video for Linux 2):Linux内核中关于视频设备驱动的框架,对上向应用层提供统一的接口,对下支持各类复杂硬件的灵活扩展;

  6. V4L2框架,主要包括 v4l2-coremeida frameworkvideobuf2等模块,这也是本文将要展开的内容,仅提纲挈领;

开始吧。

  1. v4l2-core

2.1 应用视角

先从应用的角度来看如何使用 v4l2吧:

【原创】Linux v4l2框架分析

如果您想采集视频数据,一般步骤如上图左侧所示:

[En]

If you want to capture video data, the general steps are shown on the left side of the figure above:

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

上图右侧是v4l2-core的大体框架,右侧是对硬件的抽象,要想理解好它,可以先看一下较常见的硬件拓扑结构:

【原创】Linux v4l2框架分析
  • 通常一个camera的模组如图所示,通常包括Lens、Sensor、CSI接口等,其中CSI接口用于视频数据的传输;
  • SoC的Mipi接口对接Camera,并通过I2C/SPI控制camera模组;
  • Camera模组中也可以包含ISP模块,用于对图像进行处理,有的SoC中也集成了ISP的IP,接收camera的raw数据后,进行图像处理;

2.2 数据结构

如果以上图的硬件为例,对摄像头的硬件该怎么来抽象呢?没错,就是以 v4l2_devicev4l2_subdev来进行抽象,以 v4l2_device来代表整个输入设备,以 v4l2_subdev来代表子模块,比如 CSISensor等;

【原创】Linux v4l2框架分析
  • v4l2_device:对视频设备的整体进行抽象,可以看成是一个纽带,将各个子设备联系在一起,通常它会嵌入在其他结构体中以提供 v4l2框架的功能,比如 strcut isp_device
  • v4l2_subdev:对子设备进行抽象,该结构体中包含的 struct v4l2_subdev_ops是一个完备的操作函数集,用于对接各种不同的子设备,比如video、audio、sensor等,同时还有一个核心的函数集 struct v4l2_subdev_core_ops,提供更通用的功能。子设备驱动根据设备特点实现该函数集中的某些函数即可;
  • video_device:用于向系统注册字符设备节点,以便用户空间可以进行交互,包括各类设置以及数据buffer的获取等,在该结构体中也能看到 struct v4l2_ioctl_opsstruct vb2_queue结构体字段,这些与上文中的应用层代码编写息息相关;
  • 如果子设备不需要与应用层交互, struct v4l2_subdev中内嵌的 video_device也可以不向系统注册字符设备;
  • video_device结构体,可以内嵌在其他结构体中,以便提供用户层交互的功能,比如 struct isp_video
  • 针对图中回调函数集, v4l2-core提供了一些实现,所以driver在实现时,非特殊情况下可以不用重复造轮子;

2.3 流程分析

仔细查看内部注册和调用流程:

[En]

Take a closer look at the internal registration and invocation process:

【原创】Linux v4l2框架分析
  • 在驱动实现中,驱动结构体中内嵌 struct video_device,同时实现 struct v4l2_file_operations结构体中的函数,最终通过 video_register_device向提供注册;
  • v4l2_register_device函数通过 cdev_add向系统注册字符设备,并指定了 file_operations,用户空间调用 open/read/write/ioctl等接口,便可回调到驱动实现中;
  • v4l2_register_device函数中,通过 device_register向系统注册设备,会在 /sys文件系统下创建节点;

完成注册后,用户空间便可通过文件描述符来进行访问,从应用层看,大部分都是通过 ioctl接口来完成,流程如下:

【原创】Linux v4l2框架分析
  • 用户层的 ioctl回调到 __video_do_ioctl中,该函数会对系统提供的 struct v4l2_ioctl_info v4l2_ioctls[]表进行查询,找到对应的项后进行调用;
  • 驱动程序做的就是填空,实现相应的回调,在合适的时间被调用。
    [En]

    what the driver does is fill in the blanks, implement the corresponding callback, and be called at the right time.*

在下一节中,我们来看一个更复杂的情况。

[En]

In the next section, let’s look at a more complicated situation.

3.1 问题引入

为了更好的描述,本节以 omap3isp为例,先看一下它的硬件构成:

【原创】Linux v4l2框架分析
  • CSI:camera接口,接收图像数据,RGB/YUV/JPEG等;
  • CCDC:视频处理前端,CCDC为图像传感器和数字视频源提供接口,并处理图像数据;
  • Preview/Resizer:视频处理后端,Preview提供预览功能,可针对不同类型的传感器进行定制,Resizer提供将输入图像数据按所需的显示或视频编码分辨率调整大小的方法;
  • H3A/HIST:静态统计模块,H3A支持AF、AWB、AE的回路控制,HIST根据输入数据,提供各种3A算法所需的统计数据;

上述硬件模块,可以对应到驱动结构体 struct isp_device中的各个字段。

omap3isp的硬件模块,支持多种数据流通路,它并不是唯一的,以RGB为例,如下图:

【原创】Linux v4l2框架分析
  • Raw RGB数据进入ISP模块后,可以在运行过程中,根据实际的需求进行通路设置;
  • 所以,重点是:它需要动态设置路径!
    [En]

    so, the point is: it needs to set the path dynamically!*

那么,软件如何才能满足这一要求呢?

[En]

So, how can the software meet this requirement?

3.2 框架

没错,pipeline框架的引入可以解决这个问题。说来很巧,我曾经也实现过一个类似的框架,在阅读media framework时有一种似曾相识的感觉,核心的思想大体一致。

【原创】Linux v4l2框架分析
  • 模块之间相互独立,通过 struct media_entity来进行抽象,通常会将 struct media_entity嵌入到其他结构中,以支持 media framework功能;
  • 模块包含 struct media_pad,pad可以认为是端口,与其他模块进行联系的媒介,针对特定模块来说它是确定的;
  • pad通过 struct media_link来建立连接,指定source和sink,即可将通路建立起来;
  • 各个模块之间最终建立一条数据流,便是一条pipeline了,同一条pipeline中的模块,可以根据前一个模块查找到下一个模块,因此也可以很方便进行遍历,并做进一步的设置操作;

因此,只需要将 struct media_entity嵌入到特定子模块中,最终便可以将子模块串联起来,构成数据流。所以, omap3isp的驱动中,数据流就如下图所示:

【原创】Linux v4l2框架分析
  • video devnode代表 video device,也就是前文中提到的导出到用户空间的节点,用于与用户进行控制及数据交互;
  • 每个模块分别有source pad和sink pad,从连接图就可以看出,数据通路灵活多变;
  • 至于数据通路选择问题,可以在驱动初始化的时候进行链接创建,比如 isp_create_links

还是看一下数据结构吧:

【原创】Linux v4l2框架分析
  • media_device:与 v4l2_device类似,也是负责将各个子模块集中进行管理,同时在注册的时候,会向系统注册设备节点,方便用户层进行操作;
  • media_entitymedia_padmedia_link等结构体的功能在上文中描述过,注意,这几个结构体会添加到 media_device的链表中,同时它们结构体的开始字段都需是 struct media_gobj,该结构中的 mdev将会指向它所属的 media_device。这种设计方便结构之间的查找;
  • media_entity中包含多个 media_pad,同时 media_pad又会指向它所属的 media_entity
  • media_graphmedia_pipelinemedia_entity的集合,直观来理解,就是由一些模块构成的一条数据通路,由一个统一的数据结构来组织管理;

列出几个常见的接口,但不要提及细节:

[En]

List a few common interfaces, but don’t mention the details:

/* 初始化entity的pads */
int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
              struct media_pad *pads);

/* 在两个entity之间创建link */
int media_create_pad_links(const struct media_device *mdev,
               const u32 source_function,
               struct media_entity *source,
               const u16 source_pad,
               const u32 sink_function,
               struct media_entity *sink,
               const u16 sink_pad,
               u32 flags,
               const bool allow_both_undefined);

/* 开始graph的遍历,从指定的entity开始 */
void media_graph_walk_start(struct media_graph *graph,
                struct media_entity *entity);

/* 启动pipeline */
__must_check int media_pipeline_start(struct media_entity *entity,
                      struct media_pipeline *pipe);

media frameworkv4l2_devicev4l2_subdev结合起来,就可以将各个子设备构建pipeline,完美!

  1. videobuf2

4.1 框架分析

  • 框架可以分成两个部分看:控制流+数据流,上文已经大概描述了控制流,数据流的部分就是 video buffer了。
  • V4L2的buffer管理是通过 videobuf2来完成的,它充当用户空间和驱动之间的中间层,并提供low-level,模块化的内存管理功能;

【原创】Linux v4l2框架分析
  • 上图大体包含了videobuf2的框架;
  • vb2_queue:核心的数据结构,用于描述buffer的队列,其中 struct vb2_buffer *bufs[]是存放buffer节点的数组,该数组中的成员代表了 vb2 buffer,并将在 queued_listdone_list两个队列中进行流转;
  • struct vb2_buf_ops:buffer的操作函数集,由驱动来实现,并由框架通过 call_bufop宏来对特定的函数进行调用;
  • struct vb2_mem_ops:内存buffer分配函数接口,buffer类型分为三种:1)虚拟地址和物理地址都分散,可以通过dma-sg来完成;2)物理地址分散,虚拟地址连续,可以通过vmalloc分配;3)物理地址连续,可以通过dma-contig来完成;三种类型也vb2框架中都有实现,框架可以通过 call_memop来进行调用;
  • struct vb2_ops:vb2队列操作函数集,由驱动来实现对应的接口,并在框架中通过 call_vb_qop宏被调用;

4.2 流程分析

本节以 omap3isp为例进行简要分析,感觉直接看图就可以了:

  1. buffer申请

【原创】Linux v4l2框架分析
  1. buffer enqueue

【原创】Linux v4l2框架分析
  1. buffer dequeue

【原创】Linux v4l2框架分析
  1. stream on

【原创】Linux v4l2框架分析

至此,正文讲完了,相信看完这篇文章应该有个大概的提纲,还有一些细节没有进一步描述,到此为止。

[En]

At this point, the main body finished, I believe that after reading this article should have a general outline, there are some details have not been further described, stop here.

参考

https://lwn.net/Articles/416649/
《OMAP35x Technical Reference Manual (Rev. Y).pdf》

欢迎关注公众号,不定期分享技术文章。

[En]

Welcome to follow the official account and share technical articles irregularly.

【原创】Linux v4l2框架分析

Original: https://www.cnblogs.com/LoyenWang/p/15456230.html
Author: LoyenWang
Title: 【原创】Linux v4l2框架分析

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/524425/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Nginx 实践案例(源码编译安装方式):利用LNMP搭建wordpress站点

    镜像下载、域名解析、时间同步请点击阿里云开源镜像站 ​LNMP是Linux + Nginx + MySQL + PHP 四个系统的首字母缩写,相对于 LAMP(Linux + Ap…

    Linux 2023年5月27日
    0119
  • Linux系统Yum中的$releasever和$basearch变量

    Yum的配置文件中包含大量的$releasever和$basearch变量,那么他们的取值是什么呢? 为什么要折腾这个玩意呢?有点地方的网络是私有化网络,内部有大量的Linux服务…

    Linux 2023年6月8日
    089
  • 大数据之Hadoop集群中MapReduce的Join操作

    如下两张输入表格 order表 id pid amount 1001 01 1 1002 02 2 1003 03 3 1004 01 4 1005 02 5 1006 03 6 …

    Linux 2023年6月8日
    0102
  • Color 16 Base Code 颜色代码大全

    颜色预览表,请参考以下图片。 十六进制颜色编码字符串如下所示(前置的英语单词都是颜色) ‘aliceblue’: ‘#F0F8FF’…

    Linux 2023年6月7日
    0129
  • 网络安全中常用浏览器插件、拓展

    引言 现在的火狐、Edge( Chromium内核)、Chrome等浏览器带有插件、拓展(Plugin)的功能。这些插件中有的可以过滤广告,有的提供便捷的翻译,有的提供JavaSc…

    Linux 2023年6月6日
    094
  • Git常用命令

    克隆拉取远程代码 git clone https://xxxxxxxxx 本地添加远程仓库地址 git remote add origin(设定名字,随意。不过一般都叫这个名字) …

    Linux 2023年6月8日
    093
  • 【设计模式】Java设计模式-适配器模式

    【设计模式】Java设计模式 – 适配器模式 😄 不断学习才是王道🔥 继续踏上学习之路,学之分享笔记👊 总有一天我也能像各位大佬一样🏆原创作品,更多关注我CSDN: 一…

    Linux 2023年6月6日
    0176
  • 终于知道 Shell 中单引号双引号的区别了

    在编写 shell 脚本或输入命令时,你可能已经注意到大多数命令都可以使用单引号 或双引号, 这不仅适用于 shell 脚本,而且适用于所有 Bash 命令, 但是两种类型的引号以…

    Linux 2023年6月13日
    083
  • 系列文章分类汇总

    尤娜系列 从前,有一个简单的通道系统叫尤娜…… 尤娜系统的第一次飞行中换引擎的架构垂直拆分改造 四种常用的微服务架构拆分方式 尤娜,我去面试了 专业课回顾 …

    Linux 2023年6月14日
    0107
  • gitlab

    版本控制gitlab 1. 版本控制介绍 2. gitlab部署 版本控制介绍 版本控制是指对软件开发过程中各种程序代码、配置文件及说明文档等文件变更的管理,是软件配置管理的核心思…

    Linux 2023年6月7日
    0135
  • 多用户共享文件

    假设有三个用户:Tom Jerry Bob.其中,tom和Jerry都属于market部,Bob属于tech部,请在/usr目录下创建两个用户共享的目录market和public,…

    Linux 2023年6月13日
    0103
  • VMware虚拟机centOS7下配置桥接网络

    在VMware虚拟机下centOS7下配置桥接网络 首先,在以下的配置都操作好之后,要确认宿主机的网络连接方式, 若为需要认证的网络,则可能会出现宿主机与虚拟机能互相ping,但虚…

    Linux 2023年6月6日
    0135
  • Netty 如何高效接收网络数据?一文聊透 ByteBuffer 动态自适应扩缩容机制

    本系列Netty源码解析文章基于 4.1.56.Final版本,公众号:bin的技术小屋,大家如果看到图片显示不了的话,可以查看公众号原文 前文回顾 在前边的系列文章中,我们从内核…

    Linux 2023年6月6日
    0106
  • shell笔记

    shell脚本学习笔记 1.Shell入门简介 Shell是操作系统的最外层, Shell可以合并编程语言以控制进程和文件,以及启动和控制其它程序。shell通过提示您输入,向操作…

    Linux 2023年6月7日
    077
  • Quartus II 13.0 sp1的官方下载页面

    今天为了下个ModelSim跑到网上去找下载资源,清一色的百度网盘,下载速度60k/s,简直有病,于是跑到Intel官网上把连接挖出来了,供各位直接下载 实测使用IDM多线程下载速…

    Linux 2023年6月13日
    0177
  • Centos8 设置中文

    1、一般情况 1.1 进入设置选择 Region&Language 1.2 点击 加号 1.3 点击 汉语(中国) 1.4 选择 汉语(智能拼音) 2、特殊情况 有些虚拟机…

    Linux 2023年5月27日
    0125
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球