3636#define EXAMPLE_NUMBER_OF_STREAMS (1) // This example shows how to control multiple UVC streams. Set this to 1 if you camera offers only 1 stream
3737#define EXAMPLE_USE_SDCARD (0) // SD card on P4 evaluation board will be initialized
3838
39+ #define UVC_DESC_DWFRAMEINTERVAL_TO_FPS (dwFrameInterval ) (((dwFrameInterval) != 0) ? 10000000 / ((float)(dwFrameInterval)) : 0)
40+
3941static const char * TAG = "UVC example" ;
4042static QueueHandle_t rx_frames_queue [EXAMPLE_NUMBER_OF_STREAMS ];
43+ static int device_count = 0 ;
4144static bool dev_connected = false;
45+ static uvc_host_frame_info_t * frame_info_list [EXAMPLE_NUMBER_OF_STREAMS ] = {NULL };
46+ static size_t frame_info_list_size [EXAMPLE_NUMBER_OF_STREAMS ] = {0 };
47+
48+ static const char * FORMAT_STR [] = {
49+ "FORMAT_UNDEFINED" ,
50+ "FORMAT_MJPEG" ,
51+ "FORMAT_YUY2" ,
52+ "FORMAT_H264" ,
53+ "FORMAT_H265" ,
54+ };
4255
4356bool frame_callback (const uvc_host_frame_t * frame , void * user_ctx )
4457{
@@ -63,6 +76,7 @@ static void stream_callback(const uvc_host_stream_event_data_t *event, void *use
6376 case UVC_HOST_DEVICE_DISCONNECTED :
6477 ESP_LOGI (TAG , "Device suddenly disconnected" );
6578 dev_connected = false;
79+ device_count -- ;
6680 ESP_ERROR_CHECK (uvc_host_stream_close (event -> device_disconnected .stream_hdl ));
6781 break ;
6882 case UVC_HOST_FRAME_BUFFER_OVERFLOW :
@@ -95,7 +109,7 @@ static void usb_lib_task(void *arg)
95109
96110static void frame_handling_task (void * arg )
97111{
98- const uvc_host_stream_config_t * stream_config = (const uvc_host_stream_config_t * )arg ;
112+ const uvc_host_stream_config_t * stream_config = (uvc_host_stream_config_t * )arg ;
99113 QueueHandle_t frame_q = * ((QueueHandle_t * )(stream_config -> user_ctx ));
100114 const int uvc_index = stream_config -> usb .uvc_stream_index ;
101115
@@ -153,52 +167,8 @@ static void frame_handling_task(void *arg)
153167 }
154168}
155169
156- static const uvc_host_stream_config_t stream_mjpeg_config = {
157- .event_cb = stream_callback ,
158- .frame_cb = frame_callback ,
159- .user_ctx = & rx_frames_queue [0 ],
160- .usb = {
161- .vid = EXAMPLE_USB_DEVICE_VID ,
162- .pid = EXAMPLE_USB_DEVICE_PID ,
163- .uvc_stream_index = 0 ,
164- },
165- .vs_format = {
166- .h_res = 720 ,
167- .v_res = 1280 ,
168- .fps = 15 ,
169- .format = UVC_VS_FORMAT_MJPEG ,
170- },
171- .advanced = {
172- .number_of_frame_buffers = EXAMPLE_FRAME_COUNT ,
173- .frame_size = 0 ,
174- .number_of_urbs = 4 ,
175- .urb_size = 10 * 1024 ,
176- },
177- };
178-
179170#if EXAMPLE_NUMBER_OF_STREAMS > 1
180- static const uvc_host_stream_config_t stream_h265_config = {
181- .event_cb = stream_callback ,
182- .frame_cb = frame_callback ,
183- .user_ctx = & rx_frames_queue [1 ],
184- .usb = {
185- .vid = EXAMPLE_USB_DEVICE_VID ,
186- .pid = EXAMPLE_USB_DEVICE_PID ,
187- .uvc_stream_index = 1 ,
188- },
189- .vs_format = {
190- .h_res = 1280 ,
191- .v_res = 720 ,
192- .fps = 15 ,
193- .format = UVC_VS_FORMAT_H265 ,
194- },
195- .advanced = {
196- .number_of_frame_buffers = EXAMPLE_FRAME_COUNT ,
197- .frame_size = 0 ,
198- .number_of_urbs = 4 ,
199- .urb_size = 10 * 1024 ,
200- },
201- };
171+
202172#endif // EXAMPLE_NUMBER_OF_STREAMS > 1
203173
204174#if EXAMPLE_USE_SDCARD
@@ -279,6 +249,85 @@ void app_init_sdcard(void)
279249}
280250#endif // EXAMPLE_USE_SDCARD
281251
252+ static void start_uvc_frame_handling_tasks (void )
253+ {
254+ uvc_host_stream_config_t _stream_config = {
255+ .event_cb = stream_callback ,
256+ .frame_cb = frame_callback ,
257+ .user_ctx = & rx_frames_queue [0 ],
258+ .usb = {
259+ .vid = EXAMPLE_USB_DEVICE_VID ,
260+ .pid = EXAMPLE_USB_DEVICE_PID ,
261+ .uvc_stream_index = 0 ,
262+ },
263+ .vs_format = {
264+ .h_res = frame_info_list [0 ][0 ].h_res ,
265+ .v_res = frame_info_list [0 ][0 ].v_res ,
266+ .fps = UVC_DESC_DWFRAMEINTERVAL_TO_FPS (frame_info_list [0 ][0 ].default_interval ),
267+ .format = UVC_VS_FORMAT_MJPEG ,
268+ },
269+ .advanced = {
270+ .number_of_frame_buffers = EXAMPLE_FRAME_COUNT ,
271+ .frame_size = 0 ,
272+ .number_of_urbs = 4 ,
273+ .urb_size = 10 * 1024 ,
274+ },
275+ };
276+ static uvc_host_stream_config_t stream_mjpeg_config ;
277+ memcpy (& stream_mjpeg_config , & _stream_config , sizeof (uvc_host_stream_config_t ));
278+ BaseType_t task_created = xTaskCreatePinnedToCore (frame_handling_task , "mjpeg_handling" , 4096 , (void * )& stream_mjpeg_config , EXAMPLE_USB_HOST_PRIORITY - 2 , NULL , tskNO_AFFINITY );
279+ assert (task_created == pdTRUE );
280+
281+ #if EXAMPLE_NUMBER_OF_STREAMS > 1
282+ vTaskDelay (pdMS_TO_TICKS (1000 ));
283+ _stream_config .usb .uvc_stream_index = 1 ;
284+ _stream_config .vs_format .h_res = frame_info_list [1 ][0 ].h_res ;
285+ _stream_config .vs_format .v_res = frame_info_list [1 ][0 ].v_res ;
286+ _stream_config .vs_format .fps = UVC_DESC_DWFRAMEINTERVAL_TO_FPS (frame_info_list [1 ][0 ].default_interval );
287+ _stream_config .vs_format .format = UVC_VS_FORMAT_H265 ;
288+ _stream_config .user_ctx = & rx_frames_queue [1 ];
289+ static uvc_host_stream_config_t stream_h265_config ;
290+ memcpy (& stream_h265_config , & _stream_config , sizeof (uvc_host_stream_config_t ));
291+ task_created = xTaskCreatePinnedToCore (frame_handling_task , "h265_handling" , 4096 , (void * )& stream_h265_config , EXAMPLE_USB_HOST_PRIORITY - 3 , NULL , tskNO_AFFINITY );
292+ assert (task_created == pdTRUE );
293+ #endif // EXAMPLE_NUMBER_OF_STREAMS > 1
294+ }
295+
296+ static void uvc_event_cb (const uvc_host_driver_event_data_t * event , void * user_ctx )
297+ {
298+ switch (event -> type ) {
299+ case UVC_HOST_DRIVER_EVENT_DEVICE_CONNECTED : {
300+ ESP_LOGI (TAG , "Device connected, addr: %d, stream index: %d" , event -> device_connected .dev_addr , event -> device_connected .uvc_stream_index );
301+ int stream_index = event -> device_connected .uvc_stream_index ;
302+ if (stream_index >= EXAMPLE_NUMBER_OF_STREAMS ) {
303+ ESP_LOGW (TAG , "Stream index %d is out of range. Max supported is %d" , stream_index , EXAMPLE_NUMBER_OF_STREAMS - 1 );
304+ break ;
305+ }
306+ device_count ++ ;
307+ if (device_count > 1 ) {
308+ ESP_LOGW (TAG , "Multiple devices connected. ignoring additional devices." );
309+ break ;
310+ }
311+
312+ frame_info_list_size [stream_index ] = event -> device_connected .frame_info_num ;
313+ frame_info_list [stream_index ] = calloc (frame_info_list_size [stream_index ], sizeof (uvc_host_frame_info_t ));
314+ assert (frame_info_list [stream_index ]);
315+ uvc_host_get_frame_list (event -> device_connected .dev_addr , stream_index , (uvc_host_frame_info_t (* )[])frame_info_list [stream_index ], & frame_info_list_size [stream_index ]);
316+ for (int i = 0 ; i < frame_info_list_size [stream_index ]; i ++ ) {
317+ ESP_LOGI (TAG , "Camera format: %s %d*%d@%.1ffps" ,
318+ FORMAT_STR [frame_info_list [stream_index ][i ].format ],
319+ frame_info_list [stream_index ][i ].h_res ,
320+ frame_info_list [stream_index ][i ].v_res ,
321+ UVC_DESC_DWFRAMEINTERVAL_TO_FPS (frame_info_list [stream_index ][i ].default_interval ));
322+ }
323+ start_uvc_frame_handling_tasks ();
324+ break ;
325+ }
326+ default :
327+ break ;
328+ }
329+ }
330+
282331/**
283332 * @brief Main application
284333 */
@@ -311,15 +360,7 @@ void app_main(void)
311360 .driver_task_priority = EXAMPLE_USB_HOST_PRIORITY + 1 ,
312361 .xCoreID = tskNO_AFFINITY ,
313362 .create_background_task = true,
363+ .event_cb = uvc_event_cb ,
314364 };
315365 ESP_ERROR_CHECK (uvc_host_install (& uvc_driver_config ));
316-
317- task_created = xTaskCreatePinnedToCore (frame_handling_task , "mjpeg_handling" , 4096 , (void * )& stream_mjpeg_config , EXAMPLE_USB_HOST_PRIORITY - 2 , NULL , tskNO_AFFINITY );
318- assert (task_created == pdTRUE );
319-
320- #if EXAMPLE_NUMBER_OF_STREAMS > 1
321- vTaskDelay (pdMS_TO_TICKS (1000 ));
322- task_created = xTaskCreatePinnedToCore (frame_handling_task , "h265_handling" , 4096 , (void * )& stream_h265_config , EXAMPLE_USB_HOST_PRIORITY - 3 , NULL , tskNO_AFFINITY );
323- assert (task_created == pdTRUE );
324- #endif // EXAMPLE_USE_SDCARD
325366}
0 commit comments