From d026f174576b0567e2a954292bd4339349e3f139 Mon Sep 17 00:00:00 2001 From: kkitayam <45088311+kkitayam@users.noreply.github.com> Date: Sun, 1 Aug 2021 17:11:43 +0900 Subject: [PATCH] fix: configuration descriptor has incorrectly sizes update some descriptors --- .../video_capture/src/usb_descriptors.c | 2 +- .../video_capture/src/usb_descriptors.h | 59 ++++++++++------- src/class/video/video.h | 63 +++++++++++++++---- src/class/video/video_device.c | 23 ++++--- 4 files changed, 102 insertions(+), 45 deletions(-) diff --git a/examples/device/video_capture/src/usb_descriptors.c b/examples/device/video_capture/src/usb_descriptors.c index df8c41721..067c1d946 100644 --- a/examples/device/video_capture/src/usb_descriptors.c +++ b/examples/device/video_capture/src/usb_descriptors.c @@ -102,7 +102,7 @@ uint8_t const * tud_descriptor_device_cb(void) uint8_t const desc_fs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA - TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100), + TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 500), // IAD for Video Control TUD_VIDEO_CAPTURE_DESCRIPTOR(4, EPNUM_VIDEO_IN, 128, 96, 15) }; diff --git a/examples/device/video_capture/src/usb_descriptors.h b/examples/device/video_capture/src/usb_descriptors.h index 6c6c14d35..d37ab1338 100644 --- a/examples/device/video_capture/src/usb_descriptors.h +++ b/examples/device/video_capture/src/usb_descriptors.h @@ -39,18 +39,27 @@ enum { ITF_NUM_TOTAL }; -#define TUD_VIDEO_CAPTURE_DESC_LEN (TUD_VIDEO_DESC_IAD_LEN\ +#define TUD_VIDEO_CAPTURE_DESC_LEN (\ + TUD_VIDEO_DESC_IAD_LEN\ /* control */\ + TUD_VIDEO_DESC_STD_VC_LEN\ - + TUD_VIDEO_DESC_CS_VC_LEN\ + + (TUD_VIDEO_DESC_CS_VC_LEN + 1/*bInCollection*/)\ + TUD_VIDEO_DESC_INPUT_TERM_LEN\ + TUD_VIDEO_DESC_OUTPUT_TERM_LEN\ /* Interface 1, Alternate 0 */\ + TUD_VIDEO_DESC_STD_VS_LEN\ - + TUD_VIDEO_DESC_CS_VS_IN_LEN\ + + (TUD_VIDEO_DESC_CS_VS_IN_LEN + 1/*bNumFormats x bControlSize*/)\ + TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN\ - + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN) + + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN\ + + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN\ + ) +#if 0 + /* Interface 1, Alternate 1 */\ + + TUD_VIDEO_DESC_STD_VS_LEN\ + + 7/* Endpoint */\ + +#endif #define TUD_VIDEO_DESC_CS_VS_FMT_YUY2(_fmtidx, _numfmtdesc, _frmidx, _asrx, _asry, _interlace, _cp) \ TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfmtdesc, TUD_VIDEO_GUID_YUY2, 16, _frmidx, _asrx, _asry, _interlace, _cp) @@ -64,34 +73,40 @@ enum { #define TUD_VIDEO_CAPTURE_DESCRIPTOR(_stridx, _epin, _width, _height, _fps) \ TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, ITF_NUM_TOTAL, _stridx), \ /* Video control 0 */ \ - TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, 0), \ + TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \ - TUD_VIDEO_DESC_INPUT_TERM_LEN + \ - TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ + /* wTotalLength - bLength */ \ + TUD_VIDEO_DESC_INPUT_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ UVC_CLOCK_FREQUENCY, 1, 1), \ TUD_VIDEO_DESC_INPUT_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL,\ VIDEO_TT_COMPOSITE_CONNECTOR, 0, 0), \ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL,\ - VIDEO_TT_STREAMING, 0, 1, 0), \ + VIDEO_TT_STREAMING, 0, 1, 0), \ /* Video stream alt. 0 */ \ TUD_VIDEO_DESC_STD_VS( 1, 0, 0, 0), \ /* Video stream header for without still image capture */ \ - TUD_VIDEO_DESC_CS_VS_INPUT(1, \ - TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN + \ - TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN,\ - _epin, /*bmInfo*/ 0, UVC_ENTITY_CAP_OUTPUT_TERMINAL, \ - 0, 2, 0, 0, 0, 1, 0), \ + TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \ + /*wTotalLength - bLength */\ + TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN\ + + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN\ + + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\ + _epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \ + /*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \ + /*bControlSize*/1, /*bmaControls(1)*/0), \ /* Video stream format */ \ - TUD_VIDEO_DESC_CS_VS_FMT_I420(0, 1, 0, 1, 1, 0, 0), \ + TUD_VIDEO_DESC_CS_VS_FMT_I420(/*bFormatIndex*/1, /*bNumFrameDescriptors*/1,\ + /*bDefaultFrameIndex*/1, 1, 1, 0, /*bCopyProtect*/0), \ /* Video stream frame format */ \ - TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT( 1, 0, _width, _height, \ - _width * _height * 12, _width * _height * 12 * _fps, \ - _width * _height * 12, \ - (10000000/_fps), (10000000/1), (10000000/_fps), 166666), \ - /* VS alt 1 */ \ - TUD_VIDEO_DESC_STD_VS( 1, 1, 1, 0), \ - /* EP */ \ - TUD_VIDEO_DESC_EP_ISO(_epin, (_width * _height * 12 / 8) * _fps, 1) + TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(/*bFrameIndex */1, 0, _width, _height, \ + _width * _height * 12, _width * _height * 12 * _fps, \ + _width * _height * 12, \ + (10000000/_fps), (10000000/1), (10000000/_fps), 166666), \ + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(VIDEO_COLOR_PRIMARIES_BT709,\ + VIDEO_COLOR_XFER_CH_BT709, VIDEO_COLOR_COEF_SMPTE170M), \ + /* VS alt 1 */\ + TUD_VIDEO_DESC_STD_VS(1, 1, 1, 0), \ + /* EP */ \ + TUD_VIDEO_DESC_EP_ISO(_epin, (_width * _height * 12 / 8) * _fps, 1) #endif diff --git a/src/class/video/video.h b/src/class/video/video.h index 489af8da2..597ad7d39 100644 --- a/src/class/video/video.h +++ b/src/class/video/video.h @@ -29,6 +29,35 @@ #include "common/tusb_common.h" +typedef enum { + VIDEO_COLOR_PRIMARIES_UNDEFINED = 0x00, + VIDEO_COLOR_PRIMARIES_BT709, + VIDEO_COLOR_PRIMARIES_BT470_2M, + VIDEO_COLOR_PRIMARIES_BT470_2BG, + VIDEO_COLOR_PRIMARIES_SMPTE170M, + VIDEO_COLOR_PRIMARIES_SMPTE240M, +} video_color_primaries_t; + +typedef enum { + VIDEO_COLOR_XFER_CH_UNDEFINED = 0x00, + VIDEO_COLOR_XFER_CH_BT709, + VIDEO_COLOR_XFER_CH_BT470_2M, + VIDEO_COLOR_XFER_CH_BT470_2BG, + VIDEO_COLOR_XFER_CH_SMPTE170M, + VIDEO_COLOR_XFER_CH_SMPTE240M, + VIDEO_COLOR_XFER_CH_LINEAR, + VIDEO_COLOR_XFER_CH_SRGB, +} video_color_transfer_characteristics_t; + +typedef enum { + VIDEO_COLOR_COEF_UNDEFINED = 0x00, + VIDEO_COLOR_COEF_BT709, + VIDEO_COLOR_COEF_FCC, + VIDEO_COLOR_COEF_BT470_2BG, + VIDEO_COLOR_COEF_SMPTE170M, + VIDEO_COLOR_COEF_SMPTE240M, +} video_color_matrix_coefficients_t; + /* 4.2.1.2 */ typedef enum { VIDEO_NO_ERROR = 0, /* The request succeeded. */ @@ -69,7 +98,7 @@ typedef enum VIDEO_CS_VC_INTERFACE_PROCESSING_UNIT, VIDEO_CS_VC_INTERFACE_EXTENSION_UNIT, VIDEO_CS_VC_INTERFACE_ENCODING_UNIT, -} vide_cs_vc_interface_subtype_t; +} video_cs_vc_interface_subtype_t; /* A.6 */ typedef enum @@ -278,6 +307,7 @@ typedef struct TU_ATTR_PACKED { #define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27 #define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38 #define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26 +#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6 /* 2.2 compression formats */ #define TUD_VIDEO_GUID_YUY2 0x59,0x55,0x59,0x32,0x00,0x00,0x10,0x00,0x00,0x80,0x71,0x9B,0x38,0x00,0xAA,0x00 @@ -296,8 +326,8 @@ typedef struct TU_ATTR_PACKED { /* 3.7.2 */ #define TUD_VIDEO_DESC_CS_VC(_bcdUVC, _totallen, _clkfreq, _coll, ...) \ - TUD_VIDEO_DESC_CS_VC_LEN + _coll, TUSB_DESC_CS_INTERFACE, VIDEO_CS_VC_INTERFACE_HEADER, \ - U16_TO_U8S_LE(_bcdUVC), U16_TO_U8S_LE(_totallen + TUD_VIDEO_DESC_CS_VC_LEN), \ + TUD_VIDEO_DESC_CS_VC_LEN + (_coll), TUSB_DESC_CS_INTERFACE, VIDEO_CS_VC_INTERFACE_HEADER, \ + U16_TO_U8S_LE(_bcdUVC), U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VC_LEN + (_coll)), \ U32_TO_U8S_LE(_clkfreq), _coll, __VA_ARGS__ /* 3.7.2.1 */ @@ -307,30 +337,31 @@ typedef struct TU_ATTR_PACKED { /* 3.7.2.2 */ #define TUD_VIDEO_DESC_OUTPUT_TERM(_tid, _tt, _at, _srcid, _stridx) \ - TUD_VIDEO_DESC_INPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_VC_INTERFACE_OUTPUT_TERMINAL, \ - _tid, U16_TO_U8S_LE(_tt), _at, _stridx + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_VC_INTERFACE_OUTPUT_TERMINAL, \ + _tid, U16_TO_U8S_LE(_tt), _at, _srcid, _stridx /* 3.9.1 */ -#define TUD_VIDEO_DESC_STD_VS(_itfnum, _alt, _epn, _stridx) \ - TUD_VIDEO_DESC_STD_VC_LEN, TUSB_DESC_INTERFACE, _itfnum, _alt, \ +#define TUD_VIDEO_DESC_STD_VS(_itfnum, _alt, _epn, _stridx) \ + TUD_VIDEO_DESC_STD_VS_LEN, TUSB_DESC_INTERFACE, _itfnum, _alt, \ _epn, TUSB_CLASS_VIDEO, VIDEO_SUBCLASS_STREAMING, VIDEO_INT_PROTOCOL_CODE_15, _stridx /* 3.9.2.1 */ -#define TUD_VIDEO_DESC_CS_VS_INPUT(_numfmt, _totlen, _epn, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, _ctlsz, ...) \ +#define TUD_VIDEO_DESC_CS_VS_INPUT(_numfmt, _totallen, _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, _ctlsz, ...) \ TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (_ctlsz), TUSB_DESC_CS_INTERFACE, \ VIDEO_CS_VS_INTERFACE_INPUT_HEADER, _numfmt, \ - U16_TO_U8S_LE(_totlen + TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (_ctlsz)), \ - _epn, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, _ctlsz, __VA_ARGS__ + U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_IN_LEN + (_numfmt) * (_ctlsz)), \ + _ep, _inf, _termlnk, _sticaptmeth, _trgspt, _trgusg, _ctlsz, __VA_ARGS__ /* 3.9.2.2 */ -#define TUD_VIDEO_DESC_CS_VS_OUTPUT(_numfmt, _totlen, _epn, _inf, _termlnk, _ctlsz, ...) \ +#define TUD_VIDEO_DESC_CS_VS_OUTPUT(_numfmt, _totallen, _ep, _inf, _termlnk, _ctlsz, ...) \ TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (_ctlsz), TUSB_DESC_CS_INTERFACE, \ VIDEO_CS_VS_INTERFACE_OUTPUT_HEADER, _numfmt, \ - U16_TO_U8S_LE(_totlen + TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (_ctlsz)), \ - _epn, _inf, _termlnk, _trgusg, _ctlsz, __VA_ARGS__ + U16_TO_U8S_LE((_totallen) + TUD_VIDEO_DESC_CS_VS_OUT_LEN + (_numfmt) * (_ctlsz)), \ + _ep, _inf, _termlnk, _ctlsz, __VA_ARGS__ /* Uncompressed 3.1.1 */ #define TUD_VIDEO_GUID(_g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15) _g0,_g1,_g2,_g3,_g4,_g5,_g6,_g7,_g8,_g9,_g10,_g11,_g12,_g13,_g14,_g15 + #define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfrmdesc, \ _guid, _bitsperpix, _frmidx, _asrx, _asry, _interlace, _cp) \ TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_FORMAT_UNCOMPRESSED, \ @@ -353,6 +384,12 @@ typedef struct TU_ATTR_PACKED { _frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \ U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), _numfrminterval, __VA_ARGS__ +/* 3.9.2.6 */ +#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \ + TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \ + TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_COLORFORMAT, \ + _color, _trns, _mat + /* 3.10.1.1 */ #define TUD_VIDEO_DESC_EP_ISO(_ep, _epsize, _ep_interval) \ 7, TUSB_DESC_ENDPOINT, _ep, TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_ASYNCHRONOUS,\ diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index badd838a1..94ae325dc 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -183,7 +183,7 @@ static void const* _find_desc_itf(void const *beg, void const *end, unsigned itf static void const* _find_desc_entity(tusb_desc_vc_itf_t const *vc, unsigned entityid) { void const *beg = (void const*)vc; - void const *end = beg + vc->std.bLength + vc->ctl.bLength + vc->ctl.wTotalLength; + void const *end = beg + vc->std.bLength + vc->ctl.wTotalLength; for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) { tusb_desc_cs_video_entity_itf_t const *itf = (tusb_desc_cs_video_entity_itf_t const *)cur; if ((VIDEO_CS_VC_INTERFACE_INPUT_TERMINAL == itf->bDescriptorSubtype || @@ -206,7 +206,7 @@ static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) /* The next descriptor after the class-specific VC interface header descriptor. */ void const *cur = (void const*)vc + vc->std.bLength + vc->ctl.bLength; /* The end of the video control interface descriptor. */ - void const *end = cur + vc->ctl.wTotalLength; + void const *end = (void const*)vc + vc->std.bLength + vc->ctl.wTotalLength; if (vc->std.bNumEndpoints) { /* Find the notification endpoint descriptor. */ cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); @@ -224,21 +224,25 @@ static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self) * @param[in] altnum The target alternate setting number. */ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, unsigned altnum) { + TU_LOG2(" open VC %d\r\n", altnum); void const *beg = self->beg; void const *end = beg + self->len; /* The first descriptor is a video control interface descriptor. */ unsigned itfnum = ((tusb_desc_interface_t const *)beg)->bInterfaceNumber; void const *cur = _find_desc_itf(beg, end, itfnum, altnum); + TU_LOG2(" cur %ld\r\n", cur - beg); TU_VERIFY(cur < end); tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)cur; + TU_LOG2(" bInCollection %d\r\n", vc->ctl.bInCollection); /* Support for up to 2 streaming interfaces only. */ TU_ASSERT(vc->ctl.bInCollection < 3); + /* Update to point the end of the video control interface descriptor. */ + end = cur + vc->std.bLength + vc->ctl.wTotalLength; /* Advance to the next descriptor after the class-specific VC interface header descriptor. */ cur += vc->std.bLength + vc->ctl.bLength; - /* Update to point the end of the video control interface descriptor. */ - end = cur + vc->ctl.wTotalLength; + TU_LOG2(" bNumEndpoints %d\r\n", vc->std.bNumEndpoints); /* Open the notification endpoint if it exist. */ if (vc->std.bNumEndpoints) { /* Support for 1 endpoint only. */ @@ -266,7 +270,7 @@ static bool _close_vs_itf(uint8_t rhport, videod_interface_t *self, unsigned itf /* The next of the video streaming interface header descriptor. */ void const *cur = (void const*)vs + vs->std.bLength + vs->stm.bLength; /* The end of the video streaming interface descriptor. */ - void const *end = cur + vs->stm.wTotalLength; + void const *end = (void const*)vs + vs->std.bLength + vs->stm.wTotalLength; for (unsigned i = 0; i < vs->std.bNumEndpoints; ++i) { cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); TU_ASSERT(cur < end); @@ -285,6 +289,7 @@ static bool _close_vs_itf(uint8_t rhport, videod_interface_t *self, unsigned itf * @param[in] altnum The target alternate setting number. */ static bool _open_vs_itf(uint8_t rhport, videod_interface_t *self, unsigned itfnum, unsigned altnum) { + TU_LOG2(" open VS %d,%d\r\n", itfnum, altnum); uint16_t *ofs = NULL; for (unsigned i = 1; i < sizeof(self->ofs)/sizeof(self->ofs[0]); ++i) { if (!self->ofs[i]) { @@ -297,17 +302,17 @@ static bool _open_vs_itf(uint8_t rhport, videod_interface_t *self, unsigned itfn tusb_desc_vc_itf_t const *vc = _get_desc_vc(self); void const *end = self->beg + self->len; /* Set the end of the video control interface descriptor. */ - void const *cur = (void const*)vc + vc->std.bLength + vc->ctl.bLength + vc->ctl.wTotalLength; + void const *cur = (void const*)vc + vc->std.bLength + vc->ctl.wTotalLength; cur = _find_desc_itf(cur, end, itfnum, altnum); TU_VERIFY(cur < end); tusb_desc_vs_itf_t const *vs = (tusb_desc_vs_itf_t const*)cur; /* Support for up to 2 endpoint only. */ TU_ASSERT(vs->std.bNumEndpoints < 3); + /* Update to point the end of the video control interface descriptor. */ + end = cur + vs->std.bLength + vs->stm.wTotalLength; /* Advance to the next descriptor after the class-specific VS interface header descriptor. */ cur += vs->std.bLength + vs->stm.bLength; - /* Update to point the end of the video control interface descriptor. */ - end = cur + vs->stm.wTotalLength; for (unsigned i = 0; i < vs->std.bNumEndpoints; ++i) { cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT); TU_VERIFY(cur < end); @@ -612,7 +617,7 @@ uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uin itfnum = vc->ctl.baInterfaceNr[i]; if (!_open_vs_itf(rhport, self, itfnum, 0)) return 0; } - return end - cur; + return (uintptr_t)cur - (uintptr_t)itf_desc; } // Invoked when a control transfer occurred on an interface of this class