@@ -19,13 +19,37 @@ LOG_MODULE_REGISTER(uvc_sample, LOG_LEVEL_INF);
1919
2020const static struct device * const uvc_dev = DEVICE_DT_GET (DT_NODELABEL (uvc ));
2121const static struct device * const video_dev = DEVICE_DT_GET (DT_CHOSEN (zephyr_camera ));
22+ static const struct device * const videoenc_dev = DEVICE_DT_GET_OR_NULL (DT_CHOSEN (zephyr_videoenc ));
2223
2324/* Format capabilities of video_dev, used everywhere through the sample */
2425static struct video_caps video_caps = {.type = VIDEO_BUF_TYPE_OUTPUT };
26+ static struct video_caps videoenc_out_caps = {.type = VIDEO_BUF_TYPE_OUTPUT };
27+
28+ #if DT_HAS_CHOSEN (zephyr_videoenc ) && CONFIG_VIDEO_BUFFER_POOL_NUM_MAX < 2
29+ #error CONFIG_VIDEO_BUFFER_POOL_NUM_MAX must be >=2 in order to use a zephyr,videoenc
30+ #endif
31+
32+ static bool app_has_videoenc (void )
33+ {
34+ return (videoenc_dev != NULL );
35+ }
2536
2637static const struct device * app_uvc_source_dev (void )
2738{
28- return video_dev ;
39+ if (app_has_videoenc ()) {
40+ return videoenc_dev ;
41+ } else {
42+ return video_dev ;
43+ }
44+ }
45+
46+ static struct video_caps * app_uvc_source_caps (void )
47+ {
48+ if (app_has_videoenc ()) {
49+ return & videoenc_out_caps ;
50+ } else {
51+ return & video_caps ;
52+ }
2953}
3054
3155/* Pixel formats present in one of the UVC 1.5 standard */
@@ -38,7 +62,7 @@ static bool app_is_supported_format(uint32_t pixfmt)
3862
3963static bool app_has_supported_format (void )
4064{
41- const struct video_format_cap * fmts = video_caps . format_caps ;
65+ const struct video_format_cap * fmts = app_uvc_source_caps () -> format_caps ;
4266
4367 for (int i = 0 ; fmts [i ].pixelformat != 0 ; i ++ ) {
4468 if (app_is_supported_format (fmts [i ].pixelformat )) {
@@ -103,12 +127,14 @@ static struct video_resolution video_common_fmts[] = {
103127static void app_add_filtered_formats (void )
104128{
105129 const bool has_sup_fmts = app_has_supported_format ();
130+ struct video_caps * uvc_src_caps = app_uvc_source_caps ();
106131
107- for (int i = 0 ; video_caps .format_caps [i ].pixelformat != 0 ; i ++ ) {
132+ for (int i = 0 ; uvc_src_caps -> format_caps [i ].pixelformat != 0 ; i ++ ) {
133+ uint32_t pixelformat = uvc_src_caps -> format_caps [i ].pixelformat ;
108134 const struct video_format_cap * vcap = & video_caps .format_caps [i ];
109135 int count = 1 ;
110136
111- app_add_format (vcap -> pixelformat , vcap -> width_min , vcap -> height_min , has_sup_fmts );
137+ app_add_format (pixelformat , vcap -> width_min , vcap -> height_min , has_sup_fmts );
112138
113139 if (vcap -> width_min != vcap -> width_max || vcap -> height_min != vcap -> height_max ) {
114140 app_add_format (vcap -> pixelformat , vcap -> width_max , vcap -> height_max ,
@@ -138,19 +164,119 @@ static void app_add_filtered_formats(void)
138164 continue ;
139165 }
140166
141- app_add_format (vcap -> pixelformat , video_common_fmts [j ].width ,
167+ app_add_format (pixelformat , video_common_fmts [j ].width ,
142168 video_common_fmts [j ].height , has_sup_fmts );
143169 count ++ ;
144170 }
145171 }
146172}
147173
174+ static int app_init_videoenc (const struct device * const dev )
175+ {
176+ int ret ;
177+
178+ if (!device_is_ready (dev )) {
179+ LOG_ERR ("video encoder %s failed to initialize" , dev -> name );
180+ return - ENODEV ;
181+ }
182+
183+ ret = video_get_caps (dev , & videoenc_out_caps );
184+ if (ret != 0 ) {
185+ LOG_ERR ("Unable to retrieve video encoder output capabilities" );
186+ return ret ;
187+ }
188+
189+ /*
190+ * FIXME - we should look carefully at both video capture output and encoder input
191+ * caps to detect intermediate format.
192+ * This is where we should define the format which is going to be used
193+ * between the camera and the encoder input
194+ */
195+
196+ return 0 ;
197+ }
198+
199+ static int app_configure_videoenc (const struct device * const dev ,
200+ uint32_t width , uint32_t height ,
201+ uint32_t sink_pixelformat , uint32_t source_pixelformat ,
202+ uint32_t nb_buffer )
203+ {
204+ struct video_format fmt = {
205+ .width = width ,
206+ .height = height ,
207+ };
208+ struct video_buffer * buf ;
209+ int ret ;
210+
211+ /*
212+ * Need to configure both input & output of the encoder
213+ * and allocate / enqueue buffers to the output of the
214+ * encoder
215+ */
216+ fmt .type = VIDEO_BUF_TYPE_INPUT ;
217+ fmt .pixelformat = sink_pixelformat ;
218+ ret = video_set_compose_format (dev , & fmt );
219+ if (ret != 0 ) {
220+ LOG_ERR ("Could not set the %s encoder input format" , dev -> name );
221+ return ret ;
222+ }
223+
224+ fmt .type = VIDEO_BUF_TYPE_OUTPUT ;
225+ fmt .pixelformat = source_pixelformat ;
226+ ret = video_set_compose_format (dev , & fmt );
227+ if (ret != 0 ) {
228+ LOG_ERR ("Could not set the %s encoder output format" , dev -> name );
229+ return ret ;
230+ }
231+
232+ LOG_INF ("Preparing %u buffers of %u bytes for encoder output" , nb_buffer , fmt .size );
233+
234+ for (int i = 0 ; i < nb_buffer ; i ++ ) {
235+ buf = video_buffer_aligned_alloc (fmt .size , CONFIG_VIDEO_BUFFER_POOL_ALIGN ,
236+ K_NO_WAIT );
237+ if (buf == NULL ) {
238+ LOG_ERR ("Could not allocate the encoder output buffer" );
239+ return - ENOMEM ;
240+ }
241+
242+ buf -> type = VIDEO_BUF_TYPE_OUTPUT ;
243+
244+ ret = video_enqueue (dev , buf );
245+ if (ret != 0 ) {
246+ LOG_ERR ("Could not enqueue video buffer" );
247+ return ret ;
248+ }
249+ }
250+
251+ return 0 ;
252+ }
253+
254+ static int app_start_videoenc (const struct device * const dev )
255+ {
256+ int ret ;
257+
258+ ret = video_stream_start (dev , VIDEO_BUF_TYPE_OUTPUT );
259+ if (ret != 0 ) {
260+ LOG_ERR ("Failed to start %s output" , dev -> name );
261+ return ret ;
262+ }
263+
264+ ret = video_stream_start (dev , VIDEO_BUF_TYPE_INPUT );
265+ if (ret != 0 ) {
266+ LOG_ERR ("Failed to start %s input" , dev -> name );
267+ return ret ;
268+ }
269+
270+ return 0 ;
271+ }
272+
148273int main (void )
149274{
150275 const struct device * uvc_src_dev = app_uvc_source_dev ();
151276 struct usbd_context * sample_usbd ;
152277 struct video_buffer * vbuf ;
153278 struct video_format fmt = {0 };
279+ uint32_t uvc_buf_count = CONFIG_VIDEO_BUFFER_POOL_NUM_MAX ;
154280 struct video_frmival frmival = {0 };
155281 struct k_poll_signal sig ;
156282 struct k_poll_event evt [1 ];
@@ -168,6 +294,16 @@ int main(void)
168294 return 0 ;
169295 }
170296
297+ if (app_has_videoenc ()) {
298+ ret = app_init_videoenc (videoenc_dev );
299+ if (ret != 0 ) {
300+ return ret ;
301+ }
302+
303+ /* When using encoder, we split the VIDEO_BUFFER_POOL_NUM_MAX in 2 */
304+ uvc_buf_count /= 2 ;
305+ }
306+
171307 /* Must be called before usb_enable() */
172308 uvc_set_video_dev (uvc_dev , uvc_src_dev );
173309
@@ -211,7 +347,27 @@ int main(void)
211347 VIDEO_FOURCC_TO_STR (fmt .pixelformat ), fmt .width , fmt .height ,
212348 frmival .numerator , frmival .denominator );
213349
350+ if (app_has_videoenc ()) {
351+ /*
352+ * FIXME - this is currently hardcoded in NV12 while it should be
353+ * a format that has been validated for both video dev and encoder
354+ */
355+ ret = app_configure_videoenc (videoenc_dev , fmt .width , fmt .height ,
356+ VIDEO_PIX_FMT_NV12 , fmt .pixelformat ,
357+ CONFIG_VIDEO_BUFFER_POOL_NUM_MAX - uvc_buf_count );
358+ if (ret != 0 ) {
359+ return ret ;
360+ }
361+ }
362+
214363 fmt .type = VIDEO_BUF_TYPE_OUTPUT ;
364+ if (app_has_videoenc ()) {
365+ /*
366+ * FIXME - this is currently hardcoded in NV12 while it should be
367+ * a format that has been validated for both video dev and encoder
368+ */
369+ fmt .pixelformat = VIDEO_PIX_FMT_NV12 ;
370+ }
215371
216372 ret = video_set_compose_format (video_dev , & fmt );
217373 if (ret != 0 ) {
@@ -220,14 +376,19 @@ int main(void)
220376 fmt .width , fmt .height , fmt .size );
221377 }
222378
379+ /*
380+ * FIXME - shortcut here since current available encoders do not
381+ * have frmival support for the time being so this is done directly
382+ * at camera level
383+ */
223384 ret = video_set_frmival (video_dev , & frmival );
224385 if (ret != 0 ) {
225386 LOG_WRN ("Could not set the framerate of %s" , video_dev -> name );
226387 }
227388
228- LOG_INF ("Preparing %u buffers of %u bytes" , CONFIG_VIDEO_BUFFER_POOL_NUM_MAX , fmt .size );
389+ LOG_INF ("Preparing %u buffers of %u bytes" , uvc_buf_count , fmt .size );
229390
230- for (int i = 0 ; i < CONFIG_VIDEO_BUFFER_POOL_NUM_MAX ; i ++ ) {
391+ for (int i = 0 ; i < uvc_buf_count ; i ++ ) {
231392 vbuf = video_buffer_aligned_alloc (fmt .size , CONFIG_VIDEO_BUFFER_POOL_ALIGN ,
232393 K_NO_WAIT );
233394 if (vbuf == NULL ) {
@@ -244,14 +405,14 @@ int main(void)
244405 }
245406 }
246407
247- LOG_DBG ("Preparing signaling for %s input/output" , video_dev -> name );
408+ LOG_DBG ("Preparing signaling for %s input/output" , uvc_src_dev -> name );
248409
249410 k_poll_signal_init (& sig );
250411 k_poll_event_init (& evt [0 ], K_POLL_TYPE_SIGNAL , K_POLL_MODE_NOTIFY_ONLY , & sig );
251412
252- ret = video_set_signal (video_dev , & sig );
413+ ret = video_set_signal (uvc_src_dev , & sig );
253414 if (ret != 0 ) {
254- LOG_WRN ("Failed to setup the signal on %s output endpoint" , video_dev -> name );
415+ LOG_WRN ("Failed to setup the signal on %s output endpoint" , uvc_src_dev -> name );
255416 timeout = K_MSEC (1 );
256417 }
257418
@@ -263,6 +424,13 @@ int main(void)
263424
264425 LOG_INF ("Starting the video transfer" );
265426
427+ if (app_has_videoenc ()) {
428+ ret = app_start_videoenc (videoenc_dev );
429+ if (ret != 0 ) {
430+ return ret ;
431+ }
432+ }
433+
266434 ret = video_stream_start (video_dev , VIDEO_BUF_TYPE_OUTPUT );
267435 if (ret != 0 ) {
268436 LOG_ERR ("Failed to start %s" , video_dev -> name );
@@ -276,6 +444,17 @@ int main(void)
276444 return ret ;
277445 }
278446
447+ if (app_has_videoenc ()) {
448+ ret = video_transfer_buffer (video_dev , uvc_src_dev ,
449+ VIDEO_BUF_TYPE_OUTPUT , VIDEO_BUF_TYPE_INPUT ,
450+ K_NO_WAIT );
451+ if (ret != 0 && ret != - EAGAIN ) {
452+ LOG_ERR ("Failed to transfer from %s to %s" ,
453+ video_dev -> name , uvc_src_dev -> name );
454+ return ret ;
455+ }
456+ }
457+
279458 ret = video_transfer_buffer (uvc_src_dev , uvc_dev ,
280459 VIDEO_BUF_TYPE_OUTPUT , VIDEO_BUF_TYPE_INPUT , K_NO_WAIT );
281460 if (ret != 0 && ret != - EAGAIN ) {
@@ -284,6 +463,17 @@ int main(void)
284463 return ret ;
285464 }
286465
466+ if (app_has_videoenc ()) {
467+ ret = video_transfer_buffer (uvc_src_dev , video_dev ,
468+ VIDEO_BUF_TYPE_INPUT , VIDEO_BUF_TYPE_OUTPUT ,
469+ K_NO_WAIT );
470+ if (ret != 0 && ret != - EAGAIN ) {
471+ LOG_ERR ("Failed to transfer from %s to %s" ,
472+ uvc_src_dev -> name , video_dev -> name );
473+ return ret ;
474+ }
475+ }
476+
287477 ret = video_transfer_buffer (uvc_dev , uvc_src_dev ,
288478 VIDEO_BUF_TYPE_INPUT , VIDEO_BUF_TYPE_OUTPUT , K_NO_WAIT );
289479 if (ret != 0 && ret != - EAGAIN ) {
0 commit comments