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 设置为尚未排队的 request 文件描述符,并且 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 命令失败)仍然可能导致这种情况。

type v4l2_ext_control
struct v4l2_ext_control

__u32

id

标识应用程序设置的控件。

__u32

size

此控件有效载荷的总字节大小。

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

注意

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

__u32

reserved2[1]

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

union {

(匿名)

__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

指向结构体 v4l2_area 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_AREA,则此值有效。

struct v4l2_ctrl_h264_sps *

p_h264_sps

指向结构体 v4l2_ctrl_h264_sps 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_H264_SPS,则此值有效。

struct v4l2_ctrl_h264_pps *

p_h264_pps

指向结构体 v4l2_ctrl_h264_pps 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_H264_PPS,则此值有效。

struct v4l2_ctrl_h264_scaling_matrix *

p_h264_scaling_matrix

指向结构体 v4l2_ctrl_h264_scaling_matrix 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_H264_SCALING_MATRIX,则此值有效。

struct v4l2_ctrl_h264_pred_weights *

p_h264_pred_weights

指向结构体 v4l2_ctrl_h264_pred_weights 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_H264_PRED_WEIGHTS,则此值有效。

struct v4l2_ctrl_h264_slice_params *

p_h264_slice_params

指向结构体 v4l2_ctrl_h264_slice_params 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_H264_SLICE_PARAMS,则此值有效。

struct v4l2_ctrl_h264_decode_params *

p_h264_decode_params

指向结构体 v4l2_ctrl_h264_decode_params 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_H264_DECODE_PARAMS,则此值有效。

struct v4l2_ctrl_fwht_params *

p_fwht_params

指向结构体 v4l2_ctrl_fwht_params 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_FWHT_PARAMS,则此值有效。

struct v4l2_ctrl_vp8_frame *

p_vp8_frame

指向结构体 v4l2_ctrl_vp8_frame 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_VP8_FRAME,则此值有效。

struct v4l2_ctrl_mpeg2_sequence *

p_mpeg2_sequence

指向结构体 v4l2_ctrl_mpeg2_sequence 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_MPEG2_SEQUENCE,则此值有效。

struct v4l2_ctrl_mpeg2_picture *

p_mpeg2_picture

指向结构体 v4l2_ctrl_mpeg2_picture 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_MPEG2_PICTURE,则此值有效。

struct v4l2_ctrl_mpeg2_quantisation *

p_mpeg2_quantisation

指向结构体 v4l2_ctrl_mpeg2_quantisation 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_MPEG2_QUANTISATION,则此值有效。

struct v4l2_ctrl_vp9_compressed_hdr *

p_vp9_compressed_hdr_probs

指向结构体 v4l2_ctrl_vp9_compressed_hdr 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR,则此值有效。

struct v4l2_ctrl_vp9_frame *

p_vp9_frame

指向结构体 v4l2_ctrl_vp9_frame 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_VP9_FRAME,则此值有效。

struct v4l2_ctrl_hdr10_cll_info *

p_hdr10_cll

指向结构体 v4l2_ctrl_hdr10_cll_info 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_HDR10_CLL_INFO,则此值有效。

struct v4l2_ctrl_hdr10_mastering_display *

p_hdr10_mastering

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

struct v4l2_ctrl_hevc_sps *

p_hevc_sps

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

struct v4l2_ctrl_hevc_pps *

p_hevc_pps

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

struct v4l2_ctrl_hevc_slice_params *

p_hevc_slice_params

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

struct v4l2_ctrl_hevc_scaling_matrix *

p_hevc_scaling_matrix

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

struct v4l2_ctrl_hevc_decode_params *

p_hevc_decode_params

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

struct v4l2_ctrl_av1_sequence *

p_av1_sequence

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

struct v4l2_ctrl_av1_tile_group_entry *

p_av1_tile_group_entry

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

struct v4l2_ctrl_av1_frame *

p_av1_frame

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

struct v4l2_ctrl_av1_film_grain *

p_av1_film_grain

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

struct v4l2_ctrl_hdr10_cll_info *

p_hdr10_cll_info

指向结构体 v4l2_ctrl_hdr10_cll_info 的指针。如果此控件的类型是 V4L2_CTRL_TYPE_HDR10_CLL_INFO,则此值有效。

struct v4l2_ctrl_hdr10_mastering_display *

p_hdr10_mastering_display

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

void *

ptr

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

}

type v4l2_ext_controls
struct v4l2_ext_controls

union {

(匿名)

__u32

which

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

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

使用 V4L2_CTRL_WHICH_DEF_VAL 时,请注意只能获取控件的默认值,不能设置或尝试它。

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

__u32

ctrl_class

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

}

__u32

count

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

__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_CTRLSTRY 等效项。

__s32

request_fd

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

__u32

reserved[1]

为将来的扩展保留。

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

struct v4l2_ext_control *

controls

指向 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

结构体 v4l2_ext_controlid 无效,或者结构体 v4l2_ext_controlswhich 无效,或者结构体 v4l2_ext_controlvalue 不合适(例如,驱动程序不支持给定的菜单索引),或者 which 字段设置为 V4L2_CTRL_WHICH_REQUEST_VAL 但给定的 request_fd 无效或内核不支持 V4L2_CTRL_WHICH_REQUEST_VAL。如果两个或多个控制值冲突,VIDIOC_S_EXT_CTRLSVIDIOC_TRY_EXT_CTRLS ioctl 也会返回此错误代码。

ERANGE

结构体 v4l2_ext_controlvalue 超出范围。

EBUSY

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

ENOSPC

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

EACCES

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

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

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