Skip to content

Commit e0197b6

Browse files
committed
drivers: video_sw_generator: Add support to change frame rate
Add code to to set / get / enumerate frame rates (intervals). Signed-off-by: Phi Bang Nguyen <[email protected]>
1 parent c48b390 commit e0197b6

File tree

1 file changed

+77
-3
lines changed

1 file changed

+77
-3
lines changed

drivers/video/video_sw_generator.c

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,15 @@
1313
LOG_MODULE_REGISTER(video_sw_generator, CONFIG_VIDEO_LOG_LEVEL);
1414

1515
#define VIDEO_PATTERN_COLOR_BAR 0
16-
#define VIDEO_PATTERN_FPS 30
16+
#define DEFAULT_FRAME_RATE 30
17+
/*
18+
* The pattern generator needs about 1.5 ms to fill out a 320x160 RGB565
19+
* buffer and 25 ms for a 720p XRGB32 buffer (tested on i.MX RT1064). So,
20+
* the max frame rate actually varies between 40 and 666 fps depending on
21+
* the buffer format. There is no way to determine this value for each
22+
* format. 60 fps is therefore chosen as a common value in practice.
23+
*/
24+
#define MAX_FRAME_RATE 60
1725

1826
struct video_sw_generator_data {
1927
const struct device *dev;
@@ -26,6 +34,7 @@ struct video_sw_generator_data {
2634
bool ctrl_hflip;
2735
bool ctrl_vflip;
2836
struct k_poll_signal *signal;
37+
uint32_t frame_rate;
2938
};
3039

3140
static const struct video_format_cap fmts[] = {{
@@ -93,7 +102,7 @@ static int video_sw_generator_stream_start(const struct device *dev)
93102
{
94103
struct video_sw_generator_data *data = dev->data;
95104

96-
k_work_schedule(&data->buf_work, K_MSEC(1000 / VIDEO_PATTERN_FPS));
105+
k_work_schedule(&data->buf_work, K_MSEC(1000 / data->frame_rate));
97106

98107
return 0;
99108
}
@@ -145,7 +154,7 @@ static void __buffer_work(struct k_work *work)
145154

146155
data = CONTAINER_OF(dwork, struct video_sw_generator_data, buf_work);
147156

148-
k_work_reschedule(&data->buf_work, K_MSEC(1000 / VIDEO_PATTERN_FPS));
157+
k_work_reschedule(&data->buf_work, K_MSEC(1000 / data->frame_rate));
149158

150159
vbuf = k_fifo_get(&data->fifo_in, K_NO_WAIT);
151160
if (vbuf == NULL) {
@@ -262,6 +271,67 @@ static inline int video_sw_generator_set_ctrl(const struct device *dev, unsigned
262271
return 0;
263272
}
264273

274+
static int video_sw_generator_set_frmival(const struct device *dev, enum video_endpoint_id ep,
275+
struct video_frmival *frmival)
276+
{
277+
struct video_sw_generator_data *data = dev->data;
278+
279+
if (frmival->denominator && frmival->numerator) {
280+
data->frame_rate = MIN(DIV_ROUND_CLOSEST(frmival->denominator, frmival->numerator),
281+
MAX_FRAME_RATE);
282+
} else {
283+
return -EINVAL;
284+
}
285+
286+
frmival->numerator = 1;
287+
frmival->denominator = data->frame_rate;
288+
289+
return 0;
290+
}
291+
292+
static int video_sw_generator_get_frmival(const struct device *dev, enum video_endpoint_id ep,
293+
struct video_frmival *frmival)
294+
{
295+
struct video_sw_generator_data *data = dev->data;
296+
297+
frmival->numerator = 1;
298+
frmival->denominator = data->frame_rate;
299+
300+
return 0;
301+
}
302+
303+
static int video_sw_generator_enum_frmival(const struct device *dev, enum video_endpoint_id ep,
304+
struct video_frmival_enum *fie)
305+
{
306+
int i = 0;
307+
308+
if (ep != VIDEO_EP_OUT || fie->index) {
309+
return -EINVAL;
310+
}
311+
312+
while (fmts[i].pixelformat && (fmts[i].pixelformat != fie->format->pixelformat)) {
313+
i++;
314+
}
315+
316+
if ((i == ARRAY_SIZE(fmts)) || (fie->format->width > fmts[i].width_max) ||
317+
(fie->format->width < fmts[i].width_min) ||
318+
(fie->format->height > fmts[i].height_max) ||
319+
(fie->format->height < fmts[i].height_min)) {
320+
return -EINVAL;
321+
}
322+
323+
fie->type = VIDEO_FRMIVAL_TYPE_STEPWISE;
324+
fie->stepwise.min.numerator = 1;
325+
fie->stepwise.min.denominator = MAX_FRAME_RATE;
326+
fie->stepwise.max.numerator = UINT32_MAX;
327+
fie->stepwise.max.denominator = 1;
328+
/* The frame interval step size is the minimum resolution of K_MSEC(), which is 1ms */
329+
fie->stepwise.step.numerator = 1;
330+
fie->stepwise.step.denominator = 1000;
331+
332+
return 0;
333+
}
334+
265335
static const struct video_driver_api video_sw_generator_driver_api = {
266336
.set_format = video_sw_generator_set_fmt,
267337
.get_format = video_sw_generator_get_fmt,
@@ -272,6 +342,9 @@ static const struct video_driver_api video_sw_generator_driver_api = {
272342
.dequeue = video_sw_generator_dequeue,
273343
.get_caps = video_sw_generator_get_caps,
274344
.set_ctrl = video_sw_generator_set_ctrl,
345+
.set_frmival = video_sw_generator_set_frmival,
346+
.get_frmival = video_sw_generator_get_frmival,
347+
.enum_frmival = video_sw_generator_enum_frmival,
275348
#ifdef CONFIG_POLL
276349
.set_signal = video_sw_generator_set_signal,
277350
#endif
@@ -282,6 +355,7 @@ static struct video_sw_generator_data video_sw_generator_data_0 = {
282355
.fmt.height = 160,
283356
.fmt.pitch = 320 * 2,
284357
.fmt.pixelformat = VIDEO_PIX_FMT_RGB565,
358+
.frame_rate = DEFAULT_FRAME_RATE,
285359
};
286360

287361
static int video_sw_generator_init(const struct device *dev)

0 commit comments

Comments
 (0)