Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UVC example: change input terminal type to camera from external #1150

Merged
merged 3 commits into from
Oct 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions examples/device/video_capture/src/usb_descriptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -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\
Expand Down Expand Up @@ -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), \
Expand All @@ -108,5 +110,4 @@ enum {
/* EP */ \
TUD_VIDEO_DESC_EP_ISO(_epin, _epsize, 1)


#endif
8 changes: 8 additions & 0 deletions src/class/video/video.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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, \
Expand Down
122 changes: 90 additions & 32 deletions src/class/video/video_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, default values or resolutions 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, GET_RES 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;
Expand All @@ -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);
Expand All @@ -405,18 +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_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];
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;
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:
{
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;
Expand Down Expand Up @@ -778,32 +831,28 @@ static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage,
return VIDEO_ERROR_NONE;

case VIDEO_REQUEST_GET_MIN:
case VIDEO_REQUEST_GET_MAX:
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, false, &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);
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_NONE;

case VIDEO_REQUEST_GET_MAX:
case VIDEO_REQUEST_GET_LEN:
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, true, &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);
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_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_INFO:
if (stage == CONTROL_STAGE_SETUP)
{
Expand Down Expand Up @@ -838,6 +887,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)
{
Expand Down