Skip to content

Commit

Permalink
drivers: video_sw_generator: Add support to change frame rate
Browse files Browse the repository at this point in the history
Add code to to set / get / enumerate frame rates (intervals).

Signed-off-by: Phi Bang Nguyen <phibang.nguyen@nxp.com>
  • Loading branch information
ngphibang authored and mmahadevan108 committed Sep 24, 2024
1 parent 0cbaea0 commit 16fc8f8
Showing 1 changed file with 77 additions and 3 deletions.
80 changes: 77 additions & 3 deletions drivers/video/video_sw_generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,15 @@
LOG_MODULE_REGISTER(video_sw_generator, CONFIG_VIDEO_LOG_LEVEL);

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

struct video_sw_generator_data {
const struct device *dev;
Expand All @@ -26,6 +34,7 @@ struct video_sw_generator_data {
bool ctrl_hflip;
bool ctrl_vflip;
struct k_poll_signal *signal;
uint32_t frame_rate;
};

static const struct video_format_cap fmts[] = {{
Expand Down Expand Up @@ -93,7 +102,7 @@ static int video_sw_generator_stream_start(const struct device *dev)
{
struct video_sw_generator_data *data = dev->data;

k_work_schedule(&data->buf_work, K_MSEC(1000 / VIDEO_PATTERN_FPS));
k_work_schedule(&data->buf_work, K_MSEC(1000 / data->frame_rate));

return 0;
}
Expand Down Expand Up @@ -145,7 +154,7 @@ static void __buffer_work(struct k_work *work)

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

k_work_reschedule(&data->buf_work, K_MSEC(1000 / VIDEO_PATTERN_FPS));
k_work_reschedule(&data->buf_work, K_MSEC(1000 / data->frame_rate));

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

static int video_sw_generator_set_frmival(const struct device *dev, enum video_endpoint_id ep,
struct video_frmival *frmival)
{
struct video_sw_generator_data *data = dev->data;

if (frmival->denominator && frmival->numerator) {
data->frame_rate = MIN(DIV_ROUND_CLOSEST(frmival->denominator, frmival->numerator),
MAX_FRAME_RATE);
} else {
return -EINVAL;
}

frmival->numerator = 1;
frmival->denominator = data->frame_rate;

return 0;
}

static int video_sw_generator_get_frmival(const struct device *dev, enum video_endpoint_id ep,
struct video_frmival *frmival)
{
struct video_sw_generator_data *data = dev->data;

frmival->numerator = 1;
frmival->denominator = data->frame_rate;

return 0;
}

static int video_sw_generator_enum_frmival(const struct device *dev, enum video_endpoint_id ep,
struct video_frmival_enum *fie)
{
int i = 0;

if (ep != VIDEO_EP_OUT || fie->index) {
return -EINVAL;
}

while (fmts[i].pixelformat && (fmts[i].pixelformat != fie->format->pixelformat)) {
i++;
}

if ((i == ARRAY_SIZE(fmts)) || (fie->format->width > fmts[i].width_max) ||
(fie->format->width < fmts[i].width_min) ||
(fie->format->height > fmts[i].height_max) ||
(fie->format->height < fmts[i].height_min)) {
return -EINVAL;
}

fie->type = VIDEO_FRMIVAL_TYPE_STEPWISE;
fie->stepwise.min.numerator = 1;
fie->stepwise.min.denominator = MAX_FRAME_RATE;
fie->stepwise.max.numerator = UINT32_MAX;
fie->stepwise.max.denominator = 1;
/* The frame interval step size is the minimum resolution of K_MSEC(), which is 1ms */
fie->stepwise.step.numerator = 1;
fie->stepwise.step.denominator = 1000;

return 0;
}

static const struct video_driver_api video_sw_generator_driver_api = {
.set_format = video_sw_generator_set_fmt,
.get_format = video_sw_generator_get_fmt,
Expand All @@ -272,6 +342,9 @@ static const struct video_driver_api video_sw_generator_driver_api = {
.dequeue = video_sw_generator_dequeue,
.get_caps = video_sw_generator_get_caps,
.set_ctrl = video_sw_generator_set_ctrl,
.set_frmival = video_sw_generator_set_frmival,
.get_frmival = video_sw_generator_get_frmival,
.enum_frmival = video_sw_generator_enum_frmival,
#ifdef CONFIG_POLL
.set_signal = video_sw_generator_set_signal,
#endif
Expand All @@ -282,6 +355,7 @@ static struct video_sw_generator_data video_sw_generator_data_0 = {
.fmt.height = 160,
.fmt.pitch = 320 * 2,
.fmt.pixelformat = VIDEO_PIX_FMT_RGB565,
.frame_rate = DEFAULT_FRAME_RATE,
};

static int video_sw_generator_init(const struct device *dev)
Expand Down

0 comments on commit 16fc8f8

Please sign in to comment.