Change images to MJPEG

This commit is contained in:
kkitayam
2021-10-12 23:29:58 +09:00
parent 111515a29c
commit e80714740c
5 changed files with 536 additions and 31 deletions

View File

@@ -29,6 +29,8 @@
#if (CFG_TUD_ENABLED && CFG_TUD_VIDEO && CFG_TUD_VIDEO_STREAMING)
#include <stdarg.h>
#include "device/usbd.h"
#include "device/usbd_pvt.h"
@@ -59,6 +61,30 @@ typedef struct TU_ATTR_PACKED {
uint8_t bEntityId;
} tusb_desc_cs_video_entity_itf_t;
typedef union {
struct TU_ATTR_PACKED {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubType;
uint8_t bFormatIndex;
};
tusb_desc_cs_video_fmt_uncompressed_t uncompressed;
tusb_desc_cs_video_fmt_mjpeg_t mjpeg;
tusb_desc_cs_video_fmt_frame_based_t frame_based;
} tusb_desc_cs_video_fmt_t;
typedef union {
struct TU_ATTR_PACKED {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bDescriptorSubType;
uint8_t bFrameIndex;
};
tusb_desc_cs_video_frm_uncompressed_t uncompressed;
tusb_desc_cs_video_frm_mjpeg_t mjpeg;
tusb_desc_cs_video_frm_frame_based_t frame_based;
} tusb_desc_cs_video_frm_t;
/* video streaming interface */
typedef struct TU_ATTR_PACKED {
uint8_t index_vc; /* index of bound video control interface */
@@ -167,6 +193,72 @@ static void const* _find_desc(void const *beg, void const *end, uint_fast8_t des
return cur;
}
/** Find the first descriptor of a given types
*
* @param[in] beg The head of descriptor byte array.
* @param[in] end The tail of descriptor byte array.
* @param[in] ... The target descriptor types. The last type must be 0.
*
* @return The pointer for interface descriptor.
* @retval end did not found interface descriptor */
static void const* _find_desc_n(void const *beg, void const *end, ...)
{
uint_fast8_t target = 0;
void const *cur;
for (cur = beg; cur < end && !target; cur = tu_desc_next(cur)) {
uint_fast8_t actual = tu_desc_type(cur);
va_list ap;
va_start(ap, end);
do {
target = va_arg(ap, unsigned);
} while (target && target != actual);
va_end(ap);
}
return cur;
}
/** Find the first descriptor specified by the arguments
*
* @param[in] beg The head of descriptor byte array.
* @param[in] end The tail of descriptor byte array.
* @param[in] sub_types The target bDescriptorSubtype list. The last elemnt must be 0.
*
* @return The pointer for interface descriptor.
* @retval end did not found interface descriptor */
static void const* _find_desc_cs(void const *beg, void const *end, uint8_t const *sub_types)
{
uint_fast8_t target = 0;
void const *cur;
for (cur = beg; cur < end && !target; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
uint_fast8_t actual = ((uint8_t const *)cur)[2];
uint8_t const *p = sub_types;
do {
target = *p++;
} while (target && target != actual);
}
return cur;
}
/** Find the first descriptor specified by the arguments
*
* @param[in] beg The head of descriptor byte array.
* @param[in] end The tail of descriptor byte array.
* @param[in] desc_type The target descriptor type
* @param[in] element_0 The target element following the desc_type
*
* @return The pointer for interface descriptor.
* @retval end did not found interface descriptor */
static void const* _find_desc_2(void const *beg, void const *end,
uint_fast8_t desc_type, uint_fast8_t element_0)
{
for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, desc_type)) {
uint8_t const *p = (uint8_t const *)cur;
if (p[2] == element_0) return cur;
cur = tu_desc_next(cur);
}
return end;
}
/** Find the first descriptor specified by the arguments
*
* @param[in] beg The head of descriptor byte array.
@@ -235,14 +327,19 @@ static inline void const* _find_desc_itf(void const *beg, void const *end, uint_
* @retval end did not found endpoint descriptor */
static void const* _find_desc_ep(void const *beg, void const *end)
{
for (void const *cur = beg; cur < end; cur = tu_desc_next(cur)) {
uint_fast8_t desc_type = tu_desc_type(cur);
if (TUSB_DESC_ENDPOINT == desc_type) return cur;
if (TUSB_DESC_INTERFACE == desc_type) break;
}
void const *cur = _find_desc_n(beg, end, TUSB_DESC_ENDPOINT, TUSB_DESC_INTERFACE, 0);
if ((cur < end) && (TUSB_DESC_ENDPOINT == tu_desc_type(cur)))
return cur;
return end;
}
/** Return the end of the video control descriptor. */
static inline void const* _end_of_control_descriptor(void const *desc)
{
tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const *)desc;
return desc + vc->std.bLength + vc->ctl.wTotalLength;
}
/** Find the first entity descriptor with the entity ID
* specified by the argument belonging to the current video control descriptor.
*
@@ -253,10 +350,8 @@ static void const* _find_desc_ep(void const *beg, void const *end)
* @retval end did not found interface descriptor */
static void const* _find_desc_entity(void const *desc, uint_fast8_t entityid)
{
tusb_desc_vc_itf_t const *vc = (tusb_desc_vc_itf_t const*)desc;
void const *beg = vc;
void const *end = beg + vc->std.bLength + vc->ctl.wTotalLength;
for (void const *cur = beg; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
void const *end = _end_of_control_descriptor(desc);
for (void const *cur = desc; cur < end; cur = _find_desc(cur, end, TUSB_DESC_CS_INTERFACE)) {
tusb_desc_cs_video_entity_itf_t const *itf = (tusb_desc_cs_video_entity_itf_t const *)cur;
if ((VIDEO_CS_ITF_VC_INPUT_TERMINAL <= itf->bDescriptorSubtype
&& itf->bDescriptorSubtype < VIDEO_CS_ITF_VC_MAX)
@@ -276,17 +371,38 @@ static inline void const* _end_of_streaming_descriptor(void const *desc)
}
/** Find the first format descriptor with the specified format number. */
static inline tusb_desc_cs_video_fmt_uncompressed_t const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum)
static inline void const *_find_desc_format(void const *beg, void const *end, uint_fast8_t fmtnum)
{
return (tusb_desc_cs_video_fmt_uncompressed_t const*)
_find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED, fmtnum);
static uint8_t const sub_types[] = {
VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED,
VIDEO_CS_ITF_VS_FORMAT_MJPEG,
VIDEO_CS_ITF_VS_FORMAT_DV,
VIDEO_CS_ITF_VS_FORMAT_FRAME_BASED,
0
};
while (true) {
uint8_t const *cur = _find_desc_cs(beg, end, sub_types);
if ((end == cur) || (fmtnum == cur[3]))
return cur;
cur = tu_desc_next(cur);
}
}
/** Find the first frame descriptor with the specified format number. */
static inline tusb_desc_cs_video_frm_uncompressed_t const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum)
static inline void const *_find_desc_frame(void const *beg, void const *end, uint_fast8_t frmnum)
{
return (tusb_desc_cs_video_frm_uncompressed_t const*)
_find_desc_3(beg, end, TUSB_DESC_CS_INTERFACE, VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED, frmnum);
static uint8_t const sub_types[] = {
VIDEO_CS_ITF_VS_FRAME_UNCOMPRESSED,
VIDEO_CS_ITF_VS_FRAME_MJPEG,
VIDEO_CS_ITF_VS_FRAME_FRAME_BASED,
0
};
while (true) {
uint8_t const *cur = _find_desc_cs(beg, end, sub_types);
if ((end == cur) || (frmnum == ((uint8_t const *)cur)[3]))
return cur;
cur = tu_desc_next(cur);
}
}
/** Set uniquely determined values to variables that have not been set
@@ -307,7 +423,6 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
/* Set the parameters determined by the format */
param->wKeyFrameRate = 1;
param->wPFrameRate = 0;
param->wCompQuality = 1; /* 1 to 10000 */
param->wCompWindowSize = 1; /* GOP size? */
param->wDelay = 0; /* milliseconds */
param->dwClockFrequency = 27000000; /* same as MPEG-2 system time clock */
@@ -319,8 +434,18 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
param->bBitDepthLuma = 8;
void const *end = _end_of_streaming_descriptor(vs);
tusb_desc_cs_video_fmt_uncompressed_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
tusb_desc_cs_video_fmt_t const *fmt = _find_desc_format(tu_desc_next(vs), end, fmtnum);
TU_ASSERT(fmt != end);
switch (fmt->bDescriptorSubtype) {
case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
param->wCompQuality = 1; /* 1 to 10000 */
break;
case VIDEO_CS_ITF_VS_FORMAT_MJPEG;
break;
default: return false;
}
uint_fast8_t frmnum = param->bFrameIndex;
TU_ASSERT(frmnum <= fmt->bNumFrameDescriptors);
if (!frmnum) {
@@ -328,13 +453,21 @@ static bool _update_streaming_parameters(videod_streaming_interface_t const *stm
frmnum = 1;
param->bFrameIndex = 1;
}
tusb_desc_cs_video_frm_uncompressed_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
tusb_desc_cs_video_frm_t const *frm = _find_desc_frame(tu_desc_next(fmt), end, frmnum);
TU_ASSERT(frm != end);
/* Set the parameters determined by the frame */
uint_fast32_t frame_size = param->dwMaxVideoFrameSize;
if (!frame_size) {
frame_size = (uint_fast32_t)frm->wWidth * frm->wHeight * fmt->bBitsPerPixel / 8;
switch (fmt->bDescriptorSubtype) {
case VIDEO_CS_ITF_VS_FORMAT_UNCOMPRESSED:
frame_size = (uint_fast32_t)frm->uncompressed.wWidth * frm->uncompressed.wHeight * fmt->uncompressed.bBitsPerPixel / 8;
break;
case VIDEO_CS_ITF_VS_FORMAT_MJPEG;
frame_size = (uint_fast32_t)frm->mjpeg.wWidth * frm->mjpeg.wHeight * 16 / 8; /* YUV422 */
break;
default: break;
}
param->dwMaxVideoFrameSize = frame_size;
}
@@ -487,7 +620,7 @@ static bool _close_vc_itf(uint8_t rhport, videod_interface_t *self)
/* The next descriptor after the class-specific VC interface header descriptor. */
void const *cur = (void const*)vc + vc->std.bLength + vc->ctl.bLength;
/* The end of the video control interface descriptor. */
void const *end = (void const*)vc + vc->std.bLength + vc->ctl.wTotalLength;
void const *end = _end_of_control_descriptor(vc);
if (vc->std.bNumEndpoints) {
/* Find the notification endpoint descriptor. */
cur = _find_desc(cur, end, TUSB_DESC_ENDPOINT);
@@ -519,7 +652,7 @@ static bool _open_vc_itf(uint8_t rhport, videod_interface_t *self, uint_fast8_t
TU_ASSERT(vc->ctl.bInCollection <= CFG_TUD_VIDEO_STREAMING);
/* Update to point the end of the video control interface descriptor. */
end = cur + vc->std.bLength + vc->ctl.wTotalLength;
end = _end_of_control_descriptor(cur);
/* Advance to the next descriptor after the class-specific VC interface header descriptor. */
cur += vc->std.bLength + vc->ctl.bLength;
TU_LOG2(" bNumEndpoints %d\n", vc->std.bNumEndpoints);