1.1. 打开和关闭设备

1.1.1. 通过 V4L2 控制硬件外设

使用 V4L2 uAPI 支持的硬件通常由多个设备或外设组成,每个设备或外设都有自己的驱动程序。

桥接驱动程序暴露一个或多个 V4L2 设备节点(参见V4L2 设备节点命名)。

还有其他驱动程序提供对硬件其他组件的支持,这些组件也可能暴露设备节点,称为 V4L2 子设备。

当这些 V4L2 子设备被暴露时,它们允许控制那些其他硬件组件——通常通过串行总线(如 I²C、SMBus 或 SPI)连接。根据桥接驱动程序的不同,这些子设备可以通过桥接驱动程序间接控制,或通过媒体控制器以及V4L2 子设备显式控制。

需要使用媒体控制器的设备称为 MC-中心型 设备。通过 V4L2 设备节点完全控制的设备称为 视频节点中心型

用户空间可以通过调用ioctl VIDIOC_QUERYCAP并检查device_caps 字段来检查 V4L2 硬件外设是否为 MC-中心型。

如果设备在 device_caps 中返回 V4L2_CAP_IO_MC 标志,则它是 MC-中心型,否则,它是视频节点中心型。

对于 MC-中心型驱动程序,在使用外设之前,需要识别 V4L2 子设备并通过媒体控制器 API配置管道。此外,子设备的配置应通过子设备 API控制。

注意

视频节点中心型设备仍可能提供媒体控制器和子设备接口。

然而,在这种情况下,媒体控制器和子设备接口是只读的,并且仅提供设备信息。实际配置是通过视频节点完成的。

1.1.2. V4L2 设备节点命名

V4L2 驱动程序作为内核模块实现,由系统管理员手动加载,或在首次发现设备时自动加载。驱动程序模块插入 videodev 内核模块。它提供了本文件中指定的辅助函数和通用应用程序接口。

每个加载的驱动程序都会注册一个或多个主编号为 81 的设备节点。除非内核以 CONFIG_VIDEO_FIXED_MINOR_RANGES 内核选项编译,否则次编号是动态分配的。在这种情况下,次编号会根据设备节点类型按范围分配。

Video4Linux 子系统支持的设备节点是

默认设备节点名称

用途

/dev/videoX

用于捕获/输出设备的视频和元数据

/dev/vbiX

垂直消隐数据(即隐藏字幕、图文电视)

/dev/radioX

无线电调谐器和调制器

/dev/swradioX

软件定义无线电调谐器和调制器

/dev/v4l-touchX

触摸传感器

/dev/v4l-subdevX

视频子设备(由传感器和硬件外设的其他组件使用)[1]

其中 X 是一个非负整数。

注意

  1. 实际的设备节点名称取决于系统,因为 udev 规则可能适用。

  2. 不能保证 X 对于同一设备保持不变,因为该数字取决于设备驱动程序的探测顺序。如果您需要一个唯一的名称,udev 默认规则会生成包含可唯一标识 V4L2 设备节点的链接的 /dev/v4l/by-id//dev/v4l/by-path/ 目录

    $ tree /dev/v4l
    /dev/v4l
    ├── by-id
    │   └── usb-OmniVision._USB_Camera-B4.04.27.1-video-index0 -> ../../video0
    └── by-path
        └── pci-0000:00:14.0-usb-0:2:1.0-video-index0 -> ../../video0
    

许多驱动程序支持“video_nr”、“radio_nr”或“vbi_nr”模块选项来选择特定的视频/广播/VBI 节点编号。这允许用户请求设备节点被命名为例如 /dev/video5,而不是任其随机。当驱动程序支持多个同类型设备时,可以分配多个设备节点编号,用逗号分隔

# modprobe mydriver video_nr=0,1 radio_nr=0,1

/etc/modules.conf 中,这可以写成

options mydriver video_nr=0,1 radio_nr=0,1

当没有将设备节点编号作为模块选项给出时,驱动程序会提供一个默认值。

通常,udev 会自动为您在 /dev 中创建设备节点。如果未安装 udev,则需要启用 CONFIG_VIDEO_FIXED_MINOR_RANGES 内核选项,以便能够正确地将次编号与设备节点编号关联起来。即,您需要确定次编号 5 映射到设备节点名称 video5。使用此内核选项,不同设备类型具有不同的次编号范围。这些范围列在接口中。

创建字符特殊文件(使用 mknod)是一项特权操作,并且设备不能通过主编号和次编号打开。这意味着应用程序无法可靠地扫描已加载或已安装的驱动程序。用户必须输入设备名称,或者应用程序可以尝试传统的设备名称。

1.1.4. 多次打开

V4L2 设备可以多次打开。[2] 当驱动程序支持此功能时,用户可以例如启动一个“面板”应用程序来更改亮度或音量等控件,而另一个应用程序则捕获视频和音频。换句话说,面板应用程序可与 ALSA 音频混音器应用程序相媲美。仅仅打开一个 V4L2 设备不应改变设备的状态。[3]

一旦应用程序分配了流数据所需的内存缓冲区(通过调用ioctl VIDIOC_REQBUFSioctl VIDIOC_CREATE_BUFS ioctl,或通过调用read()write()函数隐式分配),该应用程序(文件句柄)就成为设备的所有者。它不再允许进行会影响缓冲区大小的更改(例如,通过调用VIDIOC_S_FMT ioctl),并且其他应用程序不再允许分配缓冲区或启动或停止流。此时将返回 EBUSY 错误代码。

仅仅打开一个 V4L2 设备并不能授予独占访问权限。[4] 但是,发起数据交换会将读取或写入所请求数据类型以及更改相关属性的权限分配给此文件描述符。应用程序可以使用应用程序优先级中描述的优先级机制请求额外的访问权限。

1.1.5. 共享数据流

V4L2 驱动程序不应通过复制缓冲区、时分复用或类似方式支持多个应用程序读写设备上的相同数据流。这最好由用户空间中的代理应用程序处理。

1.1.6. 函数

为了打开和关闭 V4L2 设备,应用程序分别使用open()close()函数。设备使用ioctl()函数进行编程,如以下章节所述。