V4L2视频驱动详解

  • 刚建的微信群欢迎加入一起学习、讨论:
  • 1. 简介
  • 1.1 视频输入输出设备(video capture device,video output device)
  • 1.2 VBI设备(Vertical Blanking Interval)
  • 1.3 radio设备
  • 2. 系统框架图:
  • 3. 三种不同IO访问方式
  • 3.1 read/write基本IO访问方式
  • 3.2 mmap内存映射方式
  • 3.3 userp用户空间缓冲区方式


1. 简介

  • 概述:Video4Linux2(简称V4L2)是Linux下关于视频采集相关设备的驱动框架,是linux中关于视频设备的内核驱动,为驱动和应用程序提供了一套统一的接口规范。支持三类设备,分别会在/dev目录下产生不同的设备节点:是 linux操作系统下用于采集图片、视频和音频数据的 API接口,配合适当的视频采集设备和相应的驱动程序。
  • 作用: 支持许多USB 网络摄像头,电视调谐器和相关设备,使它们的输出标准化,因此程序员可以轻松地向其应用程序添加视频支持。MythTV,tvtime和Tvheadend是使用V4L框架的典型应用程序;
    可以实现图片、视频、音频等的采集。在远程会议、可视电话、视频监控系统和嵌入式多媒体终端中都有广泛的应用。
  • 存放位置: Linux中,一切皆文件,视频设备为字符设备文件,可以像普通文件一样进行读写操作,而采用 V4L2驱动的摄像头设备文件是 /dev/v4l/video0,为了通用,可以建立到一个和普通摄像头一样的 /dev/video0的链接。

1.1 视频输入输出设备(video capture device,video output device)

  • 分别是提供视频捕获功能的摄像头类型设备和提供视频输出功能的设备,对应的设备名为videoX。这是我们最常用的一种设备类型。

1.2 VBI设备(Vertical Blanking Interval)

  • 对VBI数据进行控制、发送或抓取的设备,对应设备名vbiX。

1.3 radio设备

  • 提供FM/AM发送和接收的设备,对应设备名radioX

2. 系统框架图:

【genius_platform软件平台开发】第五十二讲:Linux系统之V4L2视频驱动详解_liunx v4l2


【genius_platform软件平台开发】第五十二讲:Linux系统之V4L2视频驱动详解_用户空间_02


【genius_platform软件平台开发】第五十二讲:Linux系统之V4L2视频驱动详解_数据_03

  • 从图中可以看出,驱动的框架层次分明,最上层应用层通过字符设备提供videomedia两种控制接口,分别从视频流控制(video)媒体子设备控制(media)两种不同的角度抽象出操作接口。
  • 中间内核驱动层通过三层设备驱动分别从视频抽象,V4L2设备功能定义,子设备功能定义三个层面展开,模块化的设计提供了非常完善的扩展性。
  • 最下方是硬件层,除了提供常用摄像头传感器的功能外,对于常用的视频转换也有很好的支持。

3. 三种不同IO访问方式

3.1 read/write基本IO访问方式

  • read方式读取一帧数据,数据需要从内核空间传输到用户空间,增加了内存访问的开销,对于图像类的应用效率不高;

3.2 mmap内存映射方式

  • 这是在内核空间开辟的缓冲区,这些缓冲区可能支持DMA功能,这样极大的提高了数据从设备搬运到内存的效率。用户只需要使用mmap()系统调用将其映射到用户空间后,可以直接使用。这种方式支持的设备很多;

3.3 userp用户空间缓冲区方式

  • 这是在用户空间开辟的缓冲区,再把缓冲区的指针告诉内核。这种方式虽然也能减少内存拷贝,但是内核驱动或者硬件设备在处理这些用户空间的地址会麻烦很多,不是所有的设备都会支持;
  • mmap内存映射方式具体使用过程,参考如下流程图:
  • 具体详解如下:
    1、使用open()打开设备 2、使用ioctl()进行初始化参数设置,一般包括查询设备能力(VIDIOC_QUERYCAP),设置视频捕获相关参数,如帧率控制(VIDIOC_S_PARM)、图像的窗口尺寸(VIDIOC_S_CROP)、像素点的格式和宽高(VIDIOC_S_FMT)等
    3、使用ioctl()申请帧缓冲(VIDIOC_REQBUFS),并查询申请到的缓冲区的信息(VIDIOC_QUERYBUF)
    4、使用mmap()对申请到的缓冲区进行内存映射,保存映射得到的地址
    5、使用ioctl()把帧缓冲进行入队操作(VIDIOC_QBUF)
    6、使用ioctl()开始视频流进行捕获(VIDIOC_STREAMON)
    7、使用selet()等待接收到数据
    8、使用ioctl()取出帧缓冲即出队操作(VIDIOC_DQBUF)
    9、进行数据处理,
    10、重复帧缓冲入队操作,如此循环
    11、退出时,停止采集工作(VIDIOC_STREAMOFF),使用unmap()和close()释放资源
注意:在执行on\off的过程中,需要重新申请资源入队列,然后才能够在DQBUF中获取到相应的数据帧,
否则只是在select中有数据可以读取readfds但是在DQBUF中获取不到数据的;