Skip to content

Commit b5cd673

Browse files
committed
rename and add more video descriptors
use struct to define uvc descriptor for video_capture since uvc is rather too complicated to use macro templates
1 parent bd3c4fb commit b5cd673

File tree

5 files changed

+389
-95
lines changed

5 files changed

+389
-95
lines changed

examples/device/video_capture/src/usb_descriptors.c

Lines changed: 212 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,26 @@
4040
#define USB_VID 0xCafe
4141
#define USB_BCD 0x0200
4242

43+
// String Descriptor Index
44+
enum {
45+
STRID_LANGID = 0,
46+
STRID_MANUFACTURER,
47+
STRID_PRODUCT,
48+
STRID_SERIAL,
49+
STRID_UVC_CONTROL,
50+
STRID_UVC_STREAMING,
51+
};
52+
53+
// array of pointer to string descriptors
54+
char const* string_desc_arr[] = {
55+
(const char[]) {0x09, 0x04}, // 0: is supported language is English (0x0409)
56+
"TinyUSB", // 1: Manufacturer
57+
"TinyUSB Device", // 2: Product
58+
NULL, // 3: Serials will use unique ID if possible
59+
"TinyUSB UVC Control", // 4: UVC Interface
60+
"TinyUSB UVC Streaming", // 5: UVC Interface
61+
};
62+
4363
//--------------------------------------------------------------------+
4464
// Device Descriptors
4565
//--------------------------------------------------------------------+
@@ -60,9 +80,9 @@ tusb_desc_device_t const desc_device = {
6080
.idProduct = USB_PID,
6181
.bcdDevice = 0x0100,
6282

63-
.iManufacturer = 0x01,
64-
.iProduct = 0x02,
65-
.iSerialNumber = 0x03,
83+
.iManufacturer = STRID_MANUFACTURER,
84+
.iProduct = STRID_PRODUCT,
85+
.iSerialNumber = STRID_SERIAL,
6686

6787
.bNumConfigurations = 0x01
6888
};
@@ -164,6 +184,193 @@ uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) {
164184
}
165185
#endif // highspeed
166186

187+
typedef struct TU_ATTR_PACKED {
188+
tusb_desc_interface_t itf;
189+
tusb_desc_video_control_header_1itf_t header;
190+
tusb_desc_video_control_camera_terminal_t camera_terminal;
191+
tusb_desc_video_control_output_terminal_t output_terminal;
192+
} uvc_control_desc_t;
193+
194+
/* Windows support YUY2 and NV12
195+
* https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/usb-video-class-driver-overview */
196+
197+
typedef struct TU_ATTR_PACKED {
198+
tusb_desc_interface_t itf;
199+
tusb_desc_video_streaming_input_header_1byte_t header;
200+
tusb_desc_video_format_uncompressed_t format;
201+
tusb_desc_video_frame_uncompressed_continuous_t frame;
202+
tusb_desc_video_streaming_color_matching_t color;
203+
tusb_desc_endpoint_t ep;
204+
} uvc_streaming_desc_t;
205+
206+
typedef struct TU_ATTR_PACKED {
207+
tusb_desc_configuration_t config;
208+
tusb_desc_interface_assoc_t iad;
209+
uvc_control_desc_t video_control;
210+
uvc_streaming_desc_t video_streaming;
211+
} uvc_cfg_desc_t;
212+
213+
const uvc_cfg_desc_t config_desc = {
214+
.config = {
215+
.bLength = sizeof(tusb_desc_configuration_t),
216+
.bDescriptorType = TUSB_DESC_CONFIGURATION,
217+
218+
.wTotalLength = sizeof(uvc_cfg_desc_t),
219+
.bNumInterfaces = ITF_NUM_TOTAL,
220+
.bConfigurationValue = 1,
221+
.iConfiguration = 0,
222+
.bmAttributes = TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
223+
.bMaxPower = 100 / 2
224+
},
225+
.iad = {
226+
.bLength = sizeof(tusb_desc_interface_assoc_t),
227+
.bDescriptorType = TUSB_DESC_INTERFACE_ASSOCIATION,
228+
229+
.bFirstInterface = ITF_NUM_VIDEO_CONTROL,
230+
.bInterfaceCount = 2,
231+
.bFunctionClass = TUSB_CLASS_VIDEO,
232+
.bFunctionSubClass = VIDEO_SUBCLASS_INTERFACE_COLLECTION,
233+
.bFunctionProtocol = VIDEO_ITF_PROTOCOL_UNDEFINED,
234+
.iFunction = 0
235+
},
236+
237+
.video_control = {
238+
.itf = {
239+
.bLength = sizeof(tusb_desc_interface_t),
240+
.bDescriptorType = TUSB_DESC_INTERFACE,
241+
242+
.bInterfaceNumber = ITF_NUM_VIDEO_CONTROL,
243+
.bAlternateSetting = 0,
244+
.bNumEndpoints = 0,
245+
.bInterfaceClass = TUSB_CLASS_VIDEO,
246+
.bInterfaceSubClass = VIDEO_SUBCLASS_CONTROL,
247+
.bInterfaceProtocol = VIDEO_ITF_PROTOCOL_15,
248+
.iInterface = STRID_UVC_CONTROL
249+
},
250+
.header = {
251+
.bLength = sizeof(tusb_desc_video_control_header_1itf_t),
252+
.bDescriptorType = TUSB_DESC_CS_INTERFACE,
253+
.bDescriptorSubType = VIDEO_CS_ITF_VC_HEADER,
254+
255+
.bcdUVC = VIDEO_BCD_1_50,
256+
.wTotalLength = sizeof(uvc_control_desc_t) - sizeof(tusb_desc_interface_t), // CS VC descriptors only
257+
.dwClockFrequency = UVC_CLOCK_FREQUENCY,
258+
.bInCollection = 1,
259+
.baInterfaceNr = { ITF_NUM_VIDEO_STREAMING }
260+
},
261+
.camera_terminal = {
262+
.bLength = sizeof(tusb_desc_video_control_camera_terminal_t),
263+
.bDescriptorType = TUSB_DESC_CS_INTERFACE,
264+
.bDescriptorSubType = VIDEO_CS_ITF_VC_INPUT_TERMINAL,
265+
266+
.bTerminalID = UVC_ENTITY_CAP_INPUT_TERMINAL,
267+
.wTerminalType = VIDEO_ITT_CAMERA,
268+
.bAssocTerminal = 0,
269+
.iTerminal = 0,
270+
.wObjectiveFocalLengthMin = 0,
271+
.wObjectiveFocalLengthMax = 0,
272+
.wOcularFocalLength = 0,
273+
.bControlSize = 3,
274+
.bmControls = { 0, 0, 0 }
275+
},
276+
.output_terminal = {
277+
.bLength = sizeof(tusb_desc_video_control_output_terminal_t),
278+
.bDescriptorType = TUSB_DESC_CS_INTERFACE,
279+
.bDescriptorSubType = VIDEO_CS_ITF_VC_OUTPUT_TERMINAL,
280+
281+
.bTerminalID = UVC_ENTITY_CAP_OUTPUT_TERMINAL,
282+
.wTerminalType = VIDEO_TT_STREAMING,
283+
.bAssocTerminal = 0,
284+
.bSourceID = UVC_ENTITY_CAP_INPUT_TERMINAL,
285+
.iTerminal = 0
286+
}
287+
},
288+
289+
.video_streaming = {
290+
.itf = {
291+
.bLength = sizeof(tusb_desc_interface_t),
292+
.bDescriptorType = TUSB_DESC_INTERFACE,
293+
294+
.bInterfaceNumber = ITF_NUM_VIDEO_STREAMING,
295+
.bAlternateSetting = 0,
296+
.bNumEndpoints = 1,
297+
.bInterfaceClass = TUSB_CLASS_VIDEO,
298+
.bInterfaceSubClass = VIDEO_SUBCLASS_STREAMING,
299+
.bInterfaceProtocol = VIDEO_ITF_PROTOCOL_15,
300+
.iInterface = STRID_UVC_STREAMING
301+
},
302+
.header = {
303+
.bLength = sizeof(tusb_desc_video_streaming_input_header_1byte_t),
304+
.bDescriptorType = TUSB_DESC_CS_INTERFACE,
305+
.bDescriptorSubType = VIDEO_CS_ITF_VS_INPUT_HEADER,
306+
307+
.bNumFormats = 1,
308+
.wTotalLength = sizeof(uvc_streaming_desc_t) - sizeof(tusb_desc_interface_t) - sizeof(tusb_desc_endpoint_t), // CS VS descriptors only
309+
.bEndpointAddress = EPNUM_VIDEO_IN,
310+
.bmInfo = 0,
311+
.bTerminalLink = UVC_ENTITY_CAP_OUTPUT_TERMINAL,
312+
.bStillCaptureMethod = 0,
313+
.bTriggerSupport = 0,
314+
.bTriggerUsage = 0,
315+
.bControlSize = 1,
316+
.bmaControls = { 0 }
317+
},
318+
.format = {
319+
.bLength = sizeof(tusb_desc_video_format_uncompressed_t),
320+
.bDescriptorType = TUSB_DESC_CS_INTERFACE,
321+
.bDescriptorSubType = VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED,
322+
323+
.bFormatIndex = 1, // 1-based index
324+
.bNumFrameDescriptors = 1,
325+
.guidFormat = { TUD_VIDEO_GUID_YUY2 },
326+
.bBitsPerPixel = 16,
327+
.bDefaultFrameIndex = 1,
328+
.bAspectRatioX = 0,
329+
.bAspectRatioY = 0,
330+
.bmInterlaceFlags = 0,
331+
.bCopyProtect = 0
332+
},
333+
.frame = {
334+
.bLength = sizeof(tusb_desc_video_frame_uncompressed_continuous_t),
335+
.bDescriptorType = TUSB_DESC_CS_INTERFACE,
336+
.bDescriptorSubType = VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED,
337+
338+
.bFrameIndex = 1, // 1-based index
339+
.bmCapabilities = 0,
340+
.wWidth = FRAME_WIDTH,
341+
.wHeight = FRAME_HEIGHT,
342+
.dwMinBitRate = FRAME_WIDTH * FRAME_HEIGHT * 16 * 1,
343+
.dwMaxBitRate = FRAME_WIDTH * FRAME_HEIGHT * 16 * FRAME_RATE,
344+
.dwMaxVideoFrameBufferSize = FRAME_WIDTH * FRAME_HEIGHT * 16 / 8,
345+
.dwDefaultFrameInterval = 10000000 / FRAME_RATE,
346+
.bFrameIntervalType = 0, // continuous
347+
.dwFrameInterval = {
348+
10000000 / FRAME_RATE, // min
349+
10000000, // max
350+
10000000 / FRAME_RATE // step
351+
}
352+
},
353+
.color = {
354+
.bLength = sizeof(tusb_desc_video_streaming_color_matching_t),
355+
.bDescriptorType = TUSB_DESC_CS_INTERFACE,
356+
.bDescriptorSubType = VIDEO_CS_ITF_VS_COLORFORMAT,
357+
358+
.bColorPrimaries = VIDEO_COLOR_PRIMARIES_BT709,
359+
.bTransferCharacteristics = VIDEO_COLOR_XFER_CH_BT709,
360+
.bMatrixCoefficients = VIDEO_COLOR_COEF_SMPTE170M
361+
},
362+
.ep = {
363+
.bLength = sizeof(tusb_desc_endpoint_t),
364+
.bDescriptorType = TUSB_DESC_ENDPOINT,
365+
366+
.bEndpointAddress = EPNUM_VIDEO_IN,
367+
.bmAttributes = { .xfer = TUSB_XFER_BULK },
368+
.wMaxPacketSize = CFG_TUD_VIDEO_STREAMING_BULK ? 64 : CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE,
369+
.bInterval = 1
370+
}
371+
}
372+
};
373+
167374
// Invoked when received GET CONFIGURATION DESCRIPTOR
168375
// Application return pointer to descriptor
169376
// Descriptor contents must exist long enough for transfer to complete
@@ -174,31 +381,15 @@ uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
174381
// Although we are highspeed, host may be fullspeed.
175382
return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_hs_configuration : desc_fs_configuration;
176383
#else
177-
return desc_fs_configuration;
384+
// return desc_fs_configuration;
385+
return (uint8_t const*) &config_desc;
178386
#endif
179387
}
180388

181389
//--------------------------------------------------------------------+
182390
// String Descriptors
183391
//--------------------------------------------------------------------+
184392

185-
// String Descriptor Index
186-
enum {
187-
STRID_LANGID = 0,
188-
STRID_MANUFACTURER,
189-
STRID_PRODUCT,
190-
STRID_SERIAL,
191-
};
192-
193-
// array of pointer to string descriptors
194-
char const* string_desc_arr[] = {
195-
(const char[]) {0x09, 0x04}, // 0: is supported language is English (0x0409)
196-
"TinyUSB", // 1: Manufacturer
197-
"TinyUSB Device", // 2: Product
198-
NULL, // 3: Serials will use unique ID if possible
199-
"TinyUSB UVC", // 4: UVC Interface
200-
};
201-
202393
static uint16_t _desc_str[32 + 1];
203394

204395
// Invoked when received GET STRING DESCRIPTOR request

examples/device/video_capture/src/usb_descriptors.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ enum {
210210
/* Video stream frame format */ \
211211
TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(/*bFrameIndex */1, 0, _width, _height, \
212212
_width * _height * 16, _width * _height * 16 * _fps, \
213-
_width * _height * 16, \
213+
_width * _height * 16 / 8, \
214214
(10000000/_fps), (10000000/_fps), (10000000/_fps)*_fps, (10000000/_fps)), \
215215
TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(VIDEO_COLOR_PRIMARIES_BT709, VIDEO_COLOR_XFER_CH_BT709, VIDEO_COLOR_COEF_SMPTE170M), \
216216
TUD_VIDEO_DESC_EP_BULK(_epin, _epsize, 1)
@@ -223,7 +223,7 @@ enum {
223223
TUD_VIDEO_DESC_CS_VC(0x0150, TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \
224224
/* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \
225225
TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \
226-
TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \
226+
TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, UVC_ENTITY_CAP_INPUT_TERMINAL, 0), \
227227
/* Video stream alt. 0 */ \
228228
TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 1, _stridx), \
229229
/* Video stream header for without still image capture */ \

0 commit comments

Comments
 (0)