30#if (CFG_TUD_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING)
38#ifndef CFG_TUD_VIDEO_LOG_LEVEL
39 #define CFG_TUD_VIDEO_LOG_LEVEL CFG_TUD_LOG_LEVEL
42#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_VIDEO_LOG_LEVEL, __VA_ARGS__)
47#define VS_STATE_PROBING 0
48#define VS_STATE_COMMITTED 1
49#define VS_STATE_STREAMING 2
53 tusb_desc_video_control_header_t
ctl;
62 tusb_desc_video_control_header_t
ctl;
120 CFG_TUSB_MEM_ALIGN uint8_t
ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE];
128 uint8_t
stm[CFG_TUD_VIDEO_STREAMING];
137#define ITF_STM_MEM_RESET_SIZE offsetof(videod_streaming_interface_t, ep_buf)
151#if CFG_TUSB_DEBUG >= CFG_TUD_VIDEO_LOG_LEVEL
179 "Request Error Code",
188 "Still Image Trigger",
190 "Generate Key Frame",
191 "Update Frame Segment",
207 return ((uint8_t
const*)
desc)[2];
216 return ((uint8_t
const*)
desc)[2];
227 if (!ctl->
beg)
return NULL;
229 if (!stm->
desc.beg)
return NULL;
238 if (!self->desc.cur)
return NULL;
251static void const*
_find_desc(
void const *beg,
void const *end, uint_fast8_t desc_type) {
252 void const *cur = beg;
253 while ((cur < end) && (desc_type !=
tu_desc_type(cur))) {
268static void const*
_find_desc_2_type(
void const *beg,
void const *end, uint_fast8_t desc_type_0, uint_fast8_t desc_type_1)
270 void const *cur = beg;
288 uint_fast8_t desc_type,
289 uint_fast8_t element_0,
290 uint_fast8_t element_1) {
291 for (
void const *cur = beg; cur < end; cur =
_find_desc(cur, end, desc_type)) {
292 uint8_t
const *p = (uint8_t
const *)cur;
293 if ((p[2] == element_0) && (p[3] == element_1)) {
313 void const *cur = beg;
315 while ((cur < end) &&
331static inline uint8_t
const*
_find_desc_itf(
void const *beg,
void const *end, uint_fast8_t itfnum, uint_fast8_t altnum)
347 for (
void const *cur = beg; cur < end; cur =
tu_desc_next(cur)) {
359 return ((uint8_t
const*)
desc) + vc->
std.
bLength + tu_le16toh(vc->
ctl.wTotalLength);
375 if ((VIDEO_CS_ITF_VC_INPUT_TERMINAL <= itf->bDescriptorSubtype
393static inline void const *
_find_desc_format(
void const *beg,
void const *end, uint_fast8_t fmtnum)
396 uint8_t
const *p = (uint8_t
const *)cur;
397 uint_fast8_t fmt = p[2];
411static inline void const *
_find_desc_frame(
void const *beg,
void const *end, uint_fast8_t frmnum)
414 uint8_t
const *p = (uint8_t
const *)cur;
415 uint_fast8_t frm = p[2];
457 TU_ASSERT(fmt != end);
459 switch (fmt->bDescriptorSubType) {
467 default:
return false;
471 TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors);
473 if (1 < fmt->bNumFrameDescriptors)
return true;
478 TU_ASSERT(frm != end);
483 switch (fmt->bDescriptorSubType) {
489 frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8;
507 uint_fast32_t interval_ms = interval / 10000;
508 TU_ASSERT(interval_ms);
509 uint_fast32_t payload_size = (frame_size + interval_ms - 1) / interval_ms + 2;
510 if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) {
511 payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE;
538 default:
return false;
564 frmnum = fmt->bNumFrameDescriptors;
572 switch (fmt->bDescriptorSubType) {
581 default:
return false;
584 default:
return false;
589 uint_fast32_t frame_size;
590 switch (fmt->bDescriptorSubType) {
596 frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * 16 / 8;
599 default:
return false;
612 uint_fast32_t interval, interval_ms;
615 uint_fast32_t min_interval, max_interval;
616 uint_fast8_t num_intervals = frm->
uncompressed.bFrameIntervalType;
617 max_interval = num_intervals ? frm->
uncompressed.dwFrameInterval[num_intervals - 1]: frm->
uncompressed.dwFrameInterval[1];
619 interval = max_interval;
620 interval_ms = min_interval / 10000;
625 uint_fast32_t min_interval, max_interval;
626 uint_fast8_t num_intervals = frm->
uncompressed.bFrameIntervalType;
627 max_interval = num_intervals ? frm->
uncompressed.dwFrameInterval[num_intervals - 1]: frm->
uncompressed.dwFrameInterval[1];
629 interval = min_interval;
630 interval_ms = max_interval / 10000;
636 interval_ms = interval / 10000;
640 uint_fast8_t num_intervals = frm->
uncompressed.bFrameIntervalType;
646 interval_ms = interval / 10000;
651 default:
return false;
658 uint_fast32_t payload_size;
660 payload_size = frame_size + 2;
662 payload_size = (frame_size + interval_ms - 1) / interval_ms + 2;
664 if (CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE < payload_size) {
665 payload_size = CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE;
683 void const *cur = (uint8_t
const*)vc + vc->
std.
bLength + vc->
ctl.bLength;
690 TU_ASSERT(cur < end);
704 TU_LOG_DRV(
" open VC %d\r\n", altnum);
705 uint8_t
const *beg =
self->beg;
706 uint8_t
const *end = beg +
self->len;
710 TU_LOG_DRV(
" cur %" PRId32
"\r\n", (int32_t) (cur - beg));
711 TU_VERIFY(cur < end);
714 TU_LOG_DRV(
" bInCollection %d\r\n", vc->
ctl.bInCollection);
716 TU_ASSERT(vc->
ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING);
730 TU_VERIFY(cur < end);
735 self->cur = (uint16_t) ((uint8_t
const*)vc - beg);
741 stm->
state = VS_STATE_PROBING;
744 tu_memclr(param,
sizeof(*param));
755 TU_LOG_DRV(
" reopen VS %d\r\n", altnum);
758#ifndef TUP_DCD_EDPT_ISO_ALLOC
760 for (i = 0; i < TU_ARRAY_SIZE(stm->
desc.ep); ++i) {
761 uint_fast16_t ofs_ep = stm->
desc.ep[i];
779 uint8_t
const *beg =
desc + stm->
desc.beg;
780 uint8_t
const *end =
desc + stm->
desc.end;
782 TU_VERIFY(cur < end);
785 TU_ASSERT(numeps <= TU_ARRAY_SIZE(stm->
desc.ep));
786 stm->
desc.cur = (uint16_t)(cur -
desc);
787 if (!altnum && (VS_STATE_COMMITTED != stm->
state)) {
793 TU_ASSERT(cur < end);
799#ifdef TUP_DCD_EDPT_ISO_ALLOC
808 stm->
desc.ep[i] = (uint16_t) (cur -
desc);
812 stm->
state = VS_STATE_STREAMING;
814 TU_LOG_DRV(
" done\r\n");
822 uint_fast16_t hdr_len = stm->
ep_buf[0];
824 if (hdr_len + remaining < pkt_len) {
825 pkt_len = hdr_len + remaining;
827 TU_ASSERT(pkt_len >= hdr_len);
828 uint_fast16_t data_len = pkt_len - hdr_len;
831 remaining -= data_len;
836 return hdr_len + data_len;
842 uint_fast8_t ctl_idx)
877 uint_fast8_t ctl_idx)
947 uint_fast8_t ctl_idx)
970 uint_fast8_t stm_idx)
1002 uint_fast8_t stm_idx) {
1031 if (self->state != VS_STATE_PROBING) {
1032 self->state = VS_STATE_PROBING;
1099 self->state = VS_STATE_COMMITTED;
1100 self->buffer = NULL;
1156 uint_fast8_t stm_idx)
1176 TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
1178 if (stm)
return true;
1184 TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
1185 TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);
1187 if (!stm || !stm->
desc.ep[0])
return false;
1188 if (stm->
state == VS_STATE_PROBING)
return false;
1190#ifdef TUP_DCD_EDPT_ISO_ALLOC
1192 uint_fast16_t ofs_ep = stm->
desc.ep[0];
1195 if (stm->
state == VS_STATE_COMMITTED)
return false;
1204 TU_ASSERT(ctl_idx < CFG_TUD_VIDEO);
1205 TU_ASSERT(stm_idx < CFG_TUD_VIDEO_STREAMING);
1208 if (!stm || !stm->
desc.ep[0] || stm->
buffer)
return false;
1209 if (stm->
state == VS_STATE_PROBING)
return false;
1213 uint8_t ep_addr = 0;
1214 for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
1215 uint_fast16_t ofs_ep = stm->
desc.ep[i];
1216 if (!ofs_ep)
continue;
1220 if (!ep_addr)
return false;
1239 for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) {
1241 tu_memclr(ctl,
sizeof(*ctl));
1243 for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
1245 tu_memclr(stm, ITF_STM_MEM_RESET_SIZE);
1255 for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO; ++i) {
1257 tu_memclr(ctl,
sizeof(*ctl));
1259 for (uint_fast8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
1261 tu_memclr(stm, ITF_STM_MEM_RESET_SIZE);
1273 for (ctl_idx = 0; ctl_idx < CFG_TUD_VIDEO; ++ctl_idx) {
1278 TU_ASSERT(ctl_idx < CFG_TUD_VIDEO, 0);
1280 uint8_t
const *end = (uint8_t
const*)itf_desc + max_len;
1281 self->
beg = (uint8_t
const*) itf_desc;
1282 self->
len = max_len;
1287 uint_fast8_t bInCollection = vc->
ctl.bInCollection;
1291 for (uint8_t stm_idx = 0; stm_idx < bInCollection; ++stm_idx) {
1294 for (uint8_t i = 0; i < CFG_TUD_VIDEO_STREAMING; ++i) {
1297 self->
stm[stm_idx] = i;
1303 stm->
desc.beg = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
1305 stm->
desc.end = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
1306 stm->
state = VS_STATE_PROBING;
1307#ifdef TUP_DCD_EDPT_ISO_ALLOC
1309 uint16_t ep_size = 0;
1310 uint16_t ep_addr = 0;
1311 uint8_t
const *p_desc = (uint8_t
const*)itf_desc + stm->
desc.beg;
1312 uint8_t
const *p_desc_end = (uint8_t
const*)itf_desc + stm->
desc.end;
1313 while (p_desc < p_desc_end) {
1325 if (0 == stm_idx && 1 == bInCollection) {
1328 uint8_t
const *sbeg = (uint8_t
const*)itf_desc + stm->
desc.beg;
1329 uint8_t
const *send = (uint8_t
const*)itf_desc + stm->
desc.end;
1335 self->len = (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
1336 return (uint16_t) ((uintptr_t)cur - (uintptr_t)itf_desc);
1348 for (itf = 0; itf < CFG_TUD_VIDEO; ++itf) {
1350 if (!
desc)
continue;
1354 if (itf < CFG_TUD_VIDEO) {
1355 TU_LOG_DRV(
" VC[%d]: ", itf);
1358 if (
err)
return false;
1363 for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) {
1365 if (!stm->
desc.beg)
continue;
1370 if (itf < CFG_TUD_VIDEO_STREAMING) {
1371 TU_LOG_DRV(
" VS[%d]: ", itf);
1374 if (
err)
return false;
1381 (void)result; (void)xferred_bytes;
1387 for (itf = 0; itf < CFG_TUD_VIDEO_STREAMING; ++itf) {
1389 uint_fast16_t
const ep_ofs = stm->
desc.ep[0];
1390 if (!ep_ofs)
continue;
1392 uint8_t
const *
desc = ctl->
beg;
1396 TU_ASSERT(itf < CFG_TUD_VIDEO_STREAMING);
static usb_descriptor_buffers_t desc
static void * memcpy(void *dst, const void *src, size_t n)
AUDIO Channel Cluster Descriptor (4.1)
struct TU_ATTR_PACKED::@66 desc
uint32_t max_payload_transfer_size
uint32_t dwFrameInterval[]
uint32_t dwMaxVideoFrameSize
uint32_t dwMaxPayloadTransferSize
CFG_TUSB_MEM_ALIGN uint8_t ep_buf[CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE]
uint16_t wTotalLength
Total number of bytes returned for the class-specific AudioControl interface descriptor....
struct TU_ATTR_PACKED::@16::TU_ATTR_PACKED bmRequestType_bit
uint8_t bmAttributes
See: audio_clock_source_attribute_t.
uint8_t bDefaultFrameIndex
uint32_t dwClockFrequency
uint8_t stm[CFG_TUD_VIDEO_STREAMING]
uint8_t bDescriptorType
Descriptor Type. Value: TUSB_DESC_CS_INTERFACE.
uint8_t bInterfaceClass
Class code (assigned by the USB-IF).
uint8_t bLength
Size of this descriptor in bytes: 9.
uint8_t bInterfaceSubClass
Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bInterfaceCla...
uint8_t bRequest
Request type audio_cs_req_t.
uint8_t bNumEndpoints
Number of endpoints used by this interface (excluding endpoint zero). If this value is zero,...
uint8_t bInterfaceProtocol
Protocol code (assigned by the USB). These codes are qualified by the value of the bInterfaceClass ...
uint8_t bDescriptorSubtype
uint8_t bAlternateSetting
Value used to select this alternate setting for the interface identified in the prior field.
video_probe_and_commit_control_t probe_commit_payload
uint8_t bDescriptorSubType
uint8_t bNumFrameDescriptors
uint8_t bDescriptorSubType
tusb_desc_interface_t std
tusb_desc_video_control_header_t ctl
tusb_desc_interface_t std
tusb_desc_video_streaming_inout_header_t stm
static TU_ATTR_ALWAYS_INLINE uint8_t tu_u16_low(uint16_t ui16)
static const char * tu_lookup_find(tu_lookup_table_t const *p_table, uint32_t key)
@ TUSB_REQ_RCPT_INTERFACE
static TU_ATTR_ALWAYS_INLINE uint16_t tu_edpt_packet_size(tusb_desc_endpoint_t const *desc_ep)
static TU_ATTR_ALWAYS_INLINE uint8_t tu_desc_type(void const *desc)
static TU_ATTR_ALWAYS_INLINE uint8_t const * tu_desc_next(void const *desc)
@ TUSB_DESC_INTERFACE_ASSOCIATION
tusb_desc_video_format_mjpeg_t mjpeg
tusb_desc_video_format_framebased_t frame_based
tusb_desc_video_format_uncompressed_t uncompressed
tusb_desc_video_frame_mjpeg_t mjpeg
tusb_desc_video_frame_framebased_t frame_based
tusb_desc_video_frame_uncompressed_t uncompressed
tusb_desc_video_streaming_inout_header_t stm
tusb_desc_video_control_header_t ctl
void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr)
bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
bool usbd_edpt_claim(uint8_t rhport, uint8_t ep_addr)
bool usbd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *desc_ep)
bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size)
bool tud_control_xfer(uint8_t rhport, tusb_control_request_t const *request, void *buffer, uint16_t len)
bool tud_control_status(uint8_t rhport, tusb_control_request_t const *request)
CFG_TUH_MEM_ALIGN tusb_control_request_t request
@ VIDEO_VS_CTL_UPDATE_FRAME_SEGMENT
@ VIDEO_VS_CTL_STILL_IMAGE_TRIGGER
@ VIDEO_VS_CTL_STREAM_ERROR_CODE
@ VIDEO_VS_CTL_STILL_PROBE
@ VIDEO_VS_CTL_STILL_COMMIT
@ VIDEO_VS_CTL_GENERATE_KEY_FRAME
@ VIDEO_VS_CTL_SYNCH_DELAY_CONTROL
tusb_desc_video_frame_uncompressed_t tusb_desc_video_frame_mjpeg_t
@ VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED
@ VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED
@ VIDEO_CS_ITF_VS_FORMAT_MJPEG
@ VIDEO_CS_ITF_VS_FORMAT_DV
@ VIDEO_CS_ITF_VS_FRAME_FRAME_BASED
@ VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED
@ VIDEO_CS_ITF_VS_FRAME_MJPEG
struct TU_ATTR_PACKED video_probe_and_commit_control_t
@ VIDEO_REQUEST_SET_CUR_ALL
@ VIDEO_REQUEST_GET_DEF_ALL
@ VIDEO_REQUEST_UNDEFINED
@ VIDEO_REQUEST_GET_CUR_ALL
@ VIDEO_REQUEST_GET_MIN_ALL
@ VIDEO_REQUEST_GET_RES_ALL
@ VIDEO_REQUEST_GET_MAX_ALL
@ VIDEO_ERROR_INVALID_REQUEST
@ VIDEO_ERROR_INVALID_VALUE_WITHIN_RANGE
@ VIDEO_VC_CTL_VIDEO_POWER_MODE
@ VIDEO_VC_CTL_REQUEST_ERROR_CODE
static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self)
static void const * _find_desc_entity(void const *desc, uint_fast8_t entityid)
static tu_lookup_entry_t const tu_lookup_video_request[]
static int handle_video_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t ctl_idx)
struct TU_ATTR_PACKED videod_interface_t
static void const * _next_desc_itf(void const *beg, void const *end)
struct TU_ATTR_PACKED tusb_desc_cs_video_entity_itf_t
bool tud_video_n_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
static bool _update_streaming_parameters(videod_streaming_interface_t const *stm, video_probe_and_commit_control_t *param)
CFG_TUD_MEM_SECTION tu_static videod_streaming_interface_t _videod_streaming_itf[CFG_TUD_VIDEO_STREAMING]
static char const *const tu_str_video_vc_control_selector[]
static void const * _find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum)
bool videod_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
static bool _open_vs_itf(uint8_t rhport, videod_streaming_interface_t *stm, uint_fast8_t altnum)
static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t altnum)
static void const * _end_of_streaming_descriptor(void const *desc)
void videod_reset(uint8_t rhport)
static bool _init_vs_configuration(videod_streaming_interface_t *stm)
uint16_t videod_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
static tu_lookup_table_t const tu_table_video_request
bool videod_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
static void const * _find_desc_3(void const *beg, void const *end, uint_fast8_t desc_type, uint_fast8_t element_0, uint_fast8_t element_1)
bool tud_video_n_frame_xfer(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, void *buffer, size_t bufsize)
static char const *const tu_str_video_vs_control_selector[]
static uint8_t const * _find_desc_itf(void const *beg, void const *end, uint_fast8_t itfnum, uint_fast8_t altnum)
static int handle_video_stm_std_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t stm_idx)
static void const * _find_desc_2_type(void const *beg, void const *end, uint_fast8_t desc_type_0, uint_fast8_t desc_type_1)
tu_static uint8_t const _cap_get_set
CFG_TUD_MEM_SECTION tu_static videod_interface_t _videod_itf[CFG_TUD_VIDEO]
static bool _negotiate_streaming_parameters(videod_streaming_interface_t const *stm, uint_fast8_t request, video_probe_and_commit_control_t *param)
bool tud_video_n_connected(uint_fast8_t ctl_idx)
struct TU_ATTR_PACKED videod_streaming_interface_t
static uint_fast16_t _prepare_in_payload(videod_streaming_interface_t *stm)
static void const * _find_desc_ep(void const *beg, void const *end)
static int handle_video_stm_cs_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t stm_idx)
static uint8_t _desc_itfnum(void const *desc)
static videod_streaming_interface_t * _get_instance_streaming(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
static void const * _find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum)
static int handle_video_ctl_cs_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t ctl_idx)
static void const * _end_of_control_descriptor(void const *desc)
static uint8_t _desc_ep_addr(void const *desc)
static int handle_video_stm_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t stm_idx)
static tusb_desc_vs_itf_t const * _get_desc_vs(videod_streaming_interface_t const *self)
static void const * _find_desc(void const *beg, void const *end, uint_fast8_t desc_type)
static tusb_desc_vc_itf_t const * _get_desc_vc(videod_interface_t const *self)
tu_static uint8_t const _cap_get
static int handle_video_ctl_std_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request, uint_fast8_t ctl_idx)
TU_ATTR_WEAK int tud_video_power_mode_cb(uint_fast8_t ctl_idx, uint8_t power_mod)
TU_ATTR_WEAK void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx)
TU_ATTR_WEAK int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx, video_probe_and_commit_control_t const *parameters)