V4l2框架简述

1 硬件

常用的电脑摄像头是USB接口,主流的智能手机摄像头是MIPI接口,另外还有像树莓派等硬件使用的CSI接口的设备。常用的智能手机Camera采用的MIPI接口,电路框架以及电路图如下

Camera传感器分前后两个,分别为前置摄像头和后置摄像头,两个camera都挂载在i2c总线上。

2 软件

linux设备文件

在linux中,所有的外设都被当做“文件”处理,就是我们常说的“设备文件”,可以像访问普通文件一样访问外设,对外设进行读写操作。linux驱动按照面向对象的不同划分 “面向字符设备”、“面向块设备”、“面向网络设备” 三大类设备。字符设备和块设备驱动在文件系统中形成类似的“虚拟文件“,即节点(node),在/dev目录下统一处理,系统调用open、read、write等进行操作,而面向网络接口的设备不会被映射到文件系统中,被分配的设备名类似eth0等等,它的驱动调用方式也不是open等。

V4l2驱动框架

V4l2(全称video for linux version2)是linux系统中的视频源捕获驱动框架。其广泛应用在嵌入式设备以及移动端、个人电脑设备上面,市面上的编码产品类如:SDV、手机、IPC、行车记录仪都会用到这个框架来进行视频采集。

在linux驱动中,V4l2是linux为视频设备提供的一套标准接口,主要包括一套V4l2相关的底层数据结构和V4l2相关的底层驱动的接口,作用是使得程序有发现和操作设备的能力。V4l2驱动框架分为 V4l2核心、V4l2下层接口两个部分,其中V4l2核心部分主要功能是构建内核中标准的视频设备驱动框架以及注册字符设备为上层用户提供访问接口,V4l2下层接口部分的主要功能是挂接底层硬件IC。

== 重要内容 ==(V4l2驱动框架分层)
第一层 V4l2核心驱动框架:video_device以及V4l2_device的创建、初始化、注册
第二层V4l2下层接口驱动框架:将camera sensor挂接到i2c总线上

v412驱动框架代码目录分布

//基于Allwinner linux 3.10版本内核分析
drivers/media/platform/sunxi-vfe/  :v4l2以及i2c注册等
drivers/media/platform/vivi.c :v4l2框架核心驱动(虚拟)
drivers/media/v4l2-core/... : v4l2框架中各个代码接口的实现
drivers/media/platform/sunxi-vfe/device/..  :底层硬件设备挂接

V4l2驱动的代码在drivers\media\v4l2-core文件夹下,打开目录可以看到如下一系列文件,看似很多其实可以归类。

  1. 比如:videobufxx_xxx.c系列文件是用于实现视频的内存分配,videobuf2_xxx系列文件是对应v4l2,而videobuf_xxx系列文件是对应于v4l(video for linux version1)。
  2. v4l2-dev.c对应于video_device的实现。
  3. v4l2-device.c对应 v4l2_device的实现。
  4. v4l2-ioctl.c对应 ioctl的实现。
  5. v4l2-subdev.c对应 42vl_subdev的实现等等。

vedio驱动代码位于drivers\media下,该路径下有很多子目录,其中比如i2c mmc usb tuners radio等目录都是对应各个subdev的实现,platform目录用于存放不同的soc的驱动代码。

        tuner-core.cv4l2-common.c v4l2-compat-ioctl32.cv4l2-ctrls.cv4l2-dev.c //主要关于 video_device结构体的注册以及各种函数接口v4l2-device.c //主要关于 4vl2的设备支持 以及v4l2_device的注册以及各种函数接口v4l2-event.cv4l2-fh.cv4l2-int-device.cv4l2-ioctl.c //主要关于处理 v4l2设备的ioctl的通用框架v4l2-mem2mem.c v4l2-of.cv4l2-subdev.c // 主要关于v4l2设备的子设备以及 v4l2_subdev的注册以及各种函数接口videobuf2-core.cvideobuf2-dma-contig.cvideobuf2-dma-sg.cvideobuf2-vmalloc.cvideobuf-core.cvideobuf-dma-contig.cvideobuf-dma-sg.cvideobuf-dvb.cvideobuf-vmalloc.cvideobuf2-memops.cKconfigMakefile

V4l2驱动框架图如下所示:

    用户空间       v42l 应用接口(open read write)-------------------------------------------------内核空间         第一层  v4l2核心驱动框架:drivers/media/platform/vivi.cv42l核心驱动 : 对应video_device(v4l2核心驱动框架)video设备驱动 : 对应v4l2_device(v4l2核心驱动框架)第二层  v4l2下层接口驱动框架:drivers/media/platform/sunxi-vfe/vfe.cvideo子设备驱动 :对应v4l2_subdev(v4l2下层接口驱动框架)-------------------------------------------------video设备接口-------------------物理底层   drivers/media/platform/sunxi-vfe/device/-------------------------------------------------v4l2核心:此部分视频设备核心。对应结构体video_device,是v4l2驱动框架向上层用户提供的接口video设备驱动:此部分驱动需要我们填充,代表一个v4l2设备,主要工作是根据 4vl2提供的驱动模型,完成对具体视频设备硬件底层实现,Linux提供4vl2示例代码:vivi.cvideo子设备驱动:4vl2驱动所连接的子设备,如摄像头传感器IC,解编码器IC,音频IC等等,对应结构体v4l2_subdev,是v4l2驱动框架向下提供的接口v42l 应用接口: 应用程序通过V4L2提供read()、write()、ioctl()编程接口,来控制操作视频设备,如:设置图像分辨率、视频数据格式、开始/结束视频捕获等等。video设备:视频设备按照输入输出来区分,摄像头属于输入设备,显示器属于输出设备video设备接口:本文讨论的是摄像头,所以此处的设备接口即摄像头接口,一般目前流行的camera接口有 mipi 和 usb,mipi是当前主流的便携式设备(手机)camera接口,当然还有其他接口比如CSI接口的硬件设备。本文项目也是mipi接口。一般的usb接口camera常见于台式或者笔记本上,usb协议有专门针对video设备的接口类

v412驱动核心结构体说明

struct video_device:保存管理V4l2_device设备数据,注册成功后以类似/dev/videoxxx的字符形式提供给上层,包含底层驱动结构体v4l2_device以及为上层提供的接口cdev。

struct v4l2_device:代表一个v4l2设备,保存设备实例的数据

struct v4l2_subdev:由于目前v4l2驱动随着需求以及硬件的变化越来越复杂,所以需要使用新的数据结构来进行数据处理。v4l2驱动需要支持音频,视频,解码,编码等ic,使得大部分v4l2设备都包含了多个子设备IC,例如,编解码器,传感器,摄像头控制器等,所以在/dev目录下不仅仅要建立v4l2的节点,还需要建立各个IC的设备节点,如fb、i2c、input、alsa等设备节点,通常这些IC通过i2c总线与主板连接,以上设备统称为sub-devices子设备,代表实实在在的camera等传感器设备。驱动需要与子设备进行通信,这些子系统一般情况下就是音频处理,编解码器等,camera常见的子设备有传感器和摄像头控制器,为了方便代码管理,内核v4l2提供了一个统一的接口给这些子设备,即v4l2_sbudev结构体。

//kernel/include/media/v4l2-dev.hstruct video_device{const struct v4l2_file_operations *fops;//设备操作函数集struct cdev *cdev;      //字符设备 对应上层接口 open/read/writestruct v4l2_device *v4l2_dev;   //v4l2 设备 int minor;    //system系统之 的 video-xxx的次设备号const struct v4l2_ioctl_ops *ioctl_ops;//具体功能的实现函数......};//kernel/include/media/v4l2-device.hstruct v4l2_device {...struct list_head subdevs;    //用链表管理注册的subdev...};//kernel/inlcude/media/v4l2-subdev.hstruct v4l2_subdev {...struct list_head list;     /* 链接至 v4l2_device */  struct v4l2_device *v4l2_dev; //struct v4l2_deviceconst struct v4l2_subdev_ops *ops;//设备功能集...};struct v4l2_subdev_ops {const struct v4l2_subdev_core_ops   *core;//通用操作集合const struct v4l2_subdev_tuner_ops  *tuner;//调谐器操作合集const struct v4l2_subdev_audio_ops  *audio;//音频操作合集const struct v4l2_subdev_video_ops  *video;//视频操作合集const struct v4l2_subdev_vbi_ops    *vbi;const struct v4l2_subdev_ir_ops     *ir;const struct v4l2_subdev_sensor_ops *sensor;const struct v4l2_subdev_pad_ops    *pad;};
open /dev/videoxx --> cdev->file_oprations ---> file_oprations->v4l2_file_oprations.open

v4l2核心驱动框架

内核提供了示例驱动:drivers/media/platform/vivi.c

主要工作:

  • 构建video_device结构,包括.fops以及.ioctl_ops
  • 初始化v4l2_device结构体(代表一个v4l2设备)
  • 注册video_device结构体(video_device是内核对v4l2_device的官方封装,用于管理v4l2_device数据),向上层用户提供访问接口
//v4l2_device设备的自定义封装
struct vivi_dev {struct list_head           vivi_devlist;struct v4l2_device     v4l2_dev;//v4l2_device设备struct video_device    vdev;
...
...
};//file_operations的一个子集
static const struct v4l2_file_operations vivi_fops = {.owner      = THIS_MODULE,.open       = v4l2_fh_open,.release    = vb2_fop_release,.read       = vb2_fop_read,.poll       = vb2_fop_poll,.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */.mmap       = vb2_fop_mmap,
};static const struct v4l2_ioctl_ops vivi_ioctl_ops = {.vidioc_querycap      = vidioc_querycap,.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,.vidioc_enum_framesizes   = vidioc_enum_framesizes,.vidioc_reqbufs       = vb2_ioctl_reqbufs,.vidioc_create_bufs   = vb2_ioctl_create_bufs,.vidioc_prepare_buf   = vb2_ioctl_prepare_buf,.vidioc_querybuf      = vb2_ioctl_querybuf,.vidioc_qbuf          = vb2_ioctl_qbuf,.vidioc_dqbuf         = vb2_ioctl_dqbuf,.vidioc_enum_input    = vidioc_enum_input,.vidioc_g_input       = vidioc_g_input,.vidioc_s_input       = vidioc_s_input,.vidioc_enum_frameintervals = vidioc_enum_frameintervals,.vidioc_g_parm        = vidioc_g_parm,.vidioc_s_parm        = vidioc_s_parm,.vidioc_streamon      = vb2_ioctl_streamon,.vidioc_streamoff     = vb2_ioctl_streamoff,.vidioc_log_status    = v4l2_ctrl_log_status,.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};//struct video_device 的构造
static const struct video_device vivi_template = {.name       = "vivi",.fops       = &vivi_fops,//用户open相关内容.ioctl_ops  = &vivi_ioctl_ops, //用户iotrl对应的相关内容.release    = video_device_release_empty,
};//注册camera设备
static int __init vivi_create_instance(int inst)
{struct vivi_dev *dev;struct video_device *vfd;int ret;//注册 v4l2_device设备,内部只是一些初始化v4l2_device行为,并无实质注册动作ret = v4l2_device_register(NULL, &dev->v4l2_dev);//注册 video_device设备: VFL_TYPE_GRABBER : 代表camera video设备类型ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
}

Allwinner平台的核心驱动位于drivers/media/platform/sunxi-vfe

sunxi-vfe是Tina平台上的camera驱动框架,用于接收并行或者mipi接口的sensor信号或者是bt656格式的信号

VFE框架

  • 使用过程中可简单的看成是vfe模块+device模块+af driver+flash控制模块的方式;
  • vfe.c是驱动的主要功能实现,包括注册/注销、参数读取、与v4l2上层接口、与各device的下层接口、中断处理、buffer申请切换等;
  • device文件夹里面是各个sensor的器件层实现,一般包括上下电、初始化,各分辨率切换,yuv sensor包括绝大部分的v4l2定义的ioctl命令的实现;而raw sensor的话大部分ioctl命令在vfe层调用了ips的库实现,少数如曝光/增益调节会透过vfe层到实际器件层;
  • actuator文件夹内是各种vcm的驱动;
  • flash_light文件夹内是闪光灯控制接口的实现;
  • csi和mipi_csi为对csi接口和mipi接口的控制文件;
  • lib文件夹为isp的库文件;
/* * vfe模块初始化* csi平台初始化、isp平台初始化、mipi平台初始化、flash平台初始化* 注册vfe_driver平台驱动*///vfe_driver
static struct platform_driver vfe_driver = {.probe    = vfe_probe,    //匹配成功后调用.remove   = vfe_remove,.shutdown = vfe_shutdown,.driver = {.name   = VFE_MODULE_NAME,.owner  = THIS_MODULE,.of_match_table = sunxi_vfe_match, //匹配接口.pm     = &vfe_runtime_pm_ops,}
};
static const struct of_device_id sunxi_vfe_match[] = {{ .compatible = "allwinner,sunxi-vfe", },{},
};
static int vfe_probe(struct platform_device *pdev)
{//获取系统资源,获取配置参数,填充结构体,执行probe_workstruct vfe_dev *dev;...INIT_DELAYED_WORK(&dev->probe_work, probe_work_handle);schedule_delayed_work(&dev->probe_work,msecs_to_jiffies(1));
}//file_operations的一个子集
static const struct v4l2_file_operations vfe_fops = {.owner        = THIS_MODULE,.open           = vfe_open,.release        = vfe_close,.read           = vfe_read,.poll           = vfe_poll,.unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */.mmap          = vfe_mmap,
};static const struct v4l2_ioctl_ops vfe_ioctl_ops = {.vidioc_querycap      = vidioc_querycap,.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,.vidioc_enum_framesizes   = vidioc_enum_framesizes,.vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,.vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,.vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,.vidioc_reqbufs           = vidioc_reqbufs,.vidioc_querybuf          = vidioc_querybuf,.vidioc_qbuf              = vidioc_qbuf,.vidioc_dqbuf             = vidioc_dqbuf,.vidioc_enum_input        = vidioc_enum_input,.vidioc_g_input           = vidioc_g_input,.vidioc_s_input           = vidioc_s_input,.vidioc_streamon          = vidioc_streamon,.vidioc_streamoff         = vidioc_streamoff,.vidioc_g_parm            = vidioc_g_parm,.vidioc_s_parm            = vidioc_s_parm,.vidioc_default      = vfe_param_handler,
};//struct video_device 的构造
static struct video_device vfe_template[] = {[0] = {.name       = "vfe_0",.fops       = &vfe_fops,.ioctl_ops  = &vfe_ioctl_ops,.release    = video_device_release,},[1] = {...},
};//注册camera设备
static void probe_work_handle(struct work_struct *work)
{struct vfe_dev *dev;struct video_device *vfd;int ret;//注册 v4l2_device设备,内部只是一些初始化v4l2_device行为,并无实质注册动作ret = v4l2_device_register(&dev->pdev->dev, &dev->v4l2_dev);//注册 video_device设备: VFL_TYPE_GRABBER : 代表camera video设备类型ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_num);
}

v4l2下层接口驱动

不同的camera有不同的驱动,但是他都凌驾在i2c的控制器上。故实现camera的驱动,通常都是实现i2c_driver和i2c_client的相关内容。

//kernel/drivers/media/platform/sunxi-vfe/device/具体的元器件驱动
module_init(init_sensor);
static struct i2c_driver sensor_driver = {.driver = {.owner = THIS_MODULE,.name = SENSOR_NAME,  //"ov5640".of_match_table = sernsor_match, //.compatible = "allwinner,sensor_ov5640"},.probe = sensor_probe,.remove = sensor_remove,.id_table = sensor_id,
};
static __init int init_sensor(void)
{//i2c_add_driver i2c驱动注册的封装函数return cci_dev_init_helper(&sensor_driver);
}
/****************************************/
static const struct v4l2_subdev_core_ops sensor_core_ops = {.g_chip_ident = sensor_g_chip_ident,.g_ctrl = sensor_g_ctrl,.s_ctrl = sensor_s_ctrl,.queryctrl = sensor_queryctrl,.reset = sensor_reset,.init = sensor_init,.s_power = sensor_power,.ioctl = sensor_ioctl,
};
static const struct v4l2_subdev_video_ops sensor_video_ops = {.enum_mbus_fmt = sensor_enum_fmt,.enum_framesizes = sensor_enum_size,.try_mbus_fmt = sensor_try_fmt,.s_mbus_fmt = sensor_s_fmt,.s_parm = sensor_s_parm,.g_parm = sensor_g_parm,.g_mbus_config = sensor_g_mbus_config,
};
static const struct v4l2_subdev_ops sensor_ops = {.core = &sensor_core_ops,.video = &sensor_video_ops,
};
/****************************************/
static int sensor_probe(struct i2c_client *client, const struct i2c_device_id *id)
{struct v4l2_subdev *sd;    //v4l2子设备struct sensor_info *info;  //传感器数据...cci_dev_probe_helper(sd, client, &sensor_ops, &cci_drv);  //i2c子设备初始化与sensor_ops绑定起来...
}

Linux V4l2驱动 -- 框架概述相关推荐

  1. 深入学习Linux摄像头(二)v4l2驱动框架

    深入学习Linux摄像头系列 深入学习Linux摄像头(一)v4l2应用编程 深入学习Linux摄像头(二)v4l2驱动框架 深入学习Linux摄像头(三)虚拟摄像头驱动分析 深入学习Linux摄像头 ...

  2. Linux PCI驱动框架分析:(Peripheral Component Interconnect,外部设备互联)

    <DPDK 20.05 | rte_pci_bus思维导图 | 第一版> <linux系统下:IO端口,内存,PCI总线 的 读写(I/O)操作> <Linux指令:ls ...

  3. V4L2视频输入框架概述

    原文链接 本文开启 linux 内核 V4L2 框架部分的学习之旅,本文仅先对 V4L2 的框架做一个综述性的概括介绍,然后接下来的文章中会对 V4L2 框架的各个子模块进行一个全面的介绍,包括每一部 ...

  4. Linux PCIe驱动框架分析(第二章)

    目录 项目背景 1. 概述 2. 数据结构 3. 流程分析 3.1 设备驱动模型 3.2 初始化 3.2.1 pci_bus_match 3.2.2 pci_device_probe 3.3 枚举 项 ...

  5. Linux SPI驱动框架(1)——核心层

    概述   linux SPI驱动框架主要分为核心层,控制器驱动层以及设备驱动层.具体结构可参考下图   图中,最下层是硬件空间,SPI总线控制器,总线控制器负责硬件上的数据交互.内核空间中,需要有对应 ...

  6. 深入分析Linux PCI驱动框架分析(二)

    说明: Kernel版本:4.14 ARM64处理器 使用工具:Source Insight 3.5, Visio 1. 概述 本文将分析Linux PCI子系统的框架,主要围绕Linux PCI子系 ...

  7. V4L2系列 之 V4L2驱动框架

    目录 前言 一.V4L2驱动框架概览 1.应用层 ->中间层->驱动层 2.主要代码文件(Linux 4.19版本内核) 二.怎么写V4L2驱动 1.如何写一个设备的驱动? 2.Video ...

  8. Camera 从应用层看V4L2驱动框架

    1.V4L2驱动框架简介 V4L2可用于采集图片.视频和音频数据的通用 API 接口,配合适当的视频采集设备和相应的驱 动程序,可以实现图片.视频.音频等的采集. 2.V4L2视频采集原理 当启动视频 ...

  9. Linux USB驱动框架分析 【转】

    转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...

最新文章

  1. Unity中制作游戏的快照游戏支持玩家拍快照
  2. sql server xp_readerrorlog SQL语句查看错误日志
  3. Sublime Text 无法使用Package Control或插件安装失败的解决方法【转】
  4. Java并发,并行,同步,互斥
  5. Application Architecture Guide 2.0 (Chapter 7: Quality Attributes) Part 3
  6. 解决2次查询User的问题(ThreadLocal)
  7. Mybatisplus代码生成 之SpringBoot适配MYSQL和ORACLE
  8. 快点搜quickso.cn
  9. Framework学习(一)深入Android 系统架构
  10. python程序基本结构总结_python总结
  11. iptv直播源m3u_Padavan 单线复用实现拨号上网加IPTV 操作记录
  12. 尚硅谷大数据课程flink1.13代码实现与笔记记录
  13. 30个python常用代码大全_30 个 Python 常用极简代码,拿走就用
  14. jQuery-简介与基本使用
  15. 你所不知道的Win键
  16. 获取市场上的股票代码
  17. 计算物体自由下落的距离
  18. Redis应用项目---抢红包功能(二)
  19. Oracle 数据库
  20. 国防科技大学计算机考纲,国防科技大学2022年硕士研究生考试大纲-F1007雷达原理...

热门文章

  1. idea中lombok下载方法和搜不到lombok解决方法
  2. LDA主题模型绘制困惑度(perplexity)-主题数曲线——python
  3. 手机QQ AndroidManifest 用于跳转
  4. vue 页面回跳两个界面(返回上一页两次)
  5. 编译原理上机实习c语言小子集编译程序的实现报告,合肥工业大学编译原理实验报告(完整代码版)...
  6. 【转载】人的一生最后悔什么
  7. 详解请求转发和重定向
  8. matlab 采用描点法进行数据模拟和仿真
  9. 2345安全卫士使用分析报告
  10. OL4叠加显示天地图地图服务之WMTS实例