Skip to content

Commit 891f766

Browse files
committed
feat(esp32_usb_stream): update usb stream lib
1 parent 1f4970d commit 891f766

24 files changed

+5740
-264
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# ChangeLog
22

3+
## v0.1.0 - [2024-7-18]
4+
5+
### Enhancements:
6+
7+
* Supports compilation with ESP-IDF release/v5.1.
8+
* Synchronize code to uvc_steam version 1.4.0.
9+
310
## v0.0.1 - [2023-11-10]
411

512
### Enhancements:

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
idf_component_register(SRC_DIRS "src/original" "src"
2+
INCLUDE_DIRS "src" "src/original"
3+
REQUIRES usb esp_ringbuf)
4+
5+
include(package_manager)
6+
cu_pkg_define_version(${CMAKE_CURRENT_LIST_DIR})

idf_component.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
version: "1.4.0"
2+
targets:
3+
- esp32s2
4+
- esp32s3
5+
description: USB Host streaming driver, support UVC(video) + UAC(audio)
6+
url: https://github.com/espressif/esp-iot-solution/tree/master/components/usb/usb_stream
7+
repository: https://github.com/espressif/esp-iot-solution.git
8+
documentation: https://docs.espressif.com/projects/esp-iot-solution/en/latest/usb/usb_host/usb_stream.html
9+
issues: https://github.com/espressif/esp-iot-solution/issues
10+
dependencies:
11+
idf: ">=4.4.1"
12+
cmake_utilities: "0.5.*"
13+
examples:
14+
- path: ../../../examples/usb/host/usb_camera_mic_spk
15+
- path: ../../../examples/usb/host/usb_camera_lcd_display

library.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name=ESP32_USB_STREAM
2-
version=0.0.1
2+
version=1.4.0
33
author=espressif
4-
maintainer=alibukharai
4+
maintainer=lijunru
55
sentence=ESP32_USB_STREAM is a specialized library created to facilitate the implementation of USB stream functionality on ESP SoCs.
66
paragraph=This means that it provides a convenient and efficient way to transmit audio and video data through USB connections, making it an invaluable tool for a wide range of applications such as audio and video streaming, data transfer, and more. Currently, it is only competible with ESP32-S2 and ESP32-S3.
77
category=Other

src/USB_STREAM.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ USB_STREAM::~USB_STREAM()
3838
{}
3939

4040
// Method to register a user-defined callback function
41-
void USB_STREAM::uvcCamRegisterCb(uvc_frame_callback_t *newFunction, void *cb_arg)
41+
void USB_STREAM::uvcCamRegisterCb(uvc_frame_callback_t newFunction, void *cb_arg)
4242
{
4343
if (newFunction == NULL) {
4444
ESP_LOGE(TAG, "registerCallBack function error\n");
@@ -59,7 +59,7 @@ static void _camera_frame_cb(uvc_frame_t *frame, void *ptr)
5959
}
6060

6161
// Method to register a user-defined callback function
62-
void USB_STREAM::uacMicRegisterCb(mic_callback_t *newFunction, void *cb_arg)
62+
void USB_STREAM::uacMicRegisterCb(mic_callback_t newFunction, void *cb_arg)
6363
{
6464
if (newFunction == NULL) {
6565
ESP_LOGE(TAG, "registerCallBack function error\n");

src/USB_STREAM.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ class USB_STREAM {
2121
//Public member variables for storing user-defined callback function and arguments
2222
void *_user_mic_frame_cb_arg = NULL;
2323
void *_user_frame_cb_arg = NULL;
24-
uvc_frame_callback_t *_user_frame_cb = NULL;
25-
mic_callback_t *_user_mic_frame_cb = NULL;
24+
uvc_frame_callback_t _user_frame_cb = NULL;
25+
mic_callback_t _user_mic_frame_cb = NULL;
2626
typedef void (*StateChangeCallback)(usb_stream_state_t event, void *arg);
2727

2828
/**
@@ -67,7 +67,7 @@ class USB_STREAM {
6767
* @param newFunction Callback function
6868
* @param cb_arg callback args
6969
*/
70-
void uvcCamRegisterCb(uvc_frame_callback_t *newFunction, void *cb_arg);
70+
void uvcCamRegisterCb(uvc_frame_callback_t newFunction, void *cb_arg);
7171

7272
/**
7373
* @brief Configuration for an object
@@ -185,7 +185,7 @@ class USB_STREAM {
185185
* @param newFunction Callback function
186186
* @param cb_arg callback args
187187
*/
188-
void uacMicRegisterCb(mic_callback_t *newFunction, void *cb_arg);
188+
void uacMicRegisterCb(mic_callback_t newFunction, void *cb_arg);
189189

190190
/**
191191
* @brief Read data from internal mic buffer, the actual size will be returned

src/original/descriptor.c

Lines changed: 207 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -10,11 +10,11 @@
1010
#include <inttypes.h>
1111

1212
#include "esp_log.h"
13+
#include "include/libuvc_def.h"
1314
#include "usb/usb_host.h"
1415
#include "usb/usb_types_ch9.h"
1516
#include "usb_stream_descriptor.h"
1617

17-
// esp32/tools/esp32-arduino-libs/idf-release_v5.1-6b1f40b9bf/esp32s3/include/usb/include/usb/
1818
void print_device_descriptor(const uint8_t *buff)
1919
{
2020
if (buff == NULL) {
@@ -91,12 +91,106 @@ void print_uvc_header_desc(const uint8_t *buff, uint8_t sub_class)
9191
#endif
9292
}
9393

94-
void parse_vs_format_mjpeg_desc(const uint8_t *buff, uint8_t *format_idx, uint8_t *frame_num)
94+
struct format_table_entry {
95+
enum uvc_frame_format format;
96+
uint8_t abstract_fmt;
97+
uint8_t guid[16];
98+
int children_count;
99+
enum uvc_frame_format *children;
100+
};
101+
102+
struct format_table_entry *_get_format_entry(enum uvc_frame_format format)
103+
{
104+
#define ABS_FMT(_fmt, _num, ...) \
105+
case _fmt: { \
106+
static enum uvc_frame_format _fmt##_children[] = __VA_ARGS__; \
107+
static struct format_table_entry _fmt##_entry = { \
108+
_fmt, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, _num, _fmt##_children }; \
109+
return &_fmt##_entry; }
110+
111+
#define FMT(_fmt, ...) \
112+
case _fmt: { \
113+
static struct format_table_entry _fmt##_entry = { \
114+
_fmt, 0, __VA_ARGS__, 0, NULL }; \
115+
return &_fmt##_entry; }
116+
117+
switch (format) {
118+
/* Define new formats here */
119+
ABS_FMT(UVC_FRAME_FORMAT_ANY, 2,
120+
{UVC_FRAME_FORMAT_UNCOMPRESSED, UVC_FRAME_FORMAT_COMPRESSED})
121+
122+
ABS_FMT(UVC_FRAME_FORMAT_UNCOMPRESSED, 8, {
123+
UVC_FRAME_FORMAT_YUYV, UVC_FRAME_FORMAT_UYVY, UVC_FRAME_FORMAT_GRAY8,
124+
UVC_FRAME_FORMAT_GRAY16, UVC_FRAME_FORMAT_NV12, UVC_FRAME_FORMAT_P010,
125+
UVC_FRAME_FORMAT_BGR, UVC_FRAME_FORMAT_RGB
126+
})
127+
FMT(UVC_FRAME_FORMAT_YUYV,
128+
{'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
129+
FMT(UVC_FRAME_FORMAT_UYVY,
130+
{'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
131+
FMT(UVC_FRAME_FORMAT_GRAY8,
132+
{'Y', '8', '0', '0', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
133+
FMT(UVC_FRAME_FORMAT_GRAY16,
134+
{'Y', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
135+
FMT(UVC_FRAME_FORMAT_NV12,
136+
{'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
137+
FMT(UVC_FRAME_FORMAT_P010,
138+
{'P', '0', '1', '0', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
139+
FMT(UVC_FRAME_FORMAT_BGR,
140+
{0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70})
141+
FMT(UVC_FRAME_FORMAT_RGB,
142+
{0x7e, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70})
143+
FMT(UVC_FRAME_FORMAT_BY8,
144+
{'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
145+
FMT(UVC_FRAME_FORMAT_BA81,
146+
{'B', 'A', '8', '1', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
147+
FMT(UVC_FRAME_FORMAT_SGRBG8,
148+
{'G', 'R', 'B', 'G', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
149+
FMT(UVC_FRAME_FORMAT_SGBRG8,
150+
{'G', 'B', 'R', 'G', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
151+
FMT(UVC_FRAME_FORMAT_SRGGB8,
152+
{'R', 'G', 'G', 'B', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
153+
FMT(UVC_FRAME_FORMAT_SBGGR8,
154+
{'B', 'G', 'G', 'R', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
155+
ABS_FMT(UVC_FRAME_FORMAT_COMPRESSED, 2,
156+
{UVC_FRAME_FORMAT_MJPEG, UVC_FRAME_FORMAT_H264})
157+
FMT(UVC_FRAME_FORMAT_MJPEG,
158+
{'M', 'J', 'P', 'G'})
159+
FMT(UVC_FRAME_FORMAT_H264,
160+
{'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71})
161+
162+
default:
163+
return NULL;
164+
}
165+
166+
#undef ABS_FMT
167+
#undef FMT
168+
}
169+
170+
static enum uvc_frame_format uvc_frame_format_for_guid(const uint8_t guid[16])
171+
{
172+
struct format_table_entry *format;
173+
enum uvc_frame_format fmt;
174+
175+
for (fmt = 0; fmt < UVC_FRAME_FORMAT_COUNT; ++fmt) {
176+
format = _get_format_entry(fmt);
177+
if (!format || format->abstract_fmt) {
178+
continue;
179+
}
180+
if (!memcmp(format->guid, guid, 16)) {
181+
return format->format;
182+
}
183+
}
184+
185+
return UVC_FRAME_FORMAT_UNKNOWN;
186+
}
187+
188+
void parse_vs_format_mjpeg_desc(const uint8_t *buff, uint8_t *format_idx, uint8_t *frame_num, enum uvc_frame_format *fmt)
95189
{
96190
if (buff == NULL) {
97191
return;
98192
}
99-
const vs_format_desc_t *desc = (const vs_format_desc_t *) buff;
193+
const vs_format_mjpeg_desc_t *desc = (const vs_format_mjpeg_desc_t *) buff;
100194
#ifdef CONFIG_UVC_PRINT_DESC
101195
printf("\t*** VS Format MJPEG Descriptor ***\n");
102196
#ifdef CONFIG_UVC_PRINT_DESC_VERBOSE
@@ -123,14 +217,17 @@ void parse_vs_format_mjpeg_desc(const uint8_t *buff, uint8_t *format_idx, uint8_
123217
if (frame_num) {
124218
*frame_num = desc->bNumFrameDescriptors;
125219
}
220+
if (fmt) {
221+
*fmt = UVC_FRAME_FORMAT_MJPEG;
222+
}
126223
}
127224

128-
void parse_vs_frame_mjpeg_desc(const uint8_t *buff, uint8_t *frame_idx, uint16_t *width, uint16_t *heigh, uint8_t *interval_type, const uint32_t **pp_interval, uint32_t *dflt_interval)
225+
void parse_vs_frame_mjpeg_desc(const uint8_t *buff, uint8_t *frame_idx, uint16_t *width, uint16_t *height, uint8_t *interval_type, const uint32_t **pp_interval, uint32_t *dflt_interval)
129226
{
130227
if (buff == NULL) {
131228
return;
132229
}
133-
const vs_frame_desc_t *desc = (const vs_frame_desc_t *) buff;
230+
const vs_frame_mjpeg_desc_t *desc = (const vs_frame_mjpeg_desc_t *) buff;
134231
#ifdef CONFIG_UVC_PRINT_DESC
135232
printf("\t*** VS MJPEG Frame Descriptor ***\n");
136233
#ifdef CONFIG_UVC_PRINT_DESC_VERBOSE
@@ -160,6 +257,104 @@ void parse_vs_frame_mjpeg_desc(const uint8_t *buff, uint8_t *frame_idx, uint16_t
160257
} else {
161258
// Discrete Frame Intervals
162259
size_t num_of_intervals = (desc->bLength - 26) / 4;
260+
assert(num_of_intervals == desc->bFrameIntervalType); // num_of_intervals should same as bFrameIntervalType
261+
uint32_t *interval = (uint32_t *)&desc->dwFrameInterval;
262+
for (int i = 0; i < num_of_intervals; ++i) {
263+
printf("\tFrameInterval[%d] %"PRIu32"\n", i, interval[i]);
264+
}
265+
}
266+
#endif
267+
if (width) {
268+
*width = desc->wWidth;
269+
}
270+
if (height) {
271+
*height = desc->wHeigh;
272+
}
273+
if (frame_idx) {
274+
*frame_idx = desc->bFrameIndex;
275+
}
276+
if (interval_type) {
277+
*interval_type = desc->bFrameIntervalType;
278+
}
279+
if (pp_interval) {
280+
*pp_interval = &(desc->dwFrameInterval);
281+
}
282+
if (dflt_interval) {
283+
*dflt_interval = desc->dwDefaultFrameInterval;
284+
}
285+
}
286+
287+
void parse_vs_format_frame_based_desc(const uint8_t *buff, uint8_t *format_idx, uint8_t *frame_num, enum uvc_frame_format *fmt)
288+
{
289+
if (buff == NULL) {
290+
return;
291+
}
292+
const vs_format_frame_based_desc_t *desc = (const vs_format_frame_based_desc_t *) buff;
293+
#ifdef CONFIG_UVC_PRINT_DESC
294+
printf("\t*** VS Format Frame-Based Descriptor ***\n");
295+
#ifdef CONFIG_UVC_PRINT_DESC_VERBOSE
296+
printf("\tbLength 0x%x\n", desc->bLength);
297+
printf("\tbDescriptorType 0x%x\n", desc->bDescriptorType);
298+
printf("\tbDescriptorSubType 0x%x\n", desc->bDescriptorSubType);
299+
#endif
300+
printf("\tbFormatIndex 0x%x\n", desc->bFormatIndex);
301+
printf("\tbNumFrameDescriptors %u\n", desc->bNumFrameDescriptors);
302+
printf("\tguidFormat %.*s\n", 16, desc->guidFormat);
303+
printf("\tbDefaultFrameIndex %u\n", desc->bDefaultFrameIndex);
304+
#ifdef CONFIG_UVC_PRINT_DESC_VERBOSE
305+
printf("\tbAspectRatioX %u\n", desc->bAspectRatioX);
306+
printf("\tbAspectRatioY %u\n", desc->bAspectRatioY);
307+
printf("\tbmInterlaceFlags 0x%x\n", desc->bmInterlaceFlags);
308+
printf("\tbCopyProtect %u\n", desc->bCopyProtect);
309+
#endif
310+
#endif
311+
if (format_idx) {
312+
*format_idx = desc->bFormatIndex;
313+
}
314+
if (frame_num) {
315+
*frame_num = desc->bNumFrameDescriptors;
316+
}
317+
if (fmt) {
318+
*fmt = uvc_frame_format_for_guid(desc->guidFormat);
319+
}
320+
}
321+
322+
void parse_vs_frame_frame_based_desc(const uint8_t *buff, uint8_t *frame_idx, uint16_t *width, uint16_t *height, uint8_t *interval_type, const uint32_t **pp_interval, uint32_t *dflt_interval)
323+
{
324+
if (buff == NULL) {
325+
return;
326+
}
327+
const vs_frame_frame_based_desc_t *desc = (const vs_frame_frame_based_desc_t *) buff;
328+
#ifdef CONFIG_UVC_PRINT_DESC
329+
printf("\t*** VS Frame-Based Frame Descriptor ***\n");
330+
#ifdef CONFIG_UVC_PRINT_DESC_VERBOSE
331+
printf("\tbLength 0x%x\n", desc->bLength);
332+
printf("\tbDescriptorType 0x%x\n", desc->bDescriptorType);
333+
printf("\tbDescriptorSubType 0x%x\n", desc->bDescriptorSubType);
334+
#endif
335+
printf("\tbFrameIndex 0x%x\n", desc->bFrameIndex);
336+
#ifdef CONFIG_UVC_PRINT_DESC_VERBOSE
337+
printf("\tbmCapabilities 0x%x\n", desc->bmCapabilities);
338+
#endif
339+
printf("\twWidth %u\n", desc->wWidth);
340+
printf("\twHeigh %u\n", desc->wHeigh);
341+
#ifdef CONFIG_UVC_PRINT_DESC_VERBOSE
342+
printf("\tdwMinBitRate %"PRIu32"\n", desc->dwMinBitRate);
343+
printf("\tdwMaxBitRate %"PRIu32"\n", desc->dwMaxBitRate);
344+
printf("\tdwDefaultFrameInterval %"PRIu32"\n", desc->dwDefaultFrameInterval);
345+
printf("\tbFrameIntervalType %u\n", desc->bFrameIntervalType);
346+
printf("\tdwBytesPerLine %"PRIu32"\n", desc->dwBytesPerLine);
347+
#endif
348+
349+
if (desc->bFrameIntervalType == 0) {
350+
// Continuous Frame Intervals
351+
printf("\tdwMinFrameInterval %"PRIu32"\n", desc->dwMinFrameInterval);
352+
printf("\tdwMaxFrameInterval %"PRIu32"\n", desc->dwMaxFrameInterval);
353+
printf("\tdwFrameIntervalStep %"PRIu32"\n", desc->dwFrameIntervalStep);
354+
} else {
355+
// Discrete Frame Intervals
356+
size_t num_of_intervals = (desc->bLength - 26) / 4;
357+
assert(num_of_intervals == desc->bFrameIntervalType); // num_of_intervals should same as bFrameIntervalType
163358
uint32_t *interval = (uint32_t *)&desc->dwFrameInterval;
164359
for (int i = 0; i < num_of_intervals; ++i) {
165360
printf("\tFrameInterval[%d] %"PRIu32"\n", i, interval[i]);
@@ -169,8 +364,8 @@ void parse_vs_frame_mjpeg_desc(const uint8_t *buff, uint8_t *frame_idx, uint16_t
169364
if (width) {
170365
*width = desc->wWidth;
171366
}
172-
if (heigh) {
173-
*heigh = desc->wHeigh;
367+
if (height) {
368+
*height = desc->wHeigh;
174369
}
175370
if (frame_idx) {
176371
*frame_idx = desc->bFrameIndex;
@@ -260,8 +455,8 @@ void print_intf_desc(const uint8_t *buff)
260455
printf("\tbAlternateSetting %d\n", intf_desc->bAlternateSetting);
261456
printf("\tbNumEndpoints %d\n", intf_desc->bNumEndpoints);
262457
printf("\tbInterfaceClass 0x%x (%s)\n", intf_desc->bInterfaceClass,
263-
intf_desc->bInterfaceClass==USB_CLASS_VIDEO?"Video":
264-
(intf_desc->bInterfaceClass==USB_CLASS_AUDIO?"Audio":"Unknown"));
458+
intf_desc->bInterfaceClass == USB_CLASS_VIDEO ? "Video" :
459+
(intf_desc->bInterfaceClass == USB_CLASS_AUDIO ? "Audio" : "Unknown"));
265460
printf("\tbInterfaceSubClass 0x%x\n", intf_desc->bInterfaceSubClass);
266461
#ifdef CONFIG_UVC_PRINT_DESC_VERBOSE
267462
printf("\tbInterfaceProtocol 0x%x\n", intf_desc->bInterfaceProtocol);
@@ -429,7 +624,7 @@ void parse_ac_feature_desc(const uint8_t *buff, uint8_t *source_idx, uint8_t *fe
429624
printf("\tbUnitID %d\n", desc->bUnitID);
430625
printf("\tbSourceID %d\n", desc->bSourceID);
431626
printf("\tbControlSize %d\n", desc->bControlSize);
432-
for (size_t i = 0; i < (desc->bLength-7)/desc->bControlSize; i += desc->bControlSize) {
627+
for (size_t i = 0; i < (desc->bLength - 7) / desc->bControlSize; i += desc->bControlSize) {
433628
printf("\tbmaControls[ch%d] 0x%x\n", i, desc->bmaControls[i]);
434629
}
435630
#ifdef CONFIG_UVC_PRINT_DESC_VERBOSE
@@ -443,7 +638,7 @@ void parse_ac_feature_desc(const uint8_t *buff, uint8_t *source_idx, uint8_t *fe
443638
*source_idx = desc->bSourceID;
444639
}
445640
uint8_t ch_num = 0;
446-
for (size_t i = 0; i < (desc->bLength-7)/desc->bControlSize; i += desc->bControlSize) {
641+
for (size_t i = 0; i < (desc->bLength - 7) / desc->bControlSize; i += desc->bControlSize) {
447642
if ((desc->bmaControls[i] & AUDIO_FEATURE_CONTROL_VOLUME) && volume_ch) {
448643
*volume_ch = *volume_ch | (1 << ch_num);
449644
}

0 commit comments

Comments
 (0)