Skip to content

Commit fb97586

Browse files
committed
eanble video and video streaming, start adding usbd video class, update interface desc parsing to update IAD number
1 parent f36defb commit fb97586

File tree

7 files changed

+333
-5
lines changed

7 files changed

+333
-5
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2020 Jerzy Kasenbreg
5+
* Copyright (c) 2021 Koji KITAYAMA
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*
25+
*/
26+
27+
#ifndef _USB_DESCRIPTORS_H_
28+
#define _USB_DESCRIPTORS_H_
29+
30+
/* Time stamp base clock. It is a deprecated parameter. */
31+
#define UVC_CLOCK_FREQUENCY 27000000
32+
/* video capture path */
33+
#define UVC_ENTITY_CAP_INPUT_TERMINAL 0x01
34+
#define UVC_ENTITY_CAP_OUTPUT_TERMINAL 0x02
35+
36+
#define FRAME_WIDTH 128
37+
#define FRAME_HEIGHT 96
38+
#define FRAME_RATE 10
39+
40+
enum {
41+
ITF_NUM_VIDEO_CONTROL,
42+
ITF_NUM_VIDEO_STREAMING,
43+
ITF_NUM_TOTAL
44+
};
45+
46+
#define TUD_VIDEO_CAPTURE_DESC_UNCOMPR_LEN (\
47+
TUD_VIDEO_DESC_IAD_LEN\
48+
/* control */\
49+
+ TUD_VIDEO_DESC_STD_VC_LEN\
50+
+ (TUD_VIDEO_DESC_CS_VC_LEN + 1/*bInCollection*/)\
51+
+ TUD_VIDEO_DESC_CAMERA_TERM_LEN\
52+
+ TUD_VIDEO_DESC_OUTPUT_TERM_LEN\
53+
/* Interface 1, Alternate 0 */\
54+
+ TUD_VIDEO_DESC_STD_VS_LEN\
55+
+ (TUD_VIDEO_DESC_CS_VS_IN_LEN + 1/*bNumFormats x bControlSize*/)\
56+
+ TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN\
57+
+ TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN\
58+
+ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN\
59+
/* Interface 1, Alternate 1 */\
60+
+ TUD_VIDEO_DESC_STD_VS_LEN\
61+
+ 7/* Endpoint */\
62+
)
63+
64+
#define TUD_VIDEO_CAPTURE_DESC_MJPEG_LEN (\
65+
TUD_VIDEO_DESC_IAD_LEN\
66+
/* control */\
67+
+ TUD_VIDEO_DESC_STD_VC_LEN\
68+
+ (TUD_VIDEO_DESC_CS_VC_LEN + 1/*bInCollection*/)\
69+
+ TUD_VIDEO_DESC_CAMERA_TERM_LEN\
70+
+ TUD_VIDEO_DESC_OUTPUT_TERM_LEN\
71+
/* Interface 1, Alternate 0 */\
72+
+ TUD_VIDEO_DESC_STD_VS_LEN\
73+
+ (TUD_VIDEO_DESC_CS_VS_IN_LEN + 1/*bNumFormats x bControlSize*/)\
74+
+ TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN\
75+
+ TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN\
76+
+ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN\
77+
/* Interface 1, Alternate 1 */\
78+
+ TUD_VIDEO_DESC_STD_VS_LEN\
79+
+ 7/* Endpoint */\
80+
)
81+
82+
#define TUD_VIDEO_CAPTURE_DESC_UNCOMPR_BULK_LEN (\
83+
TUD_VIDEO_DESC_IAD_LEN\
84+
/* control */\
85+
+ TUD_VIDEO_DESC_STD_VC_LEN\
86+
+ (TUD_VIDEO_DESC_CS_VC_LEN + 1/*bInCollection*/)\
87+
+ TUD_VIDEO_DESC_CAMERA_TERM_LEN\
88+
+ TUD_VIDEO_DESC_OUTPUT_TERM_LEN\
89+
/* Interface 1, Alternate 0 */\
90+
+ TUD_VIDEO_DESC_STD_VS_LEN\
91+
+ (TUD_VIDEO_DESC_CS_VS_IN_LEN + 1/*bNumFormats x bControlSize*/)\
92+
+ TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN\
93+
+ TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN\
94+
+ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN\
95+
+ 7/* Endpoint */\
96+
)
97+
98+
#define TUD_VIDEO_CAPTURE_DESC_MJPEG_BULK_LEN (\
99+
TUD_VIDEO_DESC_IAD_LEN\
100+
/* control */\
101+
+ TUD_VIDEO_DESC_STD_VC_LEN\
102+
+ (TUD_VIDEO_DESC_CS_VC_LEN + 1/*bInCollection*/)\
103+
+ TUD_VIDEO_DESC_CAMERA_TERM_LEN\
104+
+ TUD_VIDEO_DESC_OUTPUT_TERM_LEN\
105+
/* Interface 1, Alternate 0 */\
106+
+ TUD_VIDEO_DESC_STD_VS_LEN\
107+
+ (TUD_VIDEO_DESC_CS_VS_IN_LEN + 1/*bNumFormats x bControlSize*/)\
108+
+ TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN\
109+
+ TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN\
110+
+ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN\
111+
+ 7/* Endpoint */\
112+
)
113+
114+
/* Windows support YUY2 and NV12
115+
* https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/usb-video-class-driver-overview */
116+
117+
#define TUD_VIDEO_DESC_CS_VS_FMT_YUY2(_fmtidx, _numfmtdesc, _frmidx, _asrx, _asry, _interlace, _cp) \
118+
TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfmtdesc, TUD_VIDEO_GUID_YUY2, 16, _frmidx, _asrx, _asry, _interlace, _cp)
119+
#define TUD_VIDEO_DESC_CS_VS_FMT_NV12(_fmtidx, _numfmtdesc, _frmidx, _asrx, _asry, _interlace, _cp) \
120+
TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfmtdesc, TUD_VIDEO_GUID_NV12, 12, _frmidx, _asrx, _asry, _interlace, _cp)
121+
#define TUD_VIDEO_DESC_CS_VS_FMT_M420(_fmtidx, _numfmtdesc, _frmidx, _asrx, _asry, _interlace, _cp) \
122+
TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfmtdesc, TUD_VIDEO_GUID_M420, 12, _frmidx, _asrx, _asry, _interlace, _cp)
123+
#define TUD_VIDEO_DESC_CS_VS_FMT_I420(_fmtidx, _numfmtdesc, _frmidx, _asrx, _asry, _interlace, _cp) \
124+
TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfmtdesc, TUD_VIDEO_GUID_I420, 12, _frmidx, _asrx, _asry, _interlace, _cp)
125+
126+
127+
#define TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR_BULK(_stridx, _epin, _width, _height, _fps, _epsize) \
128+
TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \
129+
/* Video control 0 */ \
130+
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), \
138+
TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \
139+
/* Video stream alt. 0 */ \
140+
TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 1, _stridx), \
141+
/* Video stream header for without still image capture */ \
142+
TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \
143+
/*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,\
147+
_epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \
148+
/*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \
149+
/*bmaControls(1)*/0), \
150+
/* Video stream format */ \
151+
TUD_VIDEO_DESC_CS_VS_FMT_YUY2(/*bFormatIndex*/1, /*bNumFrameDescriptors*/1, \
152+
/*bDefaultFrameIndex*/1, 0, 0, 0, /*bCopyProtect*/0), \
153+
/* Video stream frame format */ \
154+
TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT(/*bFrameIndex */1, 0, _width, _height, \
155+
_width * _height * 16, _width * _height * 16 * _fps, \
156+
_width * _height * 16, \
157+
(10000000/_fps), (10000000/_fps), (10000000/_fps)*_fps, (10000000/_fps)), \
158+
TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(VIDEO_COLOR_PRIMARIES_BT709, VIDEO_COLOR_XFER_CH_BT709, VIDEO_COLOR_COEF_SMPTE170M), \
159+
TUD_VIDEO_DESC_EP_BULK(_epin, _epsize, 1)
160+
161+
#endif
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*********************************************************************
2+
Adafruit invests time and resources providing this open source code,
3+
please support Adafruit and open-source hardware by purchasing
4+
products from Adafruit!
5+
6+
MIT license, check LICENSE for more information
7+
Copyright (c) 2019 Ha Thach for Adafruit Industries
8+
All text above, and the splash screen below must be included in
9+
any redistribution
10+
*********************************************************************/
11+
12+
#include "Adafruit_TinyUSB.h"
13+
#include "usb_descriptors.h"
14+
15+
#define FRAME_WIDTH 128
16+
#define FRAME_HEIGHT 96
17+
#define FRAME_RATE 10
18+
19+
uint8_t const desc_video[] = {
20+
TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR_BULK(4, 0x80, FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE, 64)
21+
};
22+
23+
Adafruit_USBD_Video usb_video(desc_video, sizeof(desc_video));
24+
25+
void setup() {
26+
Serial.begin(115200);
27+
usb_video.begin();
28+
}
29+
30+
void loop() {
31+
32+
}

src/Adafruit_TinyUSB.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@
6464
#include "arduino/webusb/Adafruit_USBD_WebUSB.h"
6565
#endif
6666

67+
#if CFG_TUD_VIDEO
68+
#include "arduino/video/Adafruit_USBD_Video.h"
69+
#endif
70+
6771
// Initialize device hardware, stack, also Serial as CDC
6872
// Wrapper for TinyUSBDevice.begin(rhport)
6973
void TinyUSB_Device_Init(uint8_t rhport);

src/arduino/Adafruit_USBD_Device.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -244,11 +244,21 @@ bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &itf) {
244244
}
245245

246246
// Parse interface descriptor to update
247-
// - Interface Number & string descriptor
248-
// - Endpoint address
247+
// - IAD: interface number
248+
// - Interface: number & string descriptor
249+
// - Endpoint: address
249250
while (desc < desc_end) {
250-
if (tu_desc_type(desc) == TUSB_DESC_INTERFACE) {
251+
switch (tu_desc_type(desc)) {
252+
case TUSB_DESC_INTERFACE_ASSOCIATION: {
253+
tusb_desc_interface_assoc_t *desc_iad =
254+
(tusb_desc_interface_assoc_t *)desc;
255+
desc_iad->bFirstInterface = _itf_count;
256+
break;
257+
}
258+
259+
case TUSB_DESC_INTERFACE: {
251260
tusb_desc_interface_t *desc_itf = (tusb_desc_interface_t *)desc;
261+
desc_itf->bInterfaceNumber = _itf_count;
252262
if (desc_itf->bAlternateSetting == 0) {
253263
_itf_count++;
254264
if (desc_str && (_desc_str_count < STRING_DESCRIPTOR_MAX)) {
@@ -258,12 +268,22 @@ bool Adafruit_USBD_Device::addInterface(Adafruit_USBD_Interface &itf) {
258268

259269
// only assign string index to first interface
260270
desc_str = NULL;
271+
} else {
272+
desc_itf->iInterface = 0;
261273
}
262274
}
263-
} else if (tu_desc_type(desc) == TUSB_DESC_ENDPOINT) {
275+
break;
276+
}
277+
278+
case TUSB_DESC_ENDPOINT: {
264279
tusb_desc_endpoint_t *desc_ep = (tusb_desc_endpoint_t *)desc;
265280
desc_ep->bEndpointAddress |=
266281
(desc_ep->bEndpointAddress & 0x80) ? _epin_count++ : _epout_count++;
282+
break;
283+
}
284+
285+
default:
286+
break;
267287
}
268288

269289
if (desc[0] == 0) {

src/arduino/ports/rp2040/tusb_config_rp2040.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,11 @@ extern "C" {
8686
#define CFG_TUD_HID 2
8787
#define CFG_TUD_MIDI 1
8888
#define CFG_TUD_VENDOR 1
89-
// #define CFG_TUD_VIDEO 1
89+
#define CFG_TUD_VIDEO 1 // number of video control interfaces
90+
#define CFG_TUD_VIDEO_STREAMING 1 // number of video streaming interfaces
91+
92+
// video streaming endpoint buffer size
93+
#define CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE 256
9094

9195
// CDC FIFO size of TX and RX
9296
#define CFG_TUD_CDC_RX_BUFSIZE 256
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2024 Ha Thach (tinyusb.org)
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*
24+
* This file is part of the TinyUSB stack.
25+
*/
26+
27+
#include "tusb_option.h"
28+
29+
#if CFG_TUD_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING
30+
31+
#include "Adafruit_USBD_Video.h"
32+
33+
Adafruit_USBD_Video::Adafruit_USBD_Video(uint8_t const *desc_itf,
34+
size_t desc_len) {
35+
_desc_itf = desc_itf;
36+
_desc_len = desc_len;
37+
}
38+
39+
bool Adafruit_USBD_Video::begin() {
40+
if (!TinyUSBDevice.addInterface(*this)) {
41+
return false;
42+
}
43+
44+
return true;
45+
}
46+
47+
uint16_t Adafruit_USBD_Video::getInterfaceDescriptor(uint8_t itfnum,
48+
uint8_t *buf,
49+
uint16_t bufsize) {
50+
(void)itfnum;
51+
52+
if (!buf || bufsize < _desc_len) {
53+
return false;
54+
}
55+
56+
memcpy(buf, _desc_itf, _desc_len);
57+
return _desc_len;
58+
}
59+
60+
#endif
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2024 Ha Thach (tinyusb.org)
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*
24+
* This file is part of the TinyUSB stack.
25+
*/
26+
27+
#ifndef ADAFRUIT_USBD_VIDEO_H
28+
#define ADAFRUIT_USBD_VIDEO_H
29+
30+
#include "arduino/Adafruit_USBD_Device.h"
31+
32+
class Adafruit_USBD_Video : public Adafruit_USBD_Interface {
33+
public:
34+
Adafruit_USBD_Video(uint8_t const *desc_itf, size_t desc_len);
35+
36+
bool begin();
37+
38+
// from Adafruit_USBD_Interface
39+
virtual uint16_t getInterfaceDescriptor(uint8_t itfnum, uint8_t *buf,
40+
uint16_t bufsize);
41+
42+
private:
43+
uint8_t const *_desc_itf;
44+
size_t _desc_len;
45+
};
46+
47+
#endif

0 commit comments

Comments
 (0)