1.10. 扩展控制 API

1.10.1. 简介

最初设计的控制机制旨在用于用户设置(亮度、饱和度等)。然而,事实证明它是一个非常有用的模型,用于实现更复杂的驱动程序 API,其中每个驱动程序仅实现较大 API 的一个子集。

MPEG 编码 API 是设计和实现此扩展控制机制的驱动力:MPEG 标准非常庞大,目前支持的硬件 MPEG 编码器每个都仅实现该标准的一个子集。此外,许多与视频如何编码为 MPEG 流相关的参数是特定于 MPEG 编码芯片的,因为 MPEG 标准仅定义了生成的 MPEG 流的格式,而不是视频实际编码为该格式的方式。

不幸的是,原始控制 API 缺少这些新用途所需的一些功能,因此它被扩展为(名称不那么原创的)扩展控制 API。

即使 MPEG 编码 API 是第一个使用扩展控制 API 的尝试,如今还有其他类型的扩展控件,例如相机控件和 FM 发射器控件。以下文本描述了扩展控制 API 以及所有扩展控件类。

1.10.2. 扩展控制 API

提供了三个新的 ioctl:VIDIOC_G_EXT_CTRLSVIDIOC_S_EXT_CTRLSVIDIOC_TRY_EXT_CTRLS。这些 ioctl 作用于控制数组(与作用于单个控制的 VIDIOC_G_CTRLVIDIOC_S_CTRL ioctl 相反)。这是必需的,因为通常需要一次原子地更改多个控件。

每个新的 ioctl 都期望指向结构 v4l2_ext_controls 的指针。此结构包含指向控制数组的指针、该数组中控件的数量计数和一个控制类。控制类用于将相似的控件分组到一个类中。例如,控制类 V4L2_CTRL_CLASS_USER 包含所有用户控件(即所有也可以使用旧的 VIDIOC_S_CTRL ioctl 设置的控件)。控制类 V4L2_CTRL_CLASS_CODEC 包含与编解码器相关的控件。

控制数组中的所有控件都必须属于指定的控制类。如果不是这种情况,则返回错误。

也可以使用空控制数组(count == 0)来检查是否支持指定的控制类。

控制数组是一个 v4l2_ext_control 结构数组。v4l2_ext_control 结构与 v4l2_control 结构非常相似,只是它还允许传递 64 位值和指针。

由于结构 v4l2_ext_control 支持指针,现在还可以使用具有复合类型的控件,例如 N 维数组和/或结构。在枚举控件时,您需要指定 V4L2_CTRL_FLAG_NEXT_COMPOUND 才能实际看到此类复合控件。换句话说,这些具有复合类型的控件应该仅以编程方式使用。

由于此类复合控件需要公开比 VIDIOC_QUERYCTRL 更多的信息,因此添加了 VIDIOC_QUERY_EXT_CTRL ioctl。特别是,如果此控件包含多个元素,则此 ioctl 会给出 N 维数组的维度。

注意

  1. 重要的是要意识到,由于控件的灵活性,有必要检查您要设置的控件是否在驱动程序中实际支持,以及有效值的范围是多少。因此,请使用 ioctls VIDIOC_QUERYCTRL、VIDIOC_QUERY_EXT_CTRL 和 VIDIOC_QUERYMENU 来检查这一点。

  2. 类型为 V4L2_CTRL_TYPE_MENU 的控件中的某些菜单索引可能不受支持(VIDIOC_QUERYMENU 将返回错误)。一个很好的例子是支持的 MPEG 音频比特率列表。一些驱动程序仅支持一两个比特率,而另一些驱动程序则支持更广泛的范围。

所有控件都使用机器字节序。

1.10.3. 枚举扩展控件

建议的枚举扩展控件的方法是结合使用 ioctls VIDIOC_QUERYCTRL、VIDIOC_QUERY_EXT_CTRL 和 VIDIOC_QUERYMENU 以及 V4L2_CTRL_FLAG_NEXT_CTRL 标志

struct v4l2_queryctrl qctrl;

qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
while (0 == ioctl (fd, VIDIOC_QUERYCTRL, &qctrl)) {
    /* ... */
    qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
}

初始控件 ID 设置为 0 与 V4L2_CTRL_FLAG_NEXT_CTRL 标志进行 OR 运算。VIDIOC_QUERYCTRL ioctl 将返回 ID 高于指定 ID 的第一个控件。当未找到此类控件时,将返回错误。

如果要获取特定控制类中的所有控件,则可以将初始 qctrl.id 值设置为控制类,并添加一个额外的检查,以便在找到另一个控制类的控件时跳出循环

qctrl.id = V4L2_CTRL_CLASS_CODEC | V4L2_CTRL_FLAG_NEXT_CTRL;
while (0 == ioctl(fd, VIDIOC_QUERYCTRL, &qctrl)) {
    if (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_CODEC)
        break;
    /* ... */
    qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
}

32 位 qctrl.id 值细分为三个位范围:顶部 4 位保留用于标志(例如 V4L2_CTRL_FLAG_NEXT_CTRL),实际上不是 ID 的一部分。其余 28 位构成控件 ID,其中最高有效 12 位定义控制类,最低有效 16 位标识控制类中的控件。保证这些最后 16 位对于控件始终为非零值。0x1000 及以上的范围保留给驱动程序特定的控件。宏 V4L2_CTRL_ID2CLASS(id) 基于控件 ID 返回控制类 ID。

如果驱动程序不支持扩展控件,则 VIDIOC_QUERYCTRL 在与 V4L2_CTRL_FLAG_NEXT_CTRL 结合使用时将失败。在这种情况下,应使用旧的枚举控制方法(请参阅 示例:枚举所有控件)。但是,如果支持,则保证枚举所有控件,包括驱动程序私有控件。

1.10.4. 创建控制面板

可以为图形用户界面创建控制面板,用户可以在其中选择各种控件。基本上,您必须使用上述方法迭代所有控件。每个控制类都以类型为 V4L2_CTRL_TYPE_CTRL_CLASS 的控件开始。VIDIOC_QUERYCTRL 将返回此控制类的名称,该名称可用作控制面板中选项卡页的标题。

结构 v4l2_queryctrl 的 flags 字段还包含有关控件行为的提示。有关更多详细信息,请参阅 ioctls VIDIOC_QUERYCTRL、VIDIOC_QUERY_EXT_CTRL 和 VIDIOC_QUERYMENU 文档。