17
17
18
18
LOG_MODULE_REGISTER (uvc_sample , LOG_LEVEL_INF );
19
19
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, usd everywhere through the sampel */
24
+ static struct video_caps video_caps = {.type = VIDEO_BUF_TYPE_OUTPUT };
25
+
26
+ static size_t app_get_min_buf_size (const struct video_format * const fmt )
27
+ {
28
+ if (video_caps .min_line_count == LINE_COUNT_HEIGHT ) {
29
+ return fmt -> pitch * fmt -> height ;
30
+ } else {
31
+ return fmt -> pitch * video_caps .min_line_count ;
32
+ }
33
+ }
34
+
35
+ static bool app_is_standard_format (uint32_t pixfmt )
36
+ {
37
+ return pixfmt == VIDEO_PIX_FMT_GREY || pixfmt == VIDEO_PIX_FMT_JPEG ||
38
+ pixfmt == VIDEO_PIX_FMT_YUYV ;
39
+ }
40
+
41
+ /* Check whether the video device supports one of the wisespread image sensor formats */
42
+ static bool app_has_standard_formats (void )
43
+ {
44
+ for (int i = 0 ;; i ++ ) {
45
+ uint32_t pixfmt = video_caps .format_caps [i ].pixelformat ;
46
+
47
+ if (pixfmt == 0 ) {
48
+ return false;
49
+ }
50
+ if (app_is_standard_format (pixfmt )) {
51
+ return true;
52
+ }
53
+ }
54
+ }
55
+
56
+ static void app_add_format (uint32_t pixfmt , uint16_t width , uint16_t height , bool has_std_fmts )
57
+ {
58
+ struct video_format fmt = {
59
+ .pixelformat = pixfmt ,
60
+ .width = width ,
61
+ .height = height ,
62
+ .type = VIDEO_BUF_TYPE_OUTPUT ,
63
+ };
64
+ int ret ;
65
+
66
+ /* If the system has any standard pixel format, only propose them to the host */
67
+ if (has_std_fmts && !app_is_standard_format (pixfmt )) {
68
+ return ;
69
+ }
70
+
71
+ /* Set the format to get the pitch */
72
+ ret = video_set_format (video_dev , & fmt );
73
+ if (ret != 0 ) {
74
+ LOG_ERR ("Could not set the format of %s" , video_dev -> name );
75
+ return ;
76
+ }
77
+
78
+ if (app_get_min_buf_size (& fmt ) > CONFIG_VIDEO_BUFFER_POOL_SZ_MAX ) {
79
+ LOG_WRN ("Skipping format %ux%u" , fmt .width , fmt .height );
80
+ return ;
81
+ }
82
+
83
+ uvc_add_format (uvc_dev , & fmt );
84
+ }
85
+
86
+ /* Submit to UVC only the formats expected to be working (enough memory for the size, etc.) */
87
+ static void app_add_filtered_formats (void )
88
+ {
89
+ const bool has_std_fmts = app_has_standard_formats ();
90
+
91
+ for (int i = 0 ; video_caps .format_caps [i ].pixelformat != 0 ; i ++ ) {
92
+ const struct video_format_cap * vcap = & video_caps .format_caps [i ];
93
+
94
+ app_add_format (vcap -> pixelformat , vcap -> width_min , vcap -> height_min , has_std_fmts );
95
+
96
+ if (vcap -> width_min != vcap -> width_max || vcap -> height_min != vcap -> height_max ) {
97
+ app_add_format (vcap -> pixelformat , vcap -> width_max , vcap -> height_max ,
98
+ has_std_fmts );
99
+ }
100
+ }
101
+ }
22
102
23
103
int main (void )
24
104
{
25
105
struct usbd_context * sample_usbd ;
26
106
struct video_buffer * vbuf ;
27
107
struct video_format fmt = {0 };
28
- struct video_caps caps ;
108
+ struct video_frmival frmival = { 0 } ;
29
109
struct k_poll_signal sig ;
30
110
struct k_poll_event evt [1 ];
31
111
k_timeout_t timeout = K_FOREVER ;
@@ -37,16 +117,18 @@ int main(void)
37
117
return - ENODEV ;
38
118
}
39
119
40
- caps .type = VIDEO_BUF_TYPE_OUTPUT ;
41
-
42
- if (video_get_caps (video_dev , & caps )) {
120
+ ret = video_get_caps (video_dev , & video_caps );
121
+ if (ret != 0 ) {
43
122
LOG_ERR ("Unable to retrieve video capabilities" );
44
123
return 0 ;
45
124
}
46
125
47
- /* Must be done before initializing USB */
126
+ /* Must be called before usb_enable() */
48
127
uvc_set_video_dev (uvc_dev , video_dev );
49
128
129
+ /* Must be called before uvc_set_video_dev() */
130
+ app_add_filtered_formats ();
131
+
50
132
sample_usbd = sample_usbd_init_device (NULL );
51
133
if (sample_usbd == NULL ) {
52
134
return - ENODEV ;
@@ -59,7 +141,6 @@ int main(void)
59
141
60
142
LOG_INF ("Waiting the host to select the video format" );
61
143
62
- /* Get the video format once it is selected by the host */
63
144
while (true) {
64
145
fmt .type = VIDEO_BUF_TYPE_INPUT ;
65
146
@@ -75,17 +156,32 @@ int main(void)
75
156
k_sleep (K_MSEC (10 ));
76
157
}
77
158
78
- LOG_INF ("The host selected format '%s' %ux%u, preparing %u buffers of %u bytes" ,
159
+ ret = video_get_frmival (uvc_dev , & frmival );
160
+ if (ret != 0 ) {
161
+ LOG_ERR ("Failed to get the video frame interval" );
162
+ return ret ;
163
+ }
164
+
165
+ LOG_INF ("The host selected format '%s' %ux%u at frame interval %u/%u" ,
79
166
VIDEO_FOURCC_TO_STR (fmt .pixelformat ), fmt .width , fmt .height ,
80
- CONFIG_VIDEO_BUFFER_POOL_NUM_MAX , fmt . pitch * fmt . height );
167
+ frmival . numerator , frmival . denominator );
81
168
82
- /* Size to allocate for each buffer */
83
- if (caps .min_line_count == LINE_COUNT_HEIGHT ) {
84
- bsize = fmt .pitch * fmt .height ;
85
- } else {
86
- bsize = fmt .pitch * caps .min_line_count ;
169
+ fmt .type = VIDEO_BUF_TYPE_OUTPUT ;
170
+
171
+ ret = video_set_format (video_dev , & fmt );
172
+ if (ret != 0 ) {
173
+ LOG_WRN ("Could not set the format of %s" , video_dev -> name );
174
+ }
175
+
176
+ ret = video_set_frmival (video_dev , & frmival );
177
+ if (ret != 0 ) {
178
+ LOG_WRN ("Could not set the framerate of %s" , video_dev -> name );
87
179
}
88
180
181
+ bsize = app_get_min_buf_size (& fmt );
182
+
183
+ LOG_INF ("Preparing %u buffers of %u bytes" , CONFIG_VIDEO_BUFFER_POOL_NUM_MAX , bsize );
184
+
89
185
for (int i = 0 ; i < CONFIG_VIDEO_BUFFER_POOL_NUM_MAX ; i ++ ) {
90
186
vbuf = video_buffer_alloc (bsize , K_NO_WAIT );
91
187
if (vbuf == NULL ) {
0 commit comments