Skip to content

Commit e79325a

Browse files
authored
Merge pull request #1668 from kkitayam/add_support_for_mjpeg
Add support for MJPEG on UVC
2 parents 2cd4e27 + 53dc9d5 commit e79325a

File tree

8 files changed

+617
-51
lines changed

8 files changed

+617
-51
lines changed

examples/device/video_capture/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ family_initialize_project(${PROJECT} ${CMAKE_CURRENT_LIST_DIR})
1212

1313
add_executable(${PROJECT})
1414

15+
if (FORCE_READONLY)
16+
target_compile_definitions(${PROJECT} PRIVATE
17+
CFG_EXAMPLE_VIDEO_READONLY
18+
)
19+
endif()
20+
1521
# Example source
1622
target_sources(${PROJECT} PUBLIC
1723
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c

examples/device/video_capture/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
include ../../../tools/top.mk
22
include ../../make.mk
33

4+
ifeq ($(DISABLE_MJPEG),1)
5+
CFLAGS += -DCFG_EXAMPLE_VIDEO_DISABLE_MJPEG
6+
endif
7+
ifeq ($(FORCE_READONLY),1)
8+
CFLAGS += -DCFG_EXAMPLE_VIDEO_READONLY
9+
endif
10+
411
INC += \
512
src \
613
$(TOP)/hw \

examples/device/video_capture/src/images.h

Lines changed: 285 additions & 0 deletions
Large diffs are not rendered by default.

examples/device/video_capture/src/main.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,23 @@ static unsigned interval_ms = 1000 / FRAME_RATE;
112112
/* YUY2 frame buffer */
113113
#ifdef CFG_EXAMPLE_VIDEO_READONLY
114114
#include "images.h"
115+
116+
# if !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPG)
117+
static struct {
118+
uint32_t size;
119+
uint8_t const *buffer;
120+
} const frames[] = {
121+
{color_bar_0_jpg_len, color_bar_0_jpg},
122+
{color_bar_1_jpg_len, color_bar_1_jpg},
123+
{color_bar_2_jpg_len, color_bar_2_jpg},
124+
{color_bar_3_jpg_len, color_bar_3_jpg},
125+
{color_bar_4_jpg_len, color_bar_4_jpg},
126+
{color_bar_5_jpg_len, color_bar_5_jpg},
127+
{color_bar_6_jpg_len, color_bar_6_jpg},
128+
{color_bar_7_jpg_len, color_bar_7_jpg},
129+
};
130+
# endif
131+
115132
#else
116133
static uint8_t frame_buffer[FRAME_WIDTH * FRAME_HEIGHT * 16 / 8];
117134
static void fill_color_bar(uint8_t *buffer, unsigned start_position)
@@ -168,8 +185,12 @@ void video_task(void)
168185
already_sent = 1;
169186
start_ms = board_millis();
170187
#ifdef CFG_EXAMPLE_VIDEO_READONLY
171-
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t) &frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
188+
# if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPG)
189+
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
172190
FRAME_WIDTH * FRAME_HEIGHT * 16/8);
191+
# else
192+
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)frames[frame_num % 8].buffer, frames[frame_num % 8].size);
193+
# endif
173194
#else
174195
fill_color_bar(frame_buffer, frame_num);
175196
tud_video_n_frame_xfer(0, 0, (void*)frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16/8);
@@ -182,8 +203,12 @@ void video_task(void)
182203
start_ms += interval_ms;
183204

184205
#ifdef CFG_EXAMPLE_VIDEO_READONLY
185-
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t) &frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
206+
# if defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPG)
207+
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)&frame_buffer[(frame_num % (FRAME_WIDTH / 2)) * 4],
186208
FRAME_WIDTH * FRAME_HEIGHT * 16/8);
209+
# else
210+
tud_video_n_frame_xfer(0, 0, (void*)(uintptr_t)frames[frame_num % 8].buffer, frames[frame_num % 8].size);
211+
# endif
187212
#else
188213
fill_color_bar(frame_buffer, frame_num);
189214
tud_video_n_frame_xfer(0, 0, (void*)frame_buffer, FRAME_WIDTH * FRAME_HEIGHT * 16/8);

examples/device/video_capture/src/usb_descriptors.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@ uint8_t const * tud_descriptor_device_cb(void)
7575
// Configuration Descriptor
7676
//--------------------------------------------------------------------+
7777

78-
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_VIDEO_CAPTURE_DESC_LEN)
78+
#if defined(CFG_EXAMPLE_VIDEO_READONLY) && !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
79+
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_VIDEO_CAPTURE_DESC_MJPEG_LEN)
80+
#else
81+
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_VIDEO_CAPTURE_DESC_UNCOMPR_LEN)
82+
#endif
7983

8084
#if TU_CHECK_MCU(OPT_MCU_LPC175X_6X, OPT_MCU_LPC177X_8X, OPT_MCU_LPC40XX)
8185
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
@@ -96,9 +100,15 @@ uint8_t const desc_fs_configuration[] =
96100
// Config number, interface count, string index, total length, attribute, power in mA
97101
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 500),
98102
// IAD for Video Control
99-
TUD_VIDEO_CAPTURE_DESCRIPTOR(4, EPNUM_VIDEO_IN,
100-
FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE,
101-
CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE)
103+
#if defined(CFG_EXAMPLE_VIDEO_READONLY) && !defined(CFG_EXAMPLE_VIDEO_DISABLE_MJPEG)
104+
TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG(4, EPNUM_VIDEO_IN,
105+
FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE,
106+
CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE)
107+
#else
108+
TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR(4, EPNUM_VIDEO_IN,
109+
FRAME_WIDTH, FRAME_HEIGHT, FRAME_RATE,
110+
CFG_TUD_VIDEO_STREAMING_EP_BUFSIZE)
111+
#endif
102112
};
103113

104114
// Invoked when received GET CONFIGURATION DESCRIPTOR

examples/device/video_capture/src/usb_descriptors.h

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ enum {
4343
ITF_NUM_TOTAL
4444
};
4545

46-
#define TUD_VIDEO_CAPTURE_DESC_LEN (\
46+
#define TUD_VIDEO_CAPTURE_DESC_UNCOMPR_LEN (\
4747
TUD_VIDEO_DESC_IAD_LEN\
4848
/* control */\
4949
+ TUD_VIDEO_DESC_STD_VC_LEN\
@@ -61,6 +61,24 @@ enum {
6161
+ 7/* Endpoint */\
6262
)
6363

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+
6482
/* Windows support YUY2 and NV12
6583
* https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/usb-video-class-driver-overview */
6684

@@ -73,7 +91,7 @@ enum {
7391
#define TUD_VIDEO_DESC_CS_VS_FMT_I420(_fmtidx, _numfmtdesc, _frmidx, _asrx, _asry, _interlace, _cp) \
7492
TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR(_fmtidx, _numfmtdesc, TUD_VIDEO_GUID_I420, 12, _frmidx, _asrx, _asry, _interlace, _cp)
7593

76-
#define TUD_VIDEO_CAPTURE_DESCRIPTOR(_stridx, _epin, _width, _height, _fps, _epsize) \
94+
#define TUD_VIDEO_CAPTURE_DESCRIPTOR_UNCOMPR(_stridx, _epin, _width, _height, _fps, _epsize) \
7795
TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \
7896
/* Video control 0 */ \
7997
TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \
@@ -110,4 +128,41 @@ enum {
110128
/* EP */ \
111129
TUD_VIDEO_DESC_EP_ISO(_epin, _epsize, 1)
112130

131+
#define TUD_VIDEO_CAPTURE_DESCRIPTOR_MJPEG(_stridx, _epin, _width, _height, _fps, _epsize) \
132+
TUD_VIDEO_DESC_IAD(ITF_NUM_VIDEO_CONTROL, /* 2 Interfaces */ 0x02, _stridx), \
133+
/* Video control 0 */ \
134+
TUD_VIDEO_DESC_STD_VC(ITF_NUM_VIDEO_CONTROL, 0, _stridx), \
135+
TUD_VIDEO_DESC_CS_VC( /* UVC 1.5*/ 0x0150, \
136+
/* wTotalLength - bLength */ \
137+
TUD_VIDEO_DESC_CAMERA_TERM_LEN + TUD_VIDEO_DESC_OUTPUT_TERM_LEN, \
138+
UVC_CLOCK_FREQUENCY, ITF_NUM_VIDEO_STREAMING), \
139+
TUD_VIDEO_DESC_CAMERA_TERM(UVC_ENTITY_CAP_INPUT_TERMINAL, 0, 0,\
140+
/*wObjectiveFocalLengthMin*/0, /*wObjectiveFocalLengthMax*/0,\
141+
/*wObjectiveFocalLength*/0, /*bmControls*/0), \
142+
TUD_VIDEO_DESC_OUTPUT_TERM(UVC_ENTITY_CAP_OUTPUT_TERMINAL, VIDEO_TT_STREAMING, 0, 1, 0), \
143+
/* Video stream alt. 0 */ \
144+
TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 0, 0, _stridx), \
145+
/* Video stream header for without still image capture */ \
146+
TUD_VIDEO_DESC_CS_VS_INPUT( /*bNumFormats*/1, \
147+
/*wTotalLength - bLength */\
148+
TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN\
149+
+ TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN\
150+
+ TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN,\
151+
_epin, /*bmInfo*/0, /*bTerminalLink*/UVC_ENTITY_CAP_OUTPUT_TERMINAL, \
152+
/*bStillCaptureMethod*/0, /*bTriggerSupport*/0, /*bTriggerUsage*/0, \
153+
/*bmaControls(1)*/0), \
154+
/* Video stream format */ \
155+
TUD_VIDEO_DESC_CS_VS_FMT_MJPEG(/*bFormatIndex*/1, /*bNumFrameDescriptors*/1, \
156+
/*bmFlags*/0, /*bDefaultFrameIndex*/1, 0, 0, 0, /*bCopyProtect*/0), \
157+
/* Video stream frame format */ \
158+
TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT(/*bFrameIndex */1, 0, _width, _height, \
159+
_width * _height * 16, _width * _height * 16 * _fps, \
160+
_width * _height * 16 / 8, \
161+
(10000000/_fps), (10000000/_fps), (10000000/_fps)*_fps, (10000000/_fps)), \
162+
TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(VIDEO_COLOR_PRIMARIES_BT709, VIDEO_COLOR_XFER_CH_BT709, VIDEO_COLOR_COEF_SMPTE170M), \
163+
/* VS alt 1 */\
164+
TUD_VIDEO_DESC_STD_VS(ITF_NUM_VIDEO_STREAMING, 1, 1, _stridx), \
165+
/* EP */ \
166+
TUD_VIDEO_DESC_EP_ISO(_epin, _epsize, 1)
167+
113168
#endif

src/class/video/video.h

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,45 @@ typedef struct TU_ATTR_PACKED {
302302
uint8_t bCopyProtect;
303303
} tusb_desc_cs_video_fmt_uncompressed_t;
304304

305+
typedef struct TU_ATTR_PACKED {
306+
uint8_t bLength;
307+
uint8_t bDescriptorType;
308+
uint8_t bDescriptorSubType;
309+
uint8_t bFormatIndex;
310+
uint8_t bNumFrameDescriptors;
311+
uint8_t bmFlags;
312+
uint8_t bDefaultFrameIndex;
313+
uint8_t bAspectRatioX;
314+
uint8_t bAspectRatioY;
315+
uint8_t bmInterlaceFlags;
316+
uint8_t bCopyProtect;
317+
} tusb_desc_cs_video_fmt_mjpeg_t;
318+
319+
typedef struct TU_ATTR_PACKED {
320+
uint8_t bLength;
321+
uint8_t bDescriptorType;
322+
uint8_t bDescriptorSubType;
323+
uint8_t bFormatIndex;
324+
uint32_t dwMaxVideoFrameBufferSize; /* deprecated */
325+
uint8_t bFormatType;
326+
} tusb_desc_cs_video_fmt_dv_t;
327+
328+
typedef struct TU_ATTR_PACKED {
329+
uint8_t bLength;
330+
uint8_t bDescriptorType;
331+
uint8_t bDescriptorSubType;
332+
uint8_t bFormatIndex;
333+
uint8_t bNumFrameDescriptors;
334+
uint8_t guidFormat[16];
335+
uint8_t bBitsPerPixel;
336+
uint8_t bDefaultFrameIndex;
337+
uint8_t bAspectRatioX;
338+
uint8_t bAspectRatioY;
339+
uint8_t bmInterlaceFlags;
340+
uint8_t bCopyProtect;
341+
uint8_t bVaribaleSize;
342+
} tusb_desc_cs_video_fmt_frame_based_t;
343+
305344
typedef struct TU_ATTR_PACKED {
306345
uint8_t bLength;
307346
uint8_t bDescriptorType;
@@ -318,6 +357,24 @@ typedef struct TU_ATTR_PACKED {
318357
uint32_t dwFrameInterval[];
319358
} tusb_desc_cs_video_frm_uncompressed_t;
320359

360+
typedef tusb_desc_cs_video_frm_uncompressed_t tusb_desc_cs_video_frm_mjpeg_t;
361+
362+
typedef struct TU_ATTR_PACKED {
363+
uint8_t bLength;
364+
uint8_t bDescriptorType;
365+
uint8_t bDescriptorSubType;
366+
uint8_t bFrameIndex;
367+
uint8_t bmCapabilities;
368+
uint16_t wWidth;
369+
uint16_t wHeight;
370+
uint32_t dwMinBitRate;
371+
uint32_t dwMaxBitRate;
372+
uint32_t dwDefaultFrameInterval;
373+
uint8_t bFrameIntervalType;
374+
uint32_t dwBytesPerLine;
375+
uint32_t dwFrameInterval[];
376+
} tusb_desc_cs_video_frm_frame_based_t;
377+
321378
//--------------------------------------------------------------------+
322379
// Requests
323380
//--------------------------------------------------------------------+
@@ -378,8 +435,11 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
378435
#define TUD_VIDEO_DESC_CS_VS_IN_LEN 13
379436
#define TUD_VIDEO_DESC_CS_VS_OUT_LEN 9
380437
#define TUD_VIDEO_DESC_CS_VS_FMT_UNCOMPR_LEN 27
438+
#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN 11
381439
#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_CONT_LEN 38
382440
#define TUD_VIDEO_DESC_CS_VS_FRM_UNCOMPR_DISC_LEN 26
441+
#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN 38
442+
#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN 26
383443
#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN 6
384444

385445
/* 2.2 compression formats */
@@ -462,6 +522,25 @@ TU_VERIFY_STATIC( sizeof(video_probe_and_commit_control_t) == 48, "size is not c
462522
_frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
463523
U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__
464524

525+
/* Motion-JPEG 3.1.1 Table 3-1 */
526+
#define TUD_VIDEO_DESC_CS_VS_FMT_MJPEG(_fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp) \
527+
TUD_VIDEO_DESC_CS_VS_FMT_MJPEG_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_MJPEG, \
528+
_fmtidx, _numfrmdesc, _fixed_sz, _frmidx, _asrx, _asry, _interlace, _cp
529+
530+
/* Motion-JPEG 3.1.1 Table 3-2 and 3-3 */
531+
#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, _minfrminterval, _maxfrminterval, _frmintervalstep) \
532+
TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_CONT_LEN, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_MJPEG, \
533+
_frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
534+
U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), 0, \
535+
U32_TO_U8S_LE(_minfrminterval), U32_TO_U8S_LE(_maxfrminterval), U32_TO_U8S_LE(_frmintervalstep)
536+
537+
/* Motion-JPEG 3.1.1 Table 3-2 and 3-4 */
538+
#define TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC(_frmidx, _cap, _width, _height, _minbr, _maxbr, _maxfrmbufsz, _frminterval, ...) \
539+
TUD_VIDEO_DESC_CS_VS_FRM_MJPEG_DISC_LEN + (TU_ARGS_NUM(__VA_ARGS__)) * 4, \
540+
TUSB_DESC_CS_INTERFACE, VIDEO_CS_VS_INTERFACE_FRAME_MJPEG, \
541+
_frmidx, _cap, U16_TO_U8S_LE(_width), U16_TO_U8S_LE(_height), U32_TO_U8S_LE(_minbr), U32_TO_U8S_LE(_maxbr), \
542+
U32_TO_U8S_LE(_maxfrmbufsz), U32_TO_U8S_LE(_frminterval), (TU_ARGS_NUM(__VA_ARGS__)), __VA_ARGS__
543+
465544
/* 3.9.2.6 */
466545
#define TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING(_color, _trns, _mat) \
467546
TUD_VIDEO_DESC_CS_VS_COLOR_MATCHING_LEN, \

0 commit comments

Comments
 (0)