Skip to content

Commit 9db1fdf

Browse files
committed
adjust streaming interface number in VC Header, and endpoint address in VS input/output header
1 parent fb97586 commit 9db1fdf

File tree

3 files changed

+128
-15
lines changed

3 files changed

+128
-15
lines changed

examples/Video/video_capture/usb_descriptors.h

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@
3333
#define UVC_ENTITY_CAP_INPUT_TERMINAL 0x01
3434
#define UVC_ENTITY_CAP_OUTPUT_TERMINAL 0x02
3535

36-
#define FRAME_WIDTH 128
37-
#define FRAME_HEIGHT 96
38-
#define FRAME_RATE 10
39-
4036
enum {
4137
ITF_NUM_VIDEO_CONTROL,
4238
ITF_NUM_VIDEO_STREAMING,
@@ -128,22 +124,17 @@ enum {
128124
TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \
129125
/* Video control 0 */ \
130126
TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \
131-
TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \
132-
/* wTotalLength - bLength */ \
133-
TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \
134-
UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \
135-
TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\
136-
/*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\
137-
/*wObjectiveFocalLength*/0, /*bmControls*/0), \
127+
/* Header: UVC 1.5, wTotalLength - bLength */ \
128+
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), \
129+
/* Camera Terminal: ID, bAssocTerminal, iTerminal, focal min, max, length, bmControl */ \
130+
TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0, 0, 0, 0, 0), \
138131
TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \
139132
/* Video stream alt. 0 */ \
140133
TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 1, _stridx), \
141134
/* Video stream header for without still image capture */ \
142135
TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \
143136
/*wTotalLength - bLength */\
144-
TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN\
145-
+ TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN\
146-
+ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\
137+
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,\
147138
_epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \
148139
/*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \
149140
/*bmaControls(1)*/0), \

examples/Video/video_capture/video_capture.ino

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,114 @@
1212
#include "Adafruit_TinyUSB.h"
1313
#include "usb_descriptors.h"
1414

15+
//--------------------------------------------------------------------+
16+
//
17+
//--------------------------------------------------------------------+
1518
#define FRAME_WIDTH 128
1619
#define FRAME_HEIGHT 96
1720
#define FRAME_RATE 10
1821

1922
uint8_t const desc_video[] = {
20-
TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR_BULK(4, 0x80, FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, 64)
23+
TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR_BULK(0, 0x80, FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, 64)
2124
};
2225

2326
Adafruit_USBD_Video usb_video(desc_video, sizeof(desc_video));
2427

28+
// YUY2 frame buffer
29+
static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 16 / 8];
30+
31+
static unsigned frame_num = 0;
32+
static unsigned tx_busy = 0;
33+
static unsigned interval_ms = 1000 / FRAME_RATE;
34+
static unsigned start_ms = 0;
35+
static unsigned already_sent = 0;
36+
37+
//--------------------------------------------------------------------+
38+
//
39+
//--------------------------------------------------------------------+
40+
static void fill_color_bar(uint8_t* buffer, unsigned start_position);
41+
2542
void setup() {
2643
Serial.begin(115200);
44+
// Serial.end();
2745
usb_video.begin();
2846
}
2947

3048
void loop() {
49+
if (!tud_video_n_streaming(0, 0)) {
50+
already_sent = 0;
51+
frame_num = 0;
52+
return;
53+
}
54+
55+
if (!already_sent) {
56+
already_sent = 1;
57+
start_ms = millis();
58+
fill_color_bar(frame_buffer, frame_num);
59+
tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8);
60+
}
61+
62+
unsigned cur = millis();
63+
if (cur - start_ms < interval_ms) return; // not enough time
64+
if (tx_busy) return;
65+
start_ms += interval_ms;
66+
67+
fill_color_bar(frame_buffer, frame_num);
68+
tud_video_n_frame_xfer(0, 0, (void*) frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16 / 8);
69+
}
70+
71+
void tud_video_frame_xfer_complete_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx) {
72+
(void) ctl_idx;
73+
(void) stm_idx;
74+
tx_busy = 0;
75+
/* flip buffer */
76+
++frame_num;
77+
}
78+
79+
int tud_video_commit_cb(uint_fast8_t ctl_idx, uint_fast8_t stm_idx,
80+
video_probe_and_commit_control_t const* parameters) {
81+
(void) ctl_idx;
82+
(void) stm_idx;
83+
/* convert unit to ms from 100 ns */
84+
interval_ms = parameters->dwFrameInterval / 10000;
85+
return VIDEO_ERROR_NONE;
86+
}
87+
88+
//------------- Helper -------------//
89+
static void fill_color_bar(uint8_t* buffer, unsigned start_position) {
90+
/* EBU color bars
91+
* See also https://stackoverflow.com/questions/6939422 */
92+
static uint8_t const bar_color[8][4] = {
93+
/* Y, U, Y, V */
94+
{ 235, 128, 235, 128}, /* 100% White */
95+
{ 219, 16, 219, 138}, /* Yellow */
96+
{ 188, 154, 188, 16}, /* Cyan */
97+
{ 173, 42, 173, 26}, /* Green */
98+
{ 78, 214, 78, 230}, /* Magenta */
99+
{ 63, 102, 63, 240}, /* Red */
100+
{ 32, 240, 32, 118}, /* Blue */
101+
{ 16, 128, 16, 128}, /* Black */
102+
};
103+
uint8_t* p;
104+
105+
/* Generate the 1st line */
106+
uint8_t* end = &buffer[FRAME_WIDTH * 2];
107+
unsigned idx = (FRAME_WIDTH / 2 - 1) - (start_position % (FRAME_WIDTH / 2));
108+
p = &buffer[idx * 4];
109+
for (unsigned i = 0; i < 8; ++i) {
110+
for (int j = 0; j < FRAME_WIDTH / (2 * 8); ++j) {
111+
memcpy(p, &bar_color[i], 4);
112+
p += 4;
113+
if (end <= p) {
114+
p = buffer;
115+
}
116+
}
117+
}
31118

119+
/* Duplicate the 1st line to the others */
120+
p = &buffer[FRAME_WIDTH * 2];
121+
for (unsigned i = 1; i < FRAME_HEIGHT; ++i) {
122+
memcpy(p, buffer, FRAME_WIDTH * 2);
123+
p += FRAME_WIDTH * 2;
124+
}
32125
}

src/arduino/Adafruit_USBD_Device.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,34 @@ bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &itf) {
259259
case TUSB_DESC_INTERFACE: {
260260
tusb_desc_interface_t *desc_itf = (tusb_desc_interface_t *)desc;
261261
desc_itf->bInterfaceNumber = _itf_count;
262+
263+
#if CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING
264+
if (TUSB_CLASS_VIDEO == desc_itf->bInterfaceClass) {
265+
desc += tu_desc_len(desc); // next to CS Interface
266+
267+
if (TUSB_DESC_CS_INTERFACE == tu_desc_type(desc)) {
268+
uint8_t const subtype = desc[2];
269+
270+
if (VIDEO_SUBCLASS_CONTROL == desc_itf->bInterfaceSubClass) {
271+
// Adjust stream interface number in VC Header
272+
if (subtype == VIDEO_CS_ITF_VC_HEADER) {
273+
uint8_t const vs_count = desc[11];
274+
for (uint8_t i = 0; i < vs_count; i++) {
275+
desc[12 + i] += _itf_count;
276+
}
277+
}
278+
} else if (VIDEO_SUBCLASS_STREAMING == desc_itf->bInterfaceSubClass) {
279+
// Adjust the endpoint address in CS VS Input/Output Header
280+
if (subtype == VIDEO_CS_ITF_VS_INPUT_HEADER) {
281+
desc[6] = 0x80 | _epin_count;
282+
} else if (subtype == VIDEO_CS_ITF_VS_OUTPUT_HEADER) {
283+
desc[6] = _epout_count;
284+
}
285+
}
286+
}
287+
}
288+
#endif
289+
262290
if (desc_itf->bAlternateSetting == 0) {
263291
_itf_count++;
264292
if (desc_str && (_desc_str_count < STRING_DESCRIPTOR_MAX)) {
@@ -272,6 +300,7 @@ bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &itf) {
272300
desc_itf->iInterface = 0;
273301
}
274302
}
303+
275304
break;
276305
}
277306

0 commit comments

Comments
 (0)