v4l2 学习笔记1--基本概念

写在前面:

  最近打算系统的学习一下v4l2,希望能通过笔记来总结,带着问题来学习,让知识由杂乱变得清晰,由浅入深,逐渐理清脉络。

  本文主要希望从宏观的层面来弄清“是什么?”,“为什么?”,“做了什么?”等相关问题,力求避免代码细节,一些参考文章,附在末尾,在此对文章作者一并感谢,感谢他们的分享精神。

  感谢博客园,能让我和朋友一起,一点点来积累知识,也方便交流共享。

  限于作者知识有限,若有不正确的地方,敬请指正。

 

1. v4l2基本概念

  (1)什么是v4l2?  

    video4linux2(V4L2)是Linux内核中关于视频设备的内核驱动。

 

  (2)支持哪些接口类型?视频设备指哪些?

    1)视频采集接口(video capture interface):高频头,摄像头

    2)视频输出接口 (video output interface):视频图像设备,如输出电视信号格式的设备

    3)直接传输视频接口(video overlay interface):视频采集设备采集信号直接输出到输出设备,不经过CPU

    4)视频间隔消隐信号接口(VBI interface):使应用可以访问传输消隐期的视频信号。

    5)收音机接口(radio interface):处理从AM或FM高频头设备接收来的音频流。

 

  (3)设备文件?

    字符设备

    主设备号:81

    1)视频设备:

      video capture device

      video output device

      video overlay device

      设备文件:/dev/video/videoX   major number: 81  minor number: 0-63

    2)radio device:

      设备文件:/dev/radio0~radio63  major number: 81  minor:64-127

    3)teletext设备:

       minor: 192-223

    4)VBI(vertical blanking interval) device

      设备文件:/dev/vbi0~31  major number: 81  minor:224-255

 

  (4)用户空间与内核空间如何交互?

    控制:ioctl系统调用

    内存映射:mmap

 

  (5)主要ioctl控制命令

    ioctl命令所在文件: linux/drivers/include/uapi/linux/videodev2.h

    VIDIOC_QUERYCAP      /*查询能力*/
    VIDIOC_G_FMT      /*获得格式*/
    VIDIOC_S_FMT         /*设置格式*/
    VIDIOC_REQBUFS      /*申请内存*/
    VIDIOC_G_FBUF       /*获得Framebuffer*/
    VIDIOC_S_FBUF        /*设置Framebuffer*/
    VIDIOC_OVERLAY     /*设置Overlay*/
    VIDIOC_QBUF         /*将内存加入队列*/
    VIDIOC_DQBUF         /*从队列取出内存*/
    VIDIOC_STREAMON       /*开始流*/
    VIDIOC_STREAMOFF     /*停止流*/
    VIDIOC_G_CTRL        /*得到控制*/
    VIDIOC_S_CTRL        /*设置控制*/

  (6) v4l2简单框图

    

   (7)V4L2支持三种I/O方式:

    Read/Write:通过调用设备节点文件的read/write函数,与设备交互数据。(默认)

    Stream I/O:流操作I/O,只传递数据缓冲区指针,不拷贝数据。

      需要调用VIDIOC_REQBUFS ioctl来通知设备。

      两种方式memory map和user buffer。

    overlay : memory to memory 传输。将数据从内存拷贝到显存中。overlay设备独有的。

  (8)Capture device 启动设备方式:

    调用VIDIOC_REQBUFS ioctl 来分配缓冲区队列;

    调用VIDIOC_STREAMON ioctl 通知设备开始stream IO

    调用VIDIOC_QBUF ioctl 从设备获取一帧视频数据;

    使用完数据后,调用 VIDIOC_DQBUF 将缓冲区还给设备,以便设备填充下一帧数据。

  (9)    

//待续。。。

 2. 重要结构

  头文件:include/linux/videodev2.h

      include/media/v4l2-dev.h

  核心实现:driver/media/video/v4l2-dev.c

  重要数据结构:

    struct video_device [v4l2-dev.h]

      负责向内核注册字符设备

    struct v4l2_device

      管理所有的子设备

    struct v4l2_subdev

      子设备,实现具体的功能

    v4l2_device, v4l2_subdev 看作所有设备和子设备的基类,编写驱动时,需要将基类嵌入到具体设备结构体,以实现继承设备基类。

  常用数据结构:

    1) 设备能力 v4l2_capability

    2) 数据格式 v4l2_format

    3) 像素格式 v4l2_pix_format

    4) 请求缓冲 v4l2_requestbuffers

    5) 数据流类型 v4l2_memory

 

3.  注册 video4linux 设备

  (1)video_register_device  注册v4l设备  [drivers/media/video/v4l2-dev.h]

    1) __video_register_device 的封装函数 

    2)驱动探测 probe到后被调用

  (2)v4l2_fops接口 [v4l2-dev.c]

    1)struct file_operations 类型,统一的应用层文件操作对应的驱动接口(字符设备)。

    2)其成员函数调用对应 struct video_device 对象的fops成员中的接口。

    3)struct video_device->fops 是具体v4l2摄像头驱动必须实现的接口。

 

图1: fops中的接口,通过struct file指针得到次设备号,进而在video_device数组中得到对应的video_device设备,最终可以调用这个设备的fops。

 

4. v4l2设备基本操作流程(从应用层看)

  1)user space 打开设备

    fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);

  2) 查询设备能力

    获取设备的capability, 查看设备功能。

    struct v4l2_capability

    VIDIOC_QUERYCAP

  3)设置优先级(可选)

    VIDIOC_G_PRIORITY

    VIDIOC_S_PRIORITY

  4)配置设备

    视频输入源的视频标准,VIDIOC_*_STD

    视频数据的格式 , VIDIOC_*_FMT

    视频输入端口, VIDIOC_*_INPUT

    视频输出端口,VIDIOC_*_OUTPUT

 

    选择视频输入

    struct v4l2_input

    VIDIOC_G_INPUT

    VIDIOC_ENUMINPUT

    VIDIOC_S_INPUT

  5)遍历所有视频格式,查询驱动所支持的格式

    struct v4l2_fmtdes

    VIDIOC_ENUM_FMT

  6)设置视频捕获格式

    struct v4l2_format

    VIDIOC_S_FMT

  7)查询视频格式     

    a)查询一种格式 VIDIOC_G_FMT

    b)遍历所有视频格式,查询驱动所支持的格式 VIDIOC_ENUM_FMT

   8) 向驱动申请帧缓冲,内存,一般不超过5个,帧缓冲管理

    struct v4l2_requestbuffers

    VIDIOC_REQBUFS  分配内存

    VIDIOC_QUERYBUF  把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址

   9) 开始捕捉图像数据(采集视频)

    enum v4l2_buf_type type;

    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    VIDIOC_STREAMON

 

  10)出队列以取得已采集数据的帧缓冲,取得原始采集数据。 

 

  11)停止视频的采集

    VIDIOC_STREAMOFF

  12) 关闭视频设备

    close(fd);

 

 5. 从驱动层看v4l2

   实现硬件相关的代码,并注册相关设备。

   (1)硬件相关的代码:

    1)具体硬件的控制代码

    2)与v4l2框架绑定

  (2)绑定:

    1)数据结构(关系)绑定:自己的结构体绑定到v4l2框架中关联结构体

    2)函数绑定:v4l2定义的空的函数指针,绑定为自己实现的函数。

 

   图:v4l2 framework 简略版

   (3)如何进行关系绑定:

    1)根据需要“继承” v4l2_device 或v4l2_subdev结构体,添加需要的结构体成员,获得一个具体设备的结构体。即将这两个结构体嵌入到新定义的结构体中,并添加链表,锁,名字,操作方法等相关成员。

    2)v4l2_device 与 v4l2 框架绑定:调用 v4l2_device_register 函数向v4l2 框架注册。

    3)v4l2_subdev 与 v4l2_device 绑定:调用 v4l2_device_register_subdev 函数向父设备注册。

    4)video_device 与 v4l2_device 绑定:将v4l2_device 的地址赋值给video_device的v4l2_dev即可。(不必要,只要能通过文件节点struct file找到 v4l2_device即可)

  (5)如何进行函数绑定

    将驱动所实现的函数赋值给相关的变量。

    在 图v4l2 framework 中, 绿色方框都是需要绑定并实现的。

    v4l2_file_operations和v4l2_ioctl_ops是必须实现的。

    v4l2_subdev_ops下的八类ops中,v4l2_subdev_core_ops是必须实现的,其余需要根据设备类型选择实现的。

    比如video capture类设备需要实现v4l2_subdev_core_ops, v4l2_subdev_video_ops。

     1)v4l2_file_operations:实现文件类操作,比如open,close,read,write,mmap等。但是ioctl是不需要实现的,一般都是用video_ioctl2代替。

    2)v4l2_ioctl_ops:V4L2导出给应用层使用的所有ioctl都在这个地方实现

    3)v4l2_subdev_ops:v4l2_subdev有可能需要实现的ops的总合。

      分为8类,core,audio,video,vbi,tuner ......等。

 

    ps:个人理解,如果没有具体的设备注册,v4l2 框架注册到内核驱动中,框架和具体硬件的接口都为NULL,也不会有提供给应用层的具体设备的设备文件。内核应该是先注册框架层,然后各个具体驱动的注册,就会把自己的相关接口挂接到框架层的接口,并留出给应用层的设备文件。

    v4l2 core  层在内核中的存在形式,以EXPORT_SYMBOL导出接口供底层调用,v4l2相关的重要数据结构。

    v4l2的设备和驱动也是通过platform总线接口注册的。//待补充

 

 

 

 

**********

references:

  1. V4L2驱动程序架构

  2. 第一章 V4L2简介— Linux V4L2 draft 

posted on 2017-12-13 17:42  sky8336  阅读(722)  评论(0编辑  收藏  举报

导航