diff --git a/host/class/uvc/usb_host_uvc/CHANGELOG.md b/host/class/uvc/usb_host_uvc/CHANGELOG.md index a8b4e416..fa00fad3 100644 --- a/host/class/uvc/usb_host_uvc/CHANGELOG.md +++ b/host/class/uvc/usb_host_uvc/CHANGELOG.md @@ -7,9 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Added NV12 stream format parsing for UVC uncompressed descriptors. + ### Fixed - Fixed regression from version 2.5.0 where unreasonably large URBs could be allocated, leading to out-of-memory scenarios. Now, if urb_size == 0, we allocate URB of size 4x MPS. For other urb_sizes, user's value is used to provide flexibility. +- Fixed unsupported UVC formats leaking into the frame list when descriptor parsing returns an invalid format. ## [2.5.0] - 2026-04-13 diff --git a/host/class/uvc/usb_host_uvc/include/usb/uvc_host.h b/host/class/uvc/usb_host_uvc/include/usb/uvc_host.h index 3e7a6755..86f25749 100644 --- a/host/class/uvc/usb_host_uvc/include/usb/uvc_host.h +++ b/host/class/uvc/usb_host_uvc/include/usb/uvc_host.h @@ -45,6 +45,7 @@ enum uvc_host_stream_format { UVC_VS_FORMAT_YUY2, /*!< YUY2 stream format. */ UVC_VS_FORMAT_H264, /*!< H.264 stream format. */ UVC_VS_FORMAT_H265, /*!< H.265 stream format. */ + UVC_VS_FORMAT_NV12, /*!< NV12 stream format. */ }; /** diff --git a/host/class/uvc/usb_host_uvc/uvc_descriptor_parsing.c b/host/class/uvc/usb_host_uvc/uvc_descriptor_parsing.c index 6d508609..2e2e1108 100644 --- a/host/class/uvc/usb_host_uvc/uvc_descriptor_parsing.c +++ b/host/class/uvc/usb_host_uvc/uvc_descriptor_parsing.c @@ -166,6 +166,8 @@ int uvc_desc_parse_format(const uvc_format_desc_t *format_desc) // We do not check full guid, but only the first 4 characters that show human readable format if (strncmp(guid, "YUY2", 4) == 0) { ret = UVC_VS_FORMAT_YUY2; + } else if (strncmp(guid, "NV12", 4) == 0) { + ret = UVC_VS_FORMAT_NV12; } break; } @@ -456,10 +458,11 @@ esp_err_t uvc_desc_get_frame_list(const usb_config_desc_t *config_desc, uint8_t } const uvc_format_desc_t *this_format = (const uvc_format_desc_t *)(current_desc); - enum uvc_host_stream_format format_type = uvc_desc_parse_format(this_format); - if (0 > format_type) { // Undefined format + int parsed_format = uvc_desc_parse_format(this_format); + if (parsed_format < 0) { // Undefined format continue; } + enum uvc_host_stream_format format_type = parsed_format; num_frame += this_format->bNumFrameDescriptors; @@ -485,6 +488,7 @@ esp_err_t uvc_desc_get_frame_list(const usb_config_desc_t *config_desc, uint8_t frame_info->v_res = this_frame->wHeight; switch (format_type) { case UVC_VS_FORMAT_YUY2: + case UVC_VS_FORMAT_NV12: case UVC_VS_FORMAT_MJPEG: frame_info->default_interval = this_frame->mjpeg_uncompressed.dwDefaultFrameInterval; frame_info->interval_type = this_frame->mjpeg_uncompressed.bFrameIntervalType;