1717
1818LOG_MODULE_REGISTER (uvc_sample , LOG_LEVEL_INF );
1919
20- const struct device * const uvc_dev = DEVICE_DT_GET (DT_NODELABEL (uvc ));
21- const struct device * const video_dev = DEVICE_DT_GET (DT_CHOSEN (zephyr_camera ));
20+ const static struct device * const uvc_dev = DEVICE_DT_GET (DT_NODELABEL (uvc ));
21+ const static struct device * const video_dev = DEVICE_DT_GET (DT_CHOSEN (zephyr_camera ));
22+
23+ /* Format capabilities of video_dev, used everywhere through the sample */
24+ static struct video_caps video_caps = {.type = VIDEO_BUF_TYPE_OUTPUT };
25+
26+ static int app_add_format (uint32_t pixfmt , uint32_t width , uint32_t height )
27+ {
28+ struct video_format fmt = {
29+ .pixelformat = pixfmt ,
30+ .width = width ,
31+ .height = height ,
32+ .type = VIDEO_BUF_TYPE_OUTPUT ,
33+ };
34+ int ret ;
35+
36+ /* Set the format to get the size */
37+ ret = video_set_format (video_dev , & fmt );
38+ if (ret != 0 ) {
39+ LOG_ERR ("Could not set the format of %s to %s %ux%u (size %u)" ,
40+ video_dev -> name , VIDEO_FOURCC_TO_STR (fmt .pixelformat ),
41+ fmt .width , fmt .height , fmt .size );
42+ return ret ;
43+ }
44+
45+ if (fmt .size > CONFIG_VIDEO_BUFFER_POOL_SZ_MAX ) {
46+ LOG_WRN ("Skipping format %ux%u" , fmt .width , fmt .height );
47+ return 0 ;
48+ }
49+
50+ ret = uvc_add_format (uvc_dev , & fmt );
51+ if (ret == - ENOMEM ) {
52+ /* If there are too many formats, ignore the error, just list fewer formats */
53+ return 0 ;
54+ }
55+ return ret ;
56+ }
57+
58+ /* Submit to UVC only the formats expected to be working (enough memory for the size, etc.) */
59+ static int app_add_filtered_formats (void )
60+ {
61+ for (int i = 0 ; video_caps .format_caps [i ].pixelformat != 0 ; i ++ ) {
62+ const struct video_format_cap * vcap = & video_caps .format_caps [i ];
63+
64+ ret = app_add_format (vcap -> pixelformat , vcap -> width_min , vcap -> height_min );
65+ if (ret != 0 ) {
66+ return ret ;
67+ }
68+
69+ if (vcap -> width_min != vcap -> width_max || vcap -> height_min != vcap -> height_max ) {
70+ ret = app_add_format (vcap -> pixelformat , vcap -> width_max , vcap -> height_max );
71+ if (ret != 0 ) {
72+ return ret ;
73+ }
74+ }
75+ }
76+
77+ return 0 ;
78+ }
2279
2380int main (void )
2481{
2582 struct usbd_context * sample_usbd ;
2683 struct video_buffer * vbuf ;
2784 struct video_format fmt = {0 };
28- struct video_caps caps ;
85+ struct video_frmival frmival = { 0 } ;
2986 struct k_poll_signal sig ;
3087 struct k_poll_event evt [1 ];
3188 k_timeout_t timeout = K_FOREVER ;
@@ -36,16 +93,21 @@ int main(void)
3693 return - ENODEV ;
3794 }
3895
39- caps .type = VIDEO_BUF_TYPE_OUTPUT ;
40-
41- if (video_get_caps (video_dev , & caps )) {
96+ ret = video_get_caps (video_dev , & video_caps );
97+ if (ret != 0 ) {
4298 LOG_ERR ("Unable to retrieve video capabilities" );
4399 return 0 ;
44100 }
45101
46- /* Must be done before initializing USB */
102+ /* Must be called before usb_enable() */
47103 uvc_set_video_dev (uvc_dev , video_dev );
48104
105+ /* Must be called before usb_enable() */
106+ ret = app_add_filtered_formats ();
107+ if (ret != 0 ) {
108+ return ret ;
109+ }
110+
49111 sample_usbd = sample_usbd_init_device (NULL );
50112 if (sample_usbd == NULL ) {
51113 return - ENODEV ;
@@ -58,7 +120,6 @@ int main(void)
58120
59121 LOG_INF ("Waiting the host to select the video format" );
60122
61- /* Get the video format once it is selected by the host */
62123 while (true) {
63124 fmt .type = VIDEO_BUF_TYPE_INPUT ;
64125
@@ -74,9 +135,31 @@ int main(void)
74135 k_sleep (K_MSEC (10 ));
75136 }
76137
77- LOG_INF ("The host selected format '%s' %ux%u, preparing %u buffers of %u bytes" ,
138+ ret = video_get_frmival (uvc_dev , & frmival );
139+ if (ret != 0 ) {
140+ LOG_ERR ("Failed to get the video frame interval" );
141+ return ret ;
142+ }
143+
144+ LOG_INF ("The host selected format '%s' %ux%u at frame interval %u/%u" ,
78145 VIDEO_FOURCC_TO_STR (fmt .pixelformat ), fmt .width , fmt .height ,
79- CONFIG_VIDEO_BUFFER_POOL_NUM_MAX , fmt .pitch * fmt .height );
146+ frmival .numerator , frmival .denominator );
147+
148+ fmt .type = VIDEO_BUF_TYPE_OUTPUT ;
149+
150+ ret = video_set_format (video_dev , & fmt );
151+ if (ret != 0 ) {
152+ LOG_ERR ("Could not set the format of %s to %s %ux%u (size %u)" ,
153+ video_dev -> name , VIDEO_FOURCC_TO_STR (fmt .pixelformat ),
154+ fmt .width , fmt .height , fmt .size );
155+ }
156+
157+ ret = video_set_frmival (video_dev , & frmival );
158+ if (ret != 0 ) {
159+ LOG_WRN ("Could not set the framerate of %s" , video_dev -> name );
160+ }
161+
162+ LOG_INF ("Preparing %u buffers of %u bytes" , CONFIG_VIDEO_BUFFER_POOL_NUM_MAX , fmt .size );
80163
81164 for (int i = 0 ; i < CONFIG_VIDEO_BUFFER_POOL_NUM_MAX ; i ++ ) {
82165 vbuf = video_buffer_alloc (fmt .size , K_NO_WAIT );
0 commit comments