7.29. ioctl VIDIOC_G_EXT_CTRLS, VIDIOC_S_EXT_CTRLS, VIDIOC_TRY_EXT_CTRLS

7.29.1. 名称

VIDIOC_G_EXT_CTRLS - VIDIOC_S_EXT_CTRLS - VIDIOC_TRY_EXT_CTRLS - 获取或设置多个控件的值,尝试控件值

7.29.2. 概要

VIDIOC_G_EXT_CTRLS

int ioctl(int fd, VIDIOC_G_EXT_CTRLS, struct v4l2_ext_controls *argp)

VIDIOC_S_EXT_CTRLS

int ioctl(int fd, VIDIOC_S_EXT_CTRLS, struct v4l2_ext_controls *argp)

VIDIOC_TRY_EXT_CTRLS

int ioctl(int fd, VIDIOC_TRY_EXT_CTRLS, struct v4l2_ext_controls *argp)

7.29.3. 参数

fd

open() 返回的文件描述符。

argp

指向 struct v4l2_ext_controls 的指针。

7.29.4. 描述

这些 ioctl 允许调用者以原子方式获取或设置多个控件。控件 ID 被分组到控件类中(参见 控件类),并且控件数组中的所有控件必须属于同一个控件类。

应用程序必须始终填写 struct v4l2_ext_controlscountwhichcontrolsreserved 字段,并初始化 controls 字段指向的 struct v4l2_ext_control 数组。

要获取一组控件的当前值,应用程序需要初始化每个 struct v4l2_ext_controlidsizereserved2 字段,并调用 VIDIOC_G_EXT_CTRLS ioctl。字符串控件还必须设置 string 字段。复合类型的控件(设置了 V4L2_CTRL_FLAG_HAS_PAYLOAD)必须设置 ptr 字段。

如果 size 太小,无法接收控件结果(仅与指针类型控件(如字符串)相关),则驱动程序会将 size 设置为有效值并返回 ENOSPC 错误代码。您应该将内存重新分配到这个新的大小并重试。对于字符串类型,如果字符串在这段时间内增长了,则可能再次出现相同的问题。建议先调用 ioctls VIDIOC_QUERYCTRL、VIDIOC_QUERY_EXT_CTRL 和 VIDIOC_QUERYMENU,并使用 maximum+1 作为新的 size 值。这保证了足够的内存。

N 维数组是逐行设置和检索的。您不能设置部分数组,必须设置或检索所有元素。总大小计算为 elems * elem_size。这些值可以通过调用 VIDIOC_QUERY_EXT_CTRL 来获取。

要更改一组控件的值,应用程序需要初始化每个 struct v4l2_ext_controlidsizereserved2value/value64/string/ptr 字段,并调用 VIDIOC_S_EXT_CTRLS ioctl。只有在所有控件值都有效时,才会设置这些控件。

要检查一组控件是否具有正确的值,应用程序需要初始化每个 struct v4l2_ext_controlidsizereserved2value/value64/string/ptr 字段,并调用 VIDIOC_TRY_EXT_CTRLS ioctl。驱动程序可以自动将错误的值调整为有效值,也可以返回错误,具体取决于驱动程序。

idwhich 无效时,驱动程序会返回 EINVAL 错误代码。当值超出范围时,驱动程序可以选择采用最接近的有效值或返回 ERANGE 错误代码,无论哪种方式看起来更合适。在第一种情况下,新值将在 struct v4l2_ext_control 中设置。如果新的控件值不合适(例如,给定的菜单索引不受菜单控件支持),那么这将导致 EINVAL 错误代码错误。

如果 request_fd 设置为尚未排队的 请求 文件描述符,并且 which 设置为 V4L2_CTRL_WHICH_REQUEST_VAL,那么控件不会在调用 VIDIOC_S_EXT_CTRLS 时立即应用,而是由驱动程序为与同一请求关联的缓冲区应用。如果设备不支持请求,则将返回 EACCES。如果支持请求,但给出了无效的请求文件描述符,则将返回 EINVAL

尝试为已排队的请求调用 VIDIOC_S_EXT_CTRLS 将导致 EBUSY 错误。

如果在调用 VIDIOC_G_EXT_CTRLS 期间指定了 request_fd 并且 which 设置为 V4L2_CTRL_WHICH_REQUEST_VAL,那么它将返回请求完成时的控件值。如果请求尚未完成,那么这将导致 EACCES 错误。

只有在所有控件值都正确时,驱动程序才会设置/获取这些控件。这可以防止仅设置/获取部分控件的情况。只有低级错误(例如,i2c 命令失败)仍然会导致这种情况。

类型 v4l2_ext_control
struct v4l2_ext_control

__u32

id

标识控件,由应用程序设置。

__u32

size

此控件的有效负载的总大小(以字节为单位)。

size 字段通常为 0,但对于指针控件,应将其设置为包含有效负载或将接收有效负载的内存大小。如果 VIDIOC_G_EXT_CTRLS 发现此值小于存储有效负载结果所需的值,那么它将被设置为足够大以存储有效负载结果的值,并且返回 ENOSPC

注意

对于字符串控件,不应将此 size 字段与字符串的长度混淆。此字段指的是包含字符串的内存的大小。字符串的实际长度可能小得多。

__u32

reserved2[1]

保留供将来扩展使用。驱动程序和应用程序必须将数组设置为零。

union {

(anonymous)

__s32

value

新值或当前值。如果此控件的类型不是 V4L2_CTRL_TYPE_INTEGER64 且未设置 V4L2_CTRL_FLAG_HAS_PAYLOAD,则有效。

__s64

value64

新值或当前值。如果此控件的类型为 V4L2_CTRL_TYPE_INTEGER64 且未设置 V4L2_CTRL_FLAG_HAS_PAYLOAD,则有效。

char *

string

指向字符串的指针。如果此控件的类型为 V4L2_CTRL_TYPE_STRING,则有效。

__u8 *

p_u8

指向无符号 8 位值的矩阵控件的指针。如果此控件的类型为 V4L2_CTRL_TYPE_U8,则有效。

__u16 *

p_u16

指向无符号 16 位值的矩阵控件的指针。如果此控件的类型为 V4L2_CTRL_TYPE_U16,则有效。

__u32 *

p_u32

指向无符号 32 位值的矩阵控件的指针。如果此控件的类型为 V4L2_CTRL_TYPE_U32,则有效。

__s32 *

p_s32

指向有符号 32 位值的矩阵控件的指针。如果此控件的类型为 V4L2_CTRL_TYPE_INTEGER 且设置了 V4L2_CTRL_FLAG_HAS_PAYLOAD,则有效。

__s64 *

p_s64

指向有符号 64 位值的矩阵控件的指针。如果此控件的类型为 V4L2_CTRL_TYPE_INTEGER64 且设置了 V4L2_CTRL_FLAG_HAS_PAYLOAD,则有效。

struct v4l2_area *

p_area

指向 struct v4l2_area 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_AREA,则有效。

struct v4l2_rect *

p_rect

指向 struct v4l2_rect 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_RECT,则有效。

struct v4l2_ctrl_h264_sps *

p_h264_sps

指向 struct v4l2_ctrl_h264_sps 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_H264_SPS,则有效。

struct v4l2_ctrl_h264_pps *

p_h264_pps

指向 struct v4l2_ctrl_h264_pps 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_H264_PPS,则有效。

struct v4l2_ctrl_h264_scaling_matrix *

p_h264_scaling_matrix

指向 struct v4l2_ctrl_h264_scaling_matrix 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_H264_SCALING_MATRIX,则有效。

struct v4l2_ctrl_h264_pred_weights *

p_h264_pred_weights

指向 struct v4l2_ctrl_h264_pred_weights 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_H264_PRED_WEIGHTS,则有效。

struct v4l2_ctrl_h264_slice_params *

p_h264_slice_params

指向 struct v4l2_ctrl_h264_slice_params 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_H264_SLICE_PARAMS,则有效。

struct v4l2_ctrl_h264_decode_params *

p_h264_decode_params

指向 struct v4l2_ctrl_h264_decode_params 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_H264_DECODE_PARAMS,则有效。

struct v4l2_ctrl_fwht_params *

p_fwht_params

指向 struct v4l2_ctrl_fwht_params 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_FWHT_PARAMS,则有效。

struct v4l2_ctrl_vp8_frame *

p_vp8_frame

指向 struct v4l2_ctrl_vp8_frame 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_VP8_FRAME,则有效。

struct v4l2_ctrl_mpeg2_sequence *

p_mpeg2_sequence

指向 struct v4l2_ctrl_mpeg2_sequence 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_MPEG2_SEQUENCE,则有效。

struct v4l2_ctrl_mpeg2_picture *

p_mpeg2_picture

指向 struct v4l2_ctrl_mpeg2_picture 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_MPEG2_PICTURE,则有效。

struct v4l2_ctrl_mpeg2_quantisation *

p_mpeg2_quantisation

指向 struct v4l2_ctrl_mpeg2_quantisation 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_MPEG2_QUANTISATION,则有效。

struct v4l2_ctrl_vp9_compressed_hdr *

p_vp9_compressed_hdr_probs

指向 struct v4l2_ctrl_vp9_compressed_hdr 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR,则有效。

struct v4l2_ctrl_vp9_frame *

p_vp9_frame

指向 struct v4l2_ctrl_vp9_frame 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_VP9_FRAME,则有效。

struct v4l2_ctrl_hdr10_cll_info *

p_hdr10_cll

指向 struct v4l2_ctrl_hdr10_cll_info 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_HDR10_CLL_INFO,则有效。

struct v4l2_ctrl_hdr10_mastering_display *

p_hdr10_mastering

指向 struct v4l2_ctrl_hdr10_mastering_display 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY,则有效。

struct v4l2_ctrl_hevc_sps *

p_hevc_sps

指向 struct v4l2_ctrl_hevc_sps 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_HEVC_SPS,则有效。

struct v4l2_ctrl_hevc_pps *

p_hevc_pps

指向 struct v4l2_ctrl_hevc_pps 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_HEVC_PPS,则有效。

struct v4l2_ctrl_hevc_slice_params *

p_hevc_slice_params

指向 struct v4l2_ctrl_hevc_slice_params 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS,则有效。

struct v4l2_ctrl_hevc_scaling_matrix *

p_hevc_scaling_matrix

指向 struct v4l2_ctrl_hevc_scaling_matrix 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX,则有效。

struct v4l2_ctrl_hevc_decode_params *

p_hevc_decode_params

指向 struct v4l2_ctrl_hevc_decode_params 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS,则有效。

struct v4l2_ctrl_av1_sequence *

p_av1_sequence

指向 struct v4l2_ctrl_av1_sequence 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_AV1_SEQUENCE,则有效。

struct v4l2_ctrl_av1_tile_group_entry *

p_av1_tile_group_entry

指向 struct v4l2_ctrl_av1_tile_group_entry 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY,则有效。

struct v4l2_ctrl_av1_frame *

p_av1_frame

指向 struct v4l2_ctrl_av1_frame 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_AV1_FRAME,则有效。

struct v4l2_ctrl_av1_film_grain *

p_av1_film_grain

指向 struct v4l2_ctrl_av1_film_grain 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_AV1_FILM_GRAIN,则有效。

struct v4l2_ctrl_hdr10_cll_info *

p_hdr10_cll_info

指向 struct v4l2_ctrl_hdr10_cll_info 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_HDR10_CLL_INFO,则有效。

struct v4l2_ctrl_hdr10_mastering_display *

p_hdr10_mastering_display

指向 struct v4l2_ctrl_hdr10_mastering_display 的指针。如果此控件的类型为 V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY,则有效。

void *

ptr

指向复合类型的指针,该复合类型可以是 N 维数组和/或复合类型(控件的类型 >= V4L2_CTRL_COMPOUND_TYPES)。如果为此控件设置了 V4L2_CTRL_FLAG_HAS_PAYLOAD,则有效。

}

类型 v4l2_ext_controls
struct v4l2_ext_controls

union {

(anonymous)

__u32

which

要获取/设置/尝试的控件的值。

V4L2_CTRL_WHICH_CUR_VAL 将返回控件的当前值,V4L2_CTRL_WHICH_DEF_VAL 将返回控件的默认值,V4L2_CTRL_WHICH_MIN_VAL 将返回控件的最小值,V4L2_CTRL_WHICH_MAX_VAL 将返回控件的最大值。V4L2_CTRL_WHICH_REQUEST_VAL 指示必须从请求中检索控件值,或者为请求尝试/设置控件值。在这种情况下,request_fd 字段包含应使用的请求的文件描述符。如果设备不支持请求,则将返回 EACCES

使用 V4L2_CTRL_WHICH_DEF_VALV4L2_CTRL_WHICH_MIN_VALV4L2_CTRL_WHICH_MAX_VAL 时,请注意您只能获取控件的默认值/最小值/最大值,而不能设置或尝试它。

是否控件支持使用 V4L2_CTRL_WHICH_MIN_VALV4L2_CTRL_WHICH_MAX_VAL 查询最小值和最大值由 V4L2_CTRL_FLAG_HAS_WHICH_MIN_MAX 标志指示。大多数非复合控件类型都支持这一点。对于具有复合类型的控件,最小值/最大值的定义由控件文档提供。如果复合控件没有记录最小值/最大值的含义,那么查询最小值或最大值将导致错误代码 -EINVAL。

为了向后兼容,您也可以在此处使用控件类(参见 控件类)。在这种情况下,所有控件都必须属于该控件类。此用法已弃用,请改用 V4L2_CTRL_WHICH_CUR_VAL。有一些非常旧的驱动程序尚不支持 V4L2_CTRL_WHICH_CUR_VAL,并且需要在此处使用控件类。您可以通过将 which 设置为 V4L2_CTRL_WHICH_CUR_VAL 并使用计数 0 调用 VIDIOC_TRY_EXT_CTRLS 来测试此类驱动程序。如果这失败了,那么驱动程序不支持 V4L2_CTRL_WHICH_CUR_VAL

__u32

ctrl_class

为了向后兼容而保留的已弃用名称。请改用 which

}

__u32

count

控件数组中控件的数量。也可以为零。

__u32

error_idx

失败控件的索引。在发生错误时由驱动程序设置。

如果错误与特定控件相关联,则 error_idx 将设置为该控件的索引。如果错误与特定控件无关,或者验证步骤失败(请参见下文),则 error_idx 将设置为 count。如果 ioctl 返回 0(成功),则该值未定义。

在从硬件读取控件或写入硬件之前,会进行验证步骤:这会检查列表中的所有控件是否都是有效的控件,是否没有尝试写入只读控件或从只写控件读取,以及任何其他可以在不访问硬件的情况下进行的预先检查。在此步骤中完成的确切验证取决于驱动程序,因为某些检查可能需要硬件访问才能用于某些设备,因此无法进行预先检查。但是,驱动程序应尽最大努力进行尽可能多的预先检查。

进行此检查是为了避免由于容易避免的问题而使硬件处于不一致的状态。但这会导致另一个问题:应用程序需要知道错误是来自验证步骤(意味着未触及硬件)还是来自实际读取硬件或写入硬件期间的错误。

为此,事后看来很糟糕的解决方案是,如果验证失败,则将 error_idx 设置为 count。这会产生一个不幸的副作用,即无法看到哪个控件验证失败。如果验证成功并且在访问硬件时发生了错误,那么 error_idx 小于 count,并且只有到 error_idx-1 的控件被正确读取或写入,其余控件的状态未定义。

由于 VIDIOC_TRY_EXT_CTRLS 不访问硬件,因此也不需要以这种特殊方式处理验证步骤,所以 error_idx 将被设置为验证失败的控件,而不是 count。这意味着,如果 VIDIOC_S_EXT_CTRLS 失败,并且 error_idx 被设置为 count,那么您可以调用 VIDIOC_TRY_EXT_CTRLS 来尝试发现实际验证失败的控件。不幸的是,对于 VIDIOC_G_EXT_CTRLS,没有等效的 TRY 操作。

__s32

request_fd

用于此操作的请求的文件描述符。仅当 which 设置为 V4L2_CTRL_WHICH_REQUEST_VAL 时有效。如果设备不支持请求,则将返回 EACCES。如果支持请求,但给出了无效的请求文件描述符,则将返回 EINVAL

__u32

保留[1]

为将来的扩展保留。

驱动程序和应用程序必须将数组设置为零。

struct v4l2_ext_control *

控件

指向 count 个 v4l2_ext_control 结构体的数组的指针。

如果 count 等于零,则忽略。

控制类

V4L2_CTRL_CLASS_USER

0x980000

包含用户控件的类。这些控件在 用户控件 中描述。可以使用 VIDIOC_S_CTRLVIDIOC_G_CTRL ioctl 设置的所有控件都属于此类。

V4L2_CTRL_CLASS_CODEC

0x990000

包含有状态编解码器控件的类。这些控件在 编解码器控件参考 中描述。

V4L2_CTRL_CLASS_CAMERA

0x9a0000

包含相机控件的类。这些控件在 相机控件参考 中描述。

V4L2_CTRL_CLASS_FM_TX

0x9b0000

包含 FM 发射器 (FM TX) 控件的类。这些控件在 FM 发射器控件参考 中描述。

V4L2_CTRL_CLASS_FLASH

0x9c0000

包含闪光灯设备控件的类。这些控件在 闪光灯控件参考 中描述。

V4L2_CTRL_CLASS_JPEG

0x9d0000

包含 JPEG 压缩控件的类。这些控件在 JPEG 控件参考 中描述。

V4L2_CTRL_CLASS_IMAGE_SOURCE

0x9e0000

包含图像源控件的类。这些控件在 图像源控件参考 中描述。

V4L2_CTRL_CLASS_IMAGE_PROC

0x9f0000

包含图像处理控件的类。这些控件在 图像处理控件参考 中描述。

V4L2_CTRL_CLASS_FM_RX

0xa10000

包含 FM 接收器 (FM RX) 控件的类。这些控件在 FM 接收器控件参考 中描述。

V4L2_CTRL_CLASS_RF_TUNER

0xa20000

包含 RF 调谐器控件的类。这些控件在 RF 调谐器控件参考 中描述。

V4L2_CTRL_CLASS_DETECT

0xa30000

包含运动或物体检测控件的类。这些控件在 检测控件参考 中描述。

V4L2_CTRL_CLASS_CODEC_STATELESS

0xa40000

包含无状态编解码器控件的类。这些控件在 无状态编解码器控件参考 中描述。

V4L2_CTRL_CLASS_COLORIMETRY

0xa50000

包含色彩控件的类。这些控件在 色彩控件参考 中描述。

7.29.5. 返回值

成功时返回 0,出错时返回 -1,并且会适当地设置 errno 变量。通用错误代码在 通用错误代码 章节中描述。

EINVAL

struct v4l2_ext_control id 无效,或者 struct v4l2_ext_controls which 无效,或者 struct v4l2_ext_control value 不合适(例如,给定的菜单索引不受驱动程序支持),或者 which 字段设置为 V4L2_CTRL_WHICH_REQUEST_VAL,但给定的 request_fd 无效或内核不支持 V4L2_CTRL_WHICH_REQUEST_VAL。如果两个或多个控件值冲突,则 VIDIOC_S_EXT_CTRLSVIDIOC_TRY_EXT_CTRLS ioctl 也会返回此错误代码。

ERANGE

struct v4l2_ext_control value 超出范围。

EBUSY

控件暂时无法更改,可能是因为另一个应用程序接管了此控件所属的设备功能的控制,或者(如果 which 字段设置为 V4L2_CTRL_WHICH_REQUEST_VAL)请求已排队但尚未完成。

ENOSPC

为控件的有效载荷保留的空间不足。字段 size 设置为足以存储有效载荷的值,并返回此错误代码。

EACCES

尝试尝试或设置只读控件,或获取只写控件,或从尚未完成的请求中获取控件。

或者 which 字段设置为 V4L2_CTRL_WHICH_REQUEST_VAL,但设备不支持请求。

或者,如果尝试设置非活动控件,并且驱动程序无法缓存新值,直到控件再次激活。