LinuxV4L2子系统与视频编解码设备介绍

科技布道师 2024-09-09 21:34:46
1.V4L2简介

1.1 什么是V4L2 V4L,其全称是Video4Linux(即Video for Linux),是Linux内核中关于视频设备的驱动框架,涉及开关视频设备,以及从该类设备采集并处理相关的音、视频信息。V4L从Linux2.1版本的内核中开始出现。现在Linux内核中用的是V4L2,即Video4Linux2(即Video for Linux Two),其是修改V4L相关Bug后的一个升级版,始于Linux 2.5内核。由于硬件的复杂性,V4L2 驱动程序往往非常复杂:大多数设备都有多个 IC,在 /dev 中导出多个设备节点,并创建非 V4L2 设备,例如 DVB、ALSA、FB、I2C 和输入(IR ) 设备。尤其是 V4L2 驱动程序必须设置支持 IC 来进行音频/视频复用/编码/解码,这一事实使其比大多数驱动程序更加复杂。通常这些IC通过一条或多条I2C总线连接到主桥驱动器,但也可以使用其他总线。此类设备称为“子设备”。长期以来,该框架仅限于用于创建 V4L 设备节点的 video_device 结构和用于处理视频缓冲区的 video_buf。这意味着所有驱动程序都必须自行设置设备实例并连接到子设备。其中一些操作要正确执行起来相当复杂,许多驱动程序从未正确执行过。还有很多通用代码由于缺乏框架而永远无法重构。因此,这个V4L2框架设置了所有驱动程序所需的基本构建块,并且这个相同的框架应该使将公共代码重构为所有驱动程序共享的实用程序函数变得更加容易。

1.2 Video设备的V4L2框架 图1-1是基于Video设备的V4L2框架

图1-1 V4L2框架Linux系统中视频设备主要包括以下四个部分: 1.字符设备驱动程序核心:V4L2本身就是一个字符设备,具有字符设备所有的特性,暴露接口给用户空间;用户空间可以通过Ioctl系统调用控制设备;在应用层,我们可以在 /dev 目录发现 videoxx 类似的设备节点。2.V4L2驱动核心:主要是构建一个内核中标准视频设备驱动的框架,为视频操作提供统一的接口函数;3.平台V4L2设备驱动:在V4L2框架下,根据平台自身的特性实现与平台相关V4L2驱动部分,包括注册video_device和v4l2_dev。4.具体的sensor驱动:主要上电、提供工作时钟、视频图像裁剪、流IO开启等,实现各种设备控制方法供上层调用并注册v4l2_subdev。

1.3 V4L2支持的设备类型 V4L2支持的设备十分广泛,但是其中只有很少一部分在本质上是真正的视频设备:video capture interface:视频采集接口,从camera上获取视频数据,视频捕获是V4L2的基本应用;video output interface:视频输出接口,允许应用程序驱动外设提供视频图像video overlay interface:视频覆盖接口,是捕获接口的一个变体,其工作是便于捕获设备直接显示到显示器,无需经过CPU;Android拍照应用在进行预览时,可能就是这种模式。VBI interfaces:基于电视场消隐实现远程传送文字的技术与设备; radio interface:无线电接口,从AM和FM调谐器设备访问音频流。Codec Interface:编解码接口,对视频数据流执行转换。

通常情况下V4L2的主设备号是81,次设备号为0~255;这些次设备号里又分为多类设备:视频设备、Radio(收音机)设备、Teletext on VBI等。因此V4L2设备对应的文件节点有:/dev/videoX、/dev/vbiX、/dev/radioX。对于Radio设备,即用于收发声音。但要提醒注意的是,对于声音的采集与处理,在我们的Android手持设备中常会有个Mic设备,它则是属于ALSA子系统的。我们主要讨论的是Video设备。

2.编解码设备 传统的Capture设备从Camera硬件读取数据到DDR,Output设备从DDR读取数据输出到Display;Codec Interface 不同于传统的V4L2 Capture / Output 设备;通常是基于M2M(memory to memory),即从DDR读取数据,进行一些处理后再写入DDR;

图2-1. V4L2 M2M DeviceV4L2 M2M设备可以在内存中压缩、解压缩、转换或以其他方式将视频数据从一种格式转换为另一种格式。M2M设备的示例包括编解码器、缩放器、去隔行器或格式转换器(如从 YUV 转换为 RGB)。

M2M视频节点的行为就像普通视频节点一样,但它支持输出(将帧从内存发送到硬件设备)和捕获(将处理后的帧从硬件接收到内存)I/O Steaming。应用程序必须为双方设置流 I/O,并最终调用 VIDIOC_STREAMON 进行捕获和输出以启动硬件。

内存到内存设备充当共享资源:您可以多次打开视频节点,每个应用程序设置自己的文件句柄本地属性,并且每个应用程序都可以独立于其他应用程序使用它。驱动程序将仲裁对硬件的访问,并在另一个文件处理程序获得访问权限时对其重新编程。这与通常的视频节点行为不同,在通常的视频节点行为中,视频属性对于设备来说是全局的(即通过一个文件句柄更改某些内容可以通过另一个文件句柄看到)。

最常见的内存到内存设备之一是编解码器。编解码器比大多数编解码器更复杂,并且需要对其编解码器参数进行额外设置。这是通过编解码器控件完成的。以下各节给出了有关如何使用编解码器内存到内存设备的更多详细信息。

2.1.Stateless Video Codecs 虽然对于上层应用来说视频播放有暂停/播放状态,其实是上层应用通过是否给底层编解码器送数据来模拟的状态;如果上层应用没有给底层编解码器喂数据,则可以认为是pause状态,反之则是playing状态; 图2-2 Android Mediaplayer状态图

对于底层soc硬件编/解码器都是基于无状态的;无状态解码器是一种在处理的帧之间不保留任何状态的解码器。这意味着每一帧的编解码独立于任何先前和未来的帧,并且客户端负责维护解码状态并将其通过每个解码请求提供给解码器。这与有状态视频解码器接口形成对比,在有状态视频解码器接口中,硬件和驱动程序维护解码状态,并且客户端所要做的就是提供原始编码流并按显示顺序使解码帧出队。

2.2 用户空间如何与无状态解码器通信 本节描述用户空间(“客户端”)如何与无状态解码器通信,以便成功解码压缩流。与有状态编解码器相比,解码器/客户端序列更简单,但这种简单性的代价是客户端中负责维护一致解码状态的额外复杂性。先用应用角度看用户空间如何调用V4L2接口: 图2-3 用户空间解码流程基本流程如下:1. 打开设备:open 设备节点 /dev/videoX2. 查询设备能力,获取设备driver_name等;3. 枚举格式/设置格式:查询设备能够支持处理的color format等;4. “请求”缓存:目前Android设备采用DMA-Buf,kernel不涉及内存申请,只是创建videobuf2队列; 5. 启动流转:6.循环处理每一帧上层送入的数据,将处理好的数据返回用户空间;

V4L2 相关 API如下: 用户空间API kernel space对应API

2.3.Buffer 管理 Buffer管理主要涉及如何在用户空间和内核空间传递数据,如视频H.264压缩数据和解码之后的YUV数据;如下图,对于解码case,output buffers是视频压缩数据,capture buffers是解码后的YUV数据;

图2-4:V4L2 M2M Buffer管理
0 阅读:12

科技布道师

简介:感谢大家的关注