Skip to content

Commit b3cce3e

Browse files
author
Alain Volmat
committed
usb: usbd_uvc: add frame_based support (currently only H264)
The frame_based descriptors differ from the frame descriptors in that there is no dwMaxVideoFrameBufferSize field. In order to do that, add a new uvc_frame_based_discrete_descriptor structure to be used to fill in proper information into the frame descriptor. In addition to that, a new format descriptor is also added for frame based transfer. Signed-off-by: Alain Volmat <[email protected]>
1 parent e91b764 commit b3cce3e

File tree

3 files changed

+136
-10
lines changed

3 files changed

+136
-10
lines changed

samples/subsys/usb/uvc/src/main.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ static bool app_is_supported_format(uint32_t pixfmt)
5757
{
5858
return pixfmt == VIDEO_PIX_FMT_JPEG ||
5959
pixfmt == VIDEO_PIX_FMT_YUYV ||
60-
pixfmt == VIDEO_PIX_FMT_NV12;
60+
pixfmt == VIDEO_PIX_FMT_NV12 ||
61+
pixfmt == VIDEO_PIX_FMT_H264;
6162
}
6263

6364
static bool app_has_supported_format(void)

subsys/usb/device_next/class/usbd_uvc.c

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ union uvc_fmt_desc {
7272
struct uvc_format_descriptor fmt;
7373
struct uvc_format_uncomp_descriptor fmt_uncomp;
7474
struct uvc_format_mjpeg_descriptor fmt_mjpeg;
75+
struct uvc_format_frame_based_descriptor fmt_frame_based;
7576
struct uvc_frame_descriptor frm;
7677
struct uvc_frame_continuous_descriptor frm_cont;
7778
struct uvc_frame_discrete_descriptor frm_disc;
@@ -398,7 +399,8 @@ static void uvc_get_vs_fmtfrm_desc(const struct device *dev,
398399
i, desc->bDescriptorSubtype, desc->bFormatIndex, desc);
399400

400401
if ((desc->bDescriptorSubtype == UVC_VS_FORMAT_UNCOMPRESSED ||
401-
desc->bDescriptorSubtype == UVC_VS_FORMAT_MJPEG) &&
402+
desc->bDescriptorSubtype == UVC_VS_FORMAT_MJPEG ||
403+
desc->bDescriptorSubtype == UVC_VS_FORMAT_FRAME_BASED) &&
402404
desc->bFormatIndex == data->format_id) {
403405
*format_desc = desc;
404406
break;
@@ -413,7 +415,8 @@ static void uvc_get_vs_fmtfrm_desc(const struct device *dev,
413415
i, desc->bDescriptorSubtype, desc->bFrameIndex, desc);
414416

415417
if (desc->bDescriptorSubtype != UVC_VS_FRAME_UNCOMPRESSED &&
416-
desc->bDescriptorSubtype != UVC_VS_FRAME_MJPEG) {
418+
desc->bDescriptorSubtype != UVC_VS_FRAME_MJPEG &&
419+
desc->bDescriptorSubtype != UVC_VS_FRAME_FRAME_BASED) {
417420
break;
418421
}
419422

@@ -461,7 +464,8 @@ static int uvc_get_vs_probe_format_index(const struct device *dev, struct uvc_pr
461464
struct uvc_format_descriptor *desc = &cfg->desc->if1_fmts[i].fmt;
462465

463466
max += desc->bDescriptorSubtype == UVC_VS_FORMAT_UNCOMPRESSED ||
464-
desc->bDescriptorSubtype == UVC_VS_FORMAT_MJPEG;
467+
desc->bDescriptorSubtype == UVC_VS_FORMAT_MJPEG ||
468+
desc->bDescriptorSubtype == UVC_VS_FORMAT_FRAME_BASED;
465469
}
466470

467471
switch (request) {
@@ -496,8 +500,9 @@ static int uvc_get_vs_probe_frame_index(const struct device *dev, struct uvc_pro
496500
struct uvc_format_descriptor *desc = &cfg->desc->if1_fmts[i].fmt;
497501

498502
if ((desc->bDescriptorSubtype == UVC_VS_FORMAT_UNCOMPRESSED ||
499-
desc->bDescriptorSubtype == UVC_VS_FORMAT_MJPEG) &&
500-
desc->bFormatIndex == data->format_id) {
503+
desc->bDescriptorSubtype == UVC_VS_FORMAT_MJPEG ||
504+
desc->bDescriptorSubtype == UVC_VS_FORMAT_FRAME_BASED) &&
505+
desc->bFormatIndex == data->format_id) {
501506
break;
502507
}
503508
}
@@ -507,7 +512,8 @@ static int uvc_get_vs_probe_frame_index(const struct device *dev, struct uvc_pro
507512
struct uvc_frame_discrete_descriptor *desc = &cfg->desc->if1_fmts[i].frm_disc;
508513

509514
if (desc->bDescriptorSubtype != UVC_VS_FRAME_UNCOMPRESSED &&
510-
desc->bDescriptorSubtype != UVC_VS_FRAME_MJPEG) {
515+
desc->bDescriptorSubtype != UVC_VS_FRAME_MJPEG &&
516+
desc->bDescriptorSubtype != UVC_VS_FRAME_FRAME_BASED) {
511517
break;
512518
}
513519
max++;
@@ -551,6 +557,13 @@ static int uvc_get_vs_probe_frame_interval(const struct device *dev, struct uvc_
551557
struct uvc_frame_discrete_descriptor *desc =
552558
(struct uvc_frame_discrete_descriptor *)frame_desc;
553559

560+
min = sys_cpu_to_le32(desc->dwFrameInterval[0]);
561+
max_id = desc->bFrameIntervalType - 1;
562+
max = sys_cpu_to_le32(desc->dwFrameInterval[max_id]);
563+
} else if (frame_desc->bDescriptorSubtype == UVC_VS_FRAME_FRAME_BASED) {
564+
struct uvc_frame_based_discrete_descriptor *desc =
565+
(struct uvc_frame_based_discrete_descriptor *)frame_desc;
566+
554567
min = sys_cpu_to_le32(desc->dwFrameInterval[0]);
555568
max_id = desc->bFrameIntervalType - 1;
556569
max = sys_cpu_to_le32(desc->dwFrameInterval[max_id]);
@@ -627,6 +640,15 @@ static int uvc_get_vs_format_from_desc(const struct device *dev, struct video_fo
627640

628641
LOG_DBG("Found descriptor for format %u, frame %u, MJPEG",
629642
format_desc->bFormatIndex, frame_desc->bFrameIndex);
643+
} else if (format_desc->bDescriptorSubtype == UVC_VS_FORMAT_FRAME_BASED) {
644+
struct uvc_format_frame_based_descriptor *format_frame_based_desc =
645+
(void *)format_desc;
646+
647+
fmt->pixelformat = uvc_guid_to_fourcc(format_frame_based_desc->guidFormat);
648+
649+
LOG_DBG("Found descriptor for format %u, frame %u, GUID '%.4s', pixfmt %04x",
650+
format_frame_based_desc->bFormatIndex, frame_desc->bFrameIndex,
651+
format_frame_based_desc->guidFormat, fmt->pixelformat);
630652
} else {
631653
struct uvc_format_uncomp_descriptor *format_uncomp_desc = (void *)format_desc;
632654

@@ -1422,6 +1444,27 @@ static int uvc_add_vs_format_desc(const struct device *dev,
14221444
cfg->desc->if1_hdr.bNumFormats++;
14231445
cfg->desc->if1_hdr.wTotalLength += desc->bLength;
14241446
*format_desc = (struct uvc_format_descriptor *)desc;
1447+
} else if (fourcc == VIDEO_PIX_FMT_H264) {
1448+
struct uvc_format_frame_based_descriptor *desc;
1449+
1450+
LOG_INF("Adding format descriptor #%u for H264",
1451+
cfg->desc->if1_hdr.bNumFormats + 1);
1452+
1453+
desc = &uvc_new_fmt_desc(dev)->fmt_frame_based;
1454+
if (desc == NULL) {
1455+
return -ENOMEM;
1456+
}
1457+
1458+
desc->bDescriptorType = USB_DESC_CS_INTERFACE;
1459+
desc->bFormatIndex = cfg->desc->if1_hdr.bNumFormats + 1;
1460+
desc->bLength = sizeof(*desc);
1461+
desc->bDescriptorSubtype = UVC_VS_FORMAT_FRAME_BASED;
1462+
uvc_fourcc_to_guid(desc->guidFormat, fourcc);
1463+
desc->bDefaultFrameIndex = 1;
1464+
desc->bVariableSize = 1;
1465+
cfg->desc->if1_hdr.bNumFormats++;
1466+
cfg->desc->if1_hdr.wTotalLength += desc->bLength;
1467+
*format_desc = (struct uvc_format_descriptor *)desc;
14251468
} else {
14261469
struct uvc_format_uncomp_descriptor *desc;
14271470

@@ -1502,6 +1545,19 @@ static int uvc_add_vs_frame_interval(struct uvc_frame_descriptor *const desc,
15021545
return -ENOMEM;
15031546
}
15041547

1548+
frame_desc->dwFrameInterval[frame_desc->bFrameIntervalType] =
1549+
sys_cpu_to_le32(video_frmival_nsec(frmival) / 100);
1550+
frame_desc->bFrameIntervalType++;
1551+
frame_desc->bLength += sizeof(uint32_t);
1552+
} else if (desc->bDescriptorSubtype == UVC_VS_FRAME_FRAME_BASED) {
1553+
struct uvc_frame_based_discrete_descriptor *frame_desc =
1554+
(struct uvc_frame_based_discrete_descriptor *)desc;
1555+
1556+
if (frame_desc->bFrameIntervalType >= CONFIG_USBD_VIDEO_MAX_FRMIVAL) {
1557+
LOG_WRN("Out of frame interval fields");
1558+
return -ENOSPC;
1559+
}
1560+
15051561
frame_desc->dwFrameInterval[frame_desc->bFrameIntervalType] =
15061562
sys_cpu_to_le32(video_frmival_nsec(frmival) / 100);
15071563
frame_desc->bFrameIntervalType++;
@@ -1544,8 +1600,13 @@ static int uvc_add_vs_frame_desc(const struct device *dev,
15441600
desc->bFrameIndex = format_desc->bNumFrameDescriptors + 1;
15451601
desc->wWidth = sys_cpu_to_le16(fmt->width);
15461602
desc->wHeight = sys_cpu_to_le16(fmt->height);
1547-
desc->bDescriptorSubtype = (format_desc->bDescriptorSubtype == UVC_VS_FORMAT_UNCOMPRESSED)
1548-
? UVC_VS_FRAME_UNCOMPRESSED : UVC_VS_FRAME_MJPEG;
1603+
if (format_desc->bDescriptorSubtype == UVC_VS_FORMAT_UNCOMPRESSED) {
1604+
desc->bDescriptorSubtype = UVC_VS_FRAME_UNCOMPRESSED;
1605+
} else if (format_desc->bDescriptorSubtype == UVC_VS_FORMAT_MJPEG) {
1606+
desc->bDescriptorSubtype = UVC_VS_FRAME_MJPEG;
1607+
} else if (format_desc->bDescriptorSubtype == UVC_VS_FORMAT_FRAME_BASED) {
1608+
desc->bDescriptorSubtype = UVC_VS_FRAME_FRAME_BASED;
1609+
}
15491610
desc->dwMinBitRate = sys_cpu_to_le32(UINT32_MAX);
15501611
desc->dwMaxBitRate = sys_cpu_to_le32(0);
15511612

@@ -1600,7 +1661,23 @@ static int uvc_add_vs_frame_desc(const struct device *dev,
16001661

16011662
/* UVC requires the frame intervals to be sorted, but not Zephyr */
16021663
qsort(frame_desc->dwFrameInterval, frame_desc->bFrameIntervalType,
1603-
sizeof(*frame_discrete_desc->dwFrameInterval), uvc_compare_frmival_desc);
1664+
sizeof(*frame_desc->dwFrameInterval), uvc_compare_frmival_desc);
1665+
1666+
frame_desc->dwDefaultFrameInterval = frame_desc->dwFrameInterval[0];
1667+
} else if (desc->bDescriptorSubtype == UVC_VS_FRAME_FRAME_BASED) {
1668+
struct uvc_frame_based_discrete_descriptor *frame_desc =
1669+
(struct uvc_frame_based_discrete_descriptor *)desc;
1670+
1671+
/* If no frame intrval supported, default to 30 FPS */
1672+
if (frame_desc->bFrameIntervalType == 0) {
1673+
struct video_frmival frmival = {.numerator = 1, .denominator = 30};
1674+
1675+
uvc_add_vs_frame_interval(desc, &frmival, fmt);
1676+
}
1677+
1678+
/* UVC requires the frame intervals to be sorted, but not Zephyr */
1679+
qsort(frame_desc->dwFrameInterval, frame_desc->bFrameIntervalType,
1680+
sizeof(*frame_desc->dwFrameInterval), uvc_compare_frmival_desc);
16041681

16051682
frame_desc->dwDefaultFrameInterval = frame_desc->dwFrameInterval[0];
16061683
} else {

subsys/usb/device_next/class/usbd_uvc.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,22 @@ struct uvc_format_mjpeg_descriptor {
375375
uint8_t bCopyProtect;
376376
} __packed;
377377

378+
struct uvc_format_frame_based_descriptor {
379+
uint8_t bLength;
380+
uint8_t bDescriptorType;
381+
uint8_t bDescriptorSubtype;
382+
uint8_t bFormatIndex;
383+
uint8_t bNumFrameDescriptors;
384+
uint8_t guidFormat[16];
385+
uint8_t bBitsPerPixel;
386+
uint8_t bDefaultFrameIndex;
387+
uint8_t bAspectRatioX;
388+
uint8_t bAspectRatioY;
389+
uint8_t bmInterlaceFlags;
390+
uint8_t bCopyProtect;
391+
uint8_t bVariableSize;
392+
} __packed;
393+
378394
struct uvc_frame_descriptor {
379395
uint8_t bLength;
380396
uint8_t bDescriptorType;
@@ -422,6 +438,38 @@ struct uvc_frame_discrete_descriptor {
422438
uint32_t dwFrameInterval[CONFIG_USBD_VIDEO_MAX_FRMIVAL];
423439
} __packed;
424440

441+
struct uvc_frame_based_continuous_descriptor {
442+
uint8_t bLength;
443+
uint8_t bDescriptorType;
444+
uint8_t bDescriptorSubtype;
445+
uint8_t bFrameIndex;
446+
uint8_t bmCapabilities;
447+
uint16_t wWidth;
448+
uint16_t wHeight;
449+
uint32_t dwMinBitRate;
450+
uint32_t dwMaxBitRate;
451+
uint32_t dwDefaultFrameInterval;
452+
uint8_t bFrameIntervalType;
453+
uint32_t dwMinFrameInterval;
454+
uint32_t dwMaxFrameInterval;
455+
uint32_t dwFrameIntervalStep;
456+
} __packed;
457+
458+
struct uvc_frame_based_discrete_descriptor {
459+
uint8_t bLength;
460+
uint8_t bDescriptorType;
461+
uint8_t bDescriptorSubtype;
462+
uint8_t bFrameIndex;
463+
uint8_t bmCapabilities;
464+
uint16_t wWidth;
465+
uint16_t wHeight;
466+
uint32_t dwMinBitRate;
467+
uint32_t dwMaxBitRate;
468+
uint32_t dwDefaultFrameInterval;
469+
uint8_t bFrameIntervalType;
470+
uint32_t dwFrameInterval[CONFIG_USBD_VIDEO_MAX_FRMIVAL];
471+
} __packed;
472+
425473
struct uvc_color_descriptor {
426474
uint8_t bLength;
427475
uint8_t bDescriptorType;

0 commit comments

Comments
 (0)