diff --git a/src/v4l2.c b/src/v4l2.c index 3addb33..765b05f 100644 --- a/src/v4l2.c +++ b/src/v4l2.c @@ -508,3 +508,63 @@ int v4l2_set_stream(int video_fd, unsigned int type, bool enable) return 0; } + +int v4l2_query_ext_ctrl(int video_fd, unsigned int id, + struct v4l2_query_ext_ctrl *qec) +{ + struct v4l2_query_ext_ctrl local; + struct v4l2_query_ext_ctrl *target = qec ? qec : &local; + int rc; + + memset(target, 0, sizeof(*target)); + target->id = id; + + rc = ioctl(video_fd, VIDIOC_QUERY_EXT_CTRL, target); + if (rc < 0) + return -1; + + return 0; +} + +int v4l2_query_menu(int video_fd, unsigned int id, unsigned int index, + struct v4l2_querymenu *qm) +{ + int rc; + + if (qm == NULL) + return -1; + + memset(qm, 0, sizeof(*qm)); + qm->id = id; + qm->index = index; + + rc = ioctl(video_fd, VIDIOC_QUERYMENU, qm); + if (rc < 0) + return -1; + + return 0; +} + +bool v4l2_ctrl_menu_has_value(int video_fd, unsigned int id, + unsigned int value) +{ + struct v4l2_query_ext_ctrl qec; + struct v4l2_querymenu qm; + long long i; + + if (v4l2_query_ext_ctrl(video_fd, id, &qec) < 0) + return false; + + if (qec.type != V4L2_CTRL_TYPE_MENU && + qec.type != V4L2_CTRL_TYPE_INTEGER_MENU) + return false; + + for (i = qec.minimum; i <= qec.maximum; i += qec.step ? qec.step : 1) { + if (v4l2_query_menu(video_fd, id, (unsigned int)i, &qm) < 0) + continue; + if ((unsigned int)i == value) + return true; + } + + return false; +} diff --git a/src/v4l2.h b/src/v4l2.h index 24c12a0..ddb8f86 100644 --- a/src/v4l2.h +++ b/src/v4l2.h @@ -64,4 +64,37 @@ int v4l2_set_control(int video_fd, int request_fd, unsigned int id, void *data, unsigned int size); int v4l2_set_stream(int video_fd, unsigned int type, bool enable); +/* + * Capability-probe helpers. These let calling code discover what the + * backing kernel driver supports rather than hardcoding assumptions + * about specific decoder hardware. + */ + +/* + * Query the metadata of an extended control by CID. Fills *qec on + * success. Returns 0 if the control exists, -1 (errno=EINVAL) if the + * driver does not expose this CID. Pass qec=NULL to test existence + * only. + */ +struct v4l2_query_ext_ctrl; +int v4l2_query_ext_ctrl(int video_fd, unsigned int id, + struct v4l2_query_ext_ctrl *qec); + +/* + * Query a single menu item of a menu/intmenu control at the given + * index. Fills *qm on success. Returns 0 if the menu item exists at + * this index, -1 otherwise. + */ +struct v4l2_querymenu; +int v4l2_query_menu(int video_fd, unsigned int id, unsigned int index, + struct v4l2_querymenu *qm); + +/* + * Convenience: for a menu-type control, return true iff `value` is a + * valid menu entry (i.e. the driver accepts it). Walks all menu items + * up to the control's maximum to check. + */ +bool v4l2_ctrl_menu_has_value(int video_fd, unsigned int id, + unsigned int value); + #endif