1313LOG_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
1826struct 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
3140static 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+
265335static 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
287361static int video_sw_generator_init (const struct device * dev )
0 commit comments