Skip to content

Commit 16d2bbd

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 ef1b48a commit 16d2bbd

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;
@@ -173,3 +184,131 @@ int video_set_ctrl(const struct device *dev, struct video_control *control)
173184

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

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
*/
@@ -183,6 +196,33 @@ struct video_control {
183196
int32_t val;
184197
};
185198

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

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)