Skip to content

Commit 15b1dd8

Browse files
committed
drivers: video: Add video query control API
Application can query information about a control given the control id, the framework fill the rest of the structure. Application can also enumerate all kinds of device's supported controls by iterating with VIDEO_CTRL_FLAG_NEXT_CTRL on the same API. Signed-off-by: Phi Bang Nguyen <phibang.nguyen@nxp.com>
1 parent f93440a commit 15b1dd8

File tree

4 files changed

+225
-0
lines changed

4 files changed

+225
-0
lines changed

drivers/video/video_ctrls.c

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
#include <stdio.h>
8+
79
#include <zephyr/drivers/video.h>
810
#include <zephyr/drivers/video-controls.h>
911
#include <zephyr/logging/log.h>
@@ -67,6 +69,7 @@ int video_init_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint32_t
6769
int ret;
6870
uint32_t flags;
6971
enum video_ctrl_type type;
72+
struct video_ctrl *vc;
7073
struct video_device *vdev = video_find_vdev(dev);
7174

7275
if (!vdev) {
@@ -95,6 +98,14 @@ int video_init_ctrl(struct video_ctrl *ctrl, const struct device *dev, uint32_t
9598
ctrl->def = def;
9699
ctrl->val = def;
97100

101+
/* Insert in an ascending order of ctrl's id */
102+
SYS_DLIST_FOR_EACH_CONTAINER(&vdev->ctrls, vc, node) {
103+
if (vc->id > ctrl->id) {
104+
sys_dlist_insert(&vc->node, &ctrl->node);
105+
return 0;
106+
}
107+
}
108+
98109
sys_dlist_append(&vdev->ctrls, &ctrl->node);
99110

100111
return 0;
@@ -172,3 +183,131 @@ int video_set_ctrl(const struct device *dev, struct video_control *control)
172183

173184
return 0;
174185
}
186+
187+
static inline const char *video_get_ctrl_name(uint32_t id)
188+
{
189+
switch (id) {
190+
/* User controls */
191+
case VIDEO_CID_BRIGHTNESS:
192+
return "Brightness";
193+
case VIDEO_CID_CONTRAST:
194+
return "Contrast";
195+
case VIDEO_CID_SATURATION:
196+
return "Saturation";
197+
case VIDEO_CID_HUE:
198+
return "Hue";
199+
case VIDEO_CID_EXPOSURE:
200+
return "Exposure";
201+
case VIDEO_CID_GAIN:
202+
return "Gain";
203+
case VIDEO_CID_HFLIP:
204+
return "Horizontal Flip";
205+
case VIDEO_CID_VFLIP:
206+
return "Vertical Flip";
207+
case VIDEO_CID_POWER_LINE_FREQUENCY:
208+
return "Power Line Frequency";
209+
210+
/* Camera controls */
211+
case VIDEO_CID_ZOOM_ABSOLUTE:
212+
return "Zoom, Absolute";
213+
214+
/* JPEG encoder controls */
215+
case VIDEO_CID_JPEG_COMPRESSION_QUALITY:
216+
return "Compression Quality";
217+
218+
/* Image processing controls */
219+
case VIDEO_CID_PIXEL_RATE:
220+
return "Pixel Rate";
221+
case VIDEO_CID_TEST_PATTERN:
222+
return "Test Pattern";
223+
default:
224+
return NULL;
225+
}
226+
}
227+
228+
int video_query_ctrl(const struct device *dev, struct video_ctrl_query *cq)
229+
{
230+
int ret;
231+
struct video_device *vdev;
232+
struct video_ctrl *ctrl = NULL;
233+
234+
if (cq->id & VIDEO_CTRL_FLAG_NEXT_CTRL) {
235+
vdev = video_find_vdev(dev);
236+
cq->id &= ~VIDEO_CTRL_FLAG_NEXT_CTRL;
237+
while (vdev) {
238+
SYS_DLIST_FOR_EACH_CONTAINER(&vdev->ctrls, ctrl, node) {
239+
if (ctrl->id > cq->id) {
240+
goto fill_query;
241+
}
242+
}
243+
vdev = video_find_vdev(vdev->src_dev);
244+
}
245+
return -ENOTSUP;
246+
}
247+
248+
ret = video_find_ctrl(dev, cq->id, &ctrl);
249+
if (ret) {
250+
return ret;
251+
}
252+
253+
fill_query:
254+
cq->id = ctrl->id;
255+
cq->type = ctrl->type;
256+
cq->flags = ctrl->flags;
257+
cq->min = ctrl->min;
258+
cq->max = ctrl->max;
259+
cq->step = ctrl->step;
260+
cq->def = ctrl->def;
261+
cq->name = video_get_ctrl_name(cq->id);
262+
263+
return 0;
264+
}
265+
266+
void video_print_ctrl(const struct device *const dev, const struct video_ctrl_query *const cq)
267+
{
268+
uint8_t i = 0;
269+
const char *type = NULL;
270+
char typebuf[8];
271+
272+
__ASSERT(dev && cq, "Invalid arguments");
273+
274+
/* Get type of the control */
275+
switch (cq->type) {
276+
case VIDEO_CTRL_TYPE_BOOLEAN:
277+
type = "bool";
278+
break;
279+
case VIDEO_CTRL_TYPE_INTEGER:
280+
type = "int";
281+
break;
282+
case VIDEO_CTRL_TYPE_INTEGER64:
283+
type = "int64";
284+
break;
285+
case VIDEO_CTRL_TYPE_MENU:
286+
type = "menu";
287+
break;
288+
case VIDEO_CTRL_TYPE_STRING:
289+
type = "string";
290+
break;
291+
default:
292+
break;
293+
}
294+
snprintf(typebuf, sizeof(typebuf), "(%s)", type);
295+
296+
/* Get current value of the control */
297+
struct video_control vc = {.id = cq->id};
298+
299+
video_get_ctrl(dev, &vc);
300+
301+
/* Print the control information */
302+
if (cq->type == VIDEO_CTRL_TYPE_INTEGER64) {
303+
LOG_INF("%32s 0x%08x %-8s (flags=0x%02x) : min=%lld max=%lld step=%lld "
304+
"default=%lld value=%lld ",
305+
cq->name, cq->id, typebuf, cq->flags, cq->range.min64, cq->range.max64,
306+
cq->range.step64, cq->range.def64, vc.val64);
307+
} else {
308+
LOG_INF("%32s 0x%08x %-8s (flags=0x%02x) : min=%d max=%d step=%d default=%d "
309+
"value=%d ",
310+
cq->name, cq->id, typebuf, cq->flags, cq->range.min, cq->range.max,
311+
cq->range.step, cq->range.def, vc.val);
312+
}
313+
}

include/zephyr/drivers/video-controls.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ enum video_power_line_frequency {
7878
/** Balance of colors in direction of blue (cold) or red (warm) */
7979
#define VIDEO_CID_WHITE_BALANCE_TEMPERATURE (VIDEO_CID_BASE + 26)
8080

81+
/** Last base CID + 1 */
82+
#define VIDEO_CID_LASTP1 (VIDEO_CID_BASE + 44)
83+
8184
/**
8285
* @}
8386
*/
@@ -160,6 +163,16 @@ enum video_power_line_frequency {
160163
*/
161164
#define VIDEO_CID_PRIVATE_BASE 0x08000000
162165

166+
/**
167+
* @}
168+
*/
169+
170+
/**
171+
* @name Query flags, to be ORed with the control ID
172+
* @{
173+
*/
174+
#define VIDEO_CTRL_FLAG_NEXT_CTRL 0x80000000
175+
163176
/**
164177
* @}
165178
*/
@@ -182,6 +195,33 @@ struct video_control {
182195
int32_t val;
183196
};
184197

198+
/**
199+
* @struct video_control_query
200+
* @brief Video control query structure
201+
*
202+
* Used to query information about a control.
203+
*/
204+
struct video_ctrl_query {
205+
/** control id */
206+
uint32_t id;
207+
/** control type */
208+
uint32_t type;
209+
/** control name */
210+
const char *name;
211+
/** control flags */
212+
uint32_t flags;
213+
/** control minimum value, inclusive */
214+
int32_t min;
215+
/** control maximum value, inclusive */
216+
int32_t max;
217+
/** control value step */
218+
int32_t step;
219+
/** control default value for VIDEO_CTRL_TYPE_INTEGER, _BOOLEAN, _MENU or
220+
* _INTEGER_MENU, not valid for other types
221+
*/
222+
int32_t def;
223+
};
224+
185225
/**
186226
* @}
187227
*/

include/zephyr/drivers/video.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,41 @@ int video_set_ctrl(const struct device *dev, struct video_control *control);
672672
*/
673673
int video_get_ctrl(const struct device *dev, struct video_control *control);
674674

675+
struct video_ctrl_query;
676+
677+
/**
678+
* @brief Query information about a control.
679+
*
680+
* Applications set the id field of the query structure, the function fills the rest of this
681+
* structure. It is possible to enumerate base class controls (i.e., VIDEO_CID_BASE + x) by calling
682+
* this function with successive id values starting from VIDEO_CID_BASE up to and exclusive
683+
* VIDEO_CID_LASTP1. The function may return -ENOTSUP if a control in this range is not supported.
684+
* Applications can also enumerate private controls by starting at VIDEO_CID_PRIVATE_BASE and
685+
* incrementing the id until the driver returns -ENOTSUP. For other control classes, it's a bit more
686+
* difficult. Hence, the best way to enumerate all kinds of device's supported controls is to
687+
* iterate with VIDEO_CTRL_FLAG_NEXT_CTRL.
688+
*
689+
* @param dev Pointer to the device structure.
690+
* @param cq Pointer to the control query struct.
691+
*
692+
* @retval 0 If successful.
693+
* @retval -EINVAL If the control id is invalid.
694+
* @retval -ENOTSUP If the control id is not supported.
695+
*/
696+
int video_query_ctrl(const struct device *dev, struct video_ctrl_query *cq);
697+
698+
/**
699+
* @brief Print all the information of a control.
700+
*
701+
* Print all the information of a control including its name, type, flag, range,
702+
* menu (if any) and current value, i.e. by invoking the video_get_ctrl(), in a
703+
* human readble format.
704+
*
705+
* @param dev Pointer to the device structure.
706+
* @param cq Pointer to the control query struct.
707+
*/
708+
void video_print_ctrl(const struct device *const dev, const struct video_ctrl_query *const cq);
709+
675710
/**
676711
* @brief Register/Unregister k_poll signal for a video endpoint.
677712
*

samples/drivers/video/capture/src/main.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2019 Linaro Limited
3+
* Copyright 2025 NXP
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
@@ -174,6 +175,16 @@ int main(void)
174175
fie.index++;
175176
}
176177

178+
/* Get supported controls */
179+
LOG_INF("- Supported controls:");
180+
181+
struct video_ctrl_query cq = {.id = VIDEO_CTRL_FLAG_NEXT_CTRL};
182+
183+
while (!video_query_ctrl(video_dev, &cq)) {
184+
video_print_ctrl(video_dev, &cq);
185+
cq.id |= VIDEO_CTRL_FLAG_NEXT_CTRL;
186+
}
187+
177188
/* Set controls */
178189
struct video_control ctrl = {VIDEO_CID_HFLIP, 1};
179190

0 commit comments

Comments
 (0)