From 7325dd633536d086491ef057a544760886190cc7 Mon Sep 17 00:00:00 2001 From: kkitayam <45088311+kkitayam@users.noreply.github.com> Date: Sat, 16 Oct 2021 12:06:13 +0900 Subject: [PATCH 1/3] Change input terminal type to camera --- examples/device/video_capture/src/usb_descriptors.h | 9 +++++---- src/class/video/video.h | 8 ++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/examples/device/video_capture/src/usb_descriptors.h b/examples/device/video_capture/src/usb_descriptors.h index 340b3f79..eeaef6bd 100644 --- a/examples/device/video_capture/src/usb_descriptors.h +++ b/examples/device/video_capture/src/usb_descriptors.h @@ -48,7 +48,7 @@ enum { /* control */\ + TUD_VIDEO_DESC_STD_VC_LEN\ + (TUD_VIDEO_DESC_CS_VC_LEN + 1/*bInCollection*/)\ - + TUD_VIDEO_DESC_INPUT_TERM_LEN\ + + TUD_VIDEO_DESC_CAMERA_TERM_LEN\ + TUD_VIDEO_DESC_OUTPUT_TERM_LEN\ /* Interface 1, Alternate 0 */\ + TUD_VIDEO_DESC_STD_VS_LEN\ @@ -79,9 +79,11 @@ enum { TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \ TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \ /* wTotalLength - bLength */ \ - TUD_VIDEO_DESC_INPUT_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ + TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \ UVC_CLOCK_FREQUENCY, 1), \ - TUD_VIDEO_DESC_INPUT_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, VIDEO_ETT_COMPOSITE_CONNECTOR, 0, 0), \ + TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\ + /*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\ + /*wObjectiveFocalLength*/0, /*bmControls*/0), \ TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \ /* Video stream alt. 0 */ \ TUD_VIDEO_DESC_STD_VS( 1, 0, 0, 0), \ @@ -108,5 +110,4 @@ enum { /* EP */ \ TUD_VIDEO_DESC_EP_ISO(_epin, _epsize, 1) - #endif diff --git a/src/class/video/video.h b/src/class/video/video.h index fa297661..84474654 100644 --- a/src/class/video/video.h +++ b/src/class/video/video.h @@ -373,6 +373,7 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c #define TUD_VIDEO_DESC_CS_VC_LEN 12 #define TUD_VIDEO_DESC_INPUT_TERM_LEN 8 #define TUD_VIDEO_DESC_OUTPUT_TERM_LEN 9 +#define TUD_VIDEO_DESC_CAMERA_TERM_LEN 18 #define TUD_VIDEO_DESC_STD_VS_LEN 9 #define TUD_VIDEO_DESC_CS_VS_IN_LEN 13 #define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9 @@ -412,6 +413,13 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c TUD_VIDEO_DESC_OUTPUT_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_OUTPUT_TERMINAL, \ _tid, U16_TO_U8S_LE(_tt), _at, _srcid, _stridx +/* 3.7.2.3 */ +#define TUD_VIDEO_DESC_CAMERA_TERM(_tid, _at, _stridx, _focal_min, _focal_max, _focal, _ctls) \ + TUD_VIDEO_DESC_CAMERA_TERM_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VC_INPUT_TERMINAL, \ + _tid, U16_TO_U8S_LE(VIDEO_ITT_CAMERA), _at, _stridx, \ + U16_TO_U8S_LE(_focal_min), U16_TO_U8S_LE(_focal_max), U16_TO_U8S_LE(_focal), 3, \ + TU_U32_BYTE0(_ctls), TU_U32_BYTE1(_ctls), TU_U32_BYTE2(_ctls) + /* 3.9.1 */ #define TUD_VIDEO_DESC_STD_VS(_itfnum, _alt, _epn, _stridx) \ TUD_VIDEO_DESC_STD_VS_LEN, TUSB_DESC_INTERFACE, _itfnum, _alt, \ From 4fd0ee4eef149237aa58b24e843649b16d5ca1dc Mon Sep 17 00:00:00 2001 From: kkitayam <45088311+kkitayam@users.noreply.github.com> Date: Sat, 16 Oct 2021 15:52:46 +0900 Subject: [PATCH 2/3] Implement GET_DEF and GET_LEN handling on Probe/Commit entities of streaming interface --- src/class/video/video_device.c | 86 +++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index 91d3b2b7..cd6459a1 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -354,21 +354,25 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm return true; } -/** Set the minimum or the maximum values to variables which need to negotiate with the host +/** Set the minimum, maximum or default values to variables which need to negotiate with the host * - * @param[in] set_max If true, the maximum values is set, otherwise the minimum value is set. + * @param[in] request GET_MAX, GET_MIN or GET_DEF * @param[in,out] param Target */ -static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, bool set_max, +static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, uint_fast8_t request, video_probe_and_commit_control_t *param) { uint_fast8_t const fmtnum = param->bFormatIndex; if (!fmtnum) { - if (set_max) { - tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); - param->bFormatIndex = vs->stm.bNumFormats; - } else { - param->bFormatIndex = 1; + switch (request) { + case VIDEO_REQUEST_GET_MAX: + param->bFormatIndex = _get_desc_vs(stm)->stm.bNumFormats; + break; + case VIDEO_REQUEST_GET_MIN: + case VIDEO_REQUEST_GET_DEF: + param->bFormatIndex = 1; + break; + default: return false; } /* Set the parameters determined by the format */ param->wKeyFrameRate = 1; @@ -391,7 +395,18 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * tusb_desc_vs_itf_t const *vs = _get_desc_vs(stm); void const *end = _end_of_streaming_descriptor(vs); tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); - frmnum = set_max ? fmt->bNumFrameDescriptors: 1; + switch (request) { + case VIDEO_REQUEST_GET_MAX: + frmnum = fmt->bNumFrameDescriptors; + break; + case VIDEO_REQUEST_GET_MIN: + frmnum = 1; + break; + case VIDEO_REQUEST_GET_DEF: + frmnum = fmt->bDefaultFrameIndex; + break; + default: return false; + } param->bFrameIndex = frmnum; /* Set the parameters determined by the frame */ tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); @@ -406,11 +421,20 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); uint_fast32_t interval; - uint_fast8_t num_intervals = frm->bFrameIntervalType; - if (!num_intervals) { - interval = set_max ? frm->dwFrameInterval[1]: frm->dwFrameInterval[0]; - } else { - interval = set_max ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[0]; + switch (request) { + case VIDEO_REQUEST_GET_MAX: + { + uint_fast8_t num_intervals = frm->bFrameIntervalType; + interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; + } + break; + case VIDEO_REQUEST_GET_MIN: + interval = frm->dwFrameInterval[0]; + break; + case VIDEO_REQUEST_GET_DEF: + interval = frm->dwDefaultFrameInterval; + break; + default: return false; } param->dwFrameInterval = interval; uint_fast32_t interval_ms = interval / 10000; @@ -784,7 +808,7 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, video_probe_and_commit_control_t tmp; tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; - TU_VERIFY(_negotiate_streaming_parameters(self, false, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + TU_VERIFY(_negotiate_streaming_parameters(self, VIDEO_REQUEST_GET_MIN, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); } return VIDEO_ERROR_NONE; @@ -795,14 +819,31 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); video_probe_and_commit_control_t tmp; tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; - TU_VERIFY(_negotiate_streaming_parameters(self, true, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + TU_VERIFY(_negotiate_streaming_parameters(self, VIDEO_REQUEST_GET_MAX, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); } return VIDEO_ERROR_NONE; case VIDEO_REQUEST_GET_RES: return VIDEO_ERROR_UNKNOWN; - case VIDEO_REQUEST_GET_DEF: return VIDEO_ERROR_UNKNOWN; - case VIDEO_REQUEST_GET_LEN: return VIDEO_ERROR_UNKNOWN; + case VIDEO_REQUEST_GET_DEF: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); + video_probe_and_commit_control_t tmp; + tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; + TU_VERIFY(_negotiate_streaming_parameters(self, VIDEO_REQUEST_GET_DEF, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_UNKNOWN; + + case VIDEO_REQUEST_GET_LEN: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN); + uint16_t len = sizeof(video_probe_and_commit_control_t); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; case VIDEO_REQUEST_GET_INFO: if (stage == CONTROL_STAGE_SETUP) @@ -838,6 +879,15 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, } return VIDEO_ERROR_NONE; + case VIDEO_REQUEST_GET_LEN: + if (stage == CONTROL_STAGE_SETUP) + { + TU_VERIFY(2 == request->wLength, VIDEO_ERROR_UNKNOWN); + uint16_t len = sizeof(video_probe_and_commit_control_t); + TU_VERIFY(tud_control_xfer(rhport, request, (uint8_t*)&len, sizeof(len)), VIDEO_ERROR_UNKNOWN); + } + return VIDEO_ERROR_NONE; + case VIDEO_REQUEST_GET_INFO: if (stage == CONTROL_STAGE_SETUP) { From b3b6b4f785de6916ce352c308108242227ce8a47 Mon Sep 17 00:00:00 2001 From: kkitayam <45088311+kkitayam@users.noreply.github.com> Date: Tue, 19 Oct 2021 21:49:00 +0900 Subject: [PATCH 3/3] Update _negotiate_streaming_parameters() to handle some requests --- src/class/video/video_device.c | 74 +++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/src/class/video/video_device.c b/src/class/video/video_device.c index cd6459a1..3cd25628 100644 --- a/src/class/video/video_device.c +++ b/src/class/video/video_device.c @@ -354,9 +354,9 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm return true; } -/** Set the minimum, maximum or default values to variables which need to negotiate with the host +/** Set the minimum, maximum, default values or resolutions to variables which need to negotiate with the host * - * @param[in] request GET_MAX, GET_MIN or GET_DEF + * @param[in] request GET_MAX, GET_MIN, GET_RES or GET_DEF * @param[in,out] param Target */ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, uint_fast8_t request, @@ -420,27 +420,56 @@ static bool _negotiate_streaming_parameters(videod_streaming_interface_t const * tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum); tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum); - uint_fast32_t interval; + uint_fast32_t interval, interval_ms; switch (request) { case VIDEO_REQUEST_GET_MAX: { + uint_fast32_t min_interval, max_interval; uint_fast8_t num_intervals = frm->bFrameIntervalType; - interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; + max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; + min_interval = frm->dwFrameInterval[0]; + interval = max_interval; + interval_ms = min_interval / 10000; } break; case VIDEO_REQUEST_GET_MIN: - interval = frm->dwFrameInterval[0]; + { + uint_fast32_t min_interval, max_interval; + uint_fast8_t num_intervals = frm->bFrameIntervalType; + max_interval = num_intervals ? frm->dwFrameInterval[num_intervals - 1]: frm->dwFrameInterval[1]; + min_interval = frm->dwFrameInterval[0]; + interval = min_interval; + interval_ms = max_interval / 10000; + } break; case VIDEO_REQUEST_GET_DEF: interval = frm->dwDefaultFrameInterval; + interval_ms = interval / 10000; + break; + case VIDEO_REQUEST_GET_RES: + { + uint_fast8_t num_intervals = frm->bFrameIntervalType; + if (num_intervals) { + interval = 0; + } else { + interval = frm->dwFrameInterval[2]; + interval_ms = interval / 10000; + } + } break; default: return false; } param->dwFrameInterval = interval; - uint_fast32_t interval_ms = interval / 10000; - TU_ASSERT(interval_ms); - uint_fast32_t frame_size = param->dwMaxVideoFrameSize; - param->dwMaxPayloadTransferSize = (frame_size + interval_ms - 1) / interval_ms + 2; + if (!interval) { + param->dwMaxPayloadTransferSize = 0; + } else { + uint_fast32_t frame_size = param->dwMaxVideoFrameSize; + if (!interval_ms) { + param->dwMaxPayloadTransferSize = frame_size + 2; + } else { + param->dwMaxPayloadTransferSize = (frame_size + interval_ms - 1) / interval_ms + 2; + } + } return true; } return true; @@ -802,39 +831,18 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, return VIDEO_ERROR_NONE; case VIDEO_REQUEST_GET_MIN: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); - - video_probe_and_commit_control_t tmp; - tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; - TU_VERIFY(_negotiate_streaming_parameters(self, VIDEO_REQUEST_GET_MIN, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); - TU_VERIFY(tud_control_xfer(rhport, request, &tmp, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - case VIDEO_REQUEST_GET_MAX: - if (stage == CONTROL_STAGE_SETUP) - { - TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); - video_probe_and_commit_control_t tmp; - tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; - TU_VERIFY(_negotiate_streaming_parameters(self, VIDEO_REQUEST_GET_MAX, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); - TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); - } - return VIDEO_ERROR_NONE; - - case VIDEO_REQUEST_GET_RES: return VIDEO_ERROR_UNKNOWN; + case VIDEO_REQUEST_GET_RES: case VIDEO_REQUEST_GET_DEF: if (stage == CONTROL_STAGE_SETUP) { TU_VERIFY(request->wLength, VIDEO_ERROR_UNKNOWN); video_probe_and_commit_control_t tmp; tmp = *(video_probe_and_commit_control_t*)&self->ep_buf; - TU_VERIFY(_negotiate_streaming_parameters(self, VIDEO_REQUEST_GET_DEF, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); + TU_VERIFY(_negotiate_streaming_parameters(self, request->bRequest, &tmp), VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE); TU_VERIFY(tud_control_xfer(rhport, request, self->ep_buf, sizeof(video_probe_and_commit_control_t)), VIDEO_ERROR_UNKNOWN); } - return VIDEO_ERROR_UNKNOWN; + return VIDEO_ERROR_NONE; case VIDEO_REQUEST_GET_LEN: if (stage == CONTROL_STAGE_SETUP)