From afa77ec20b4b03b83518e3c6b067142866ad90fd Mon Sep 17 00:00:00 2001 From: sakumisu <1203593632@qq.com> Date: Sat, 15 Jun 2024 13:33:34 +0800 Subject: [PATCH] update(video): add more video desc macros, like h264, yuv, add vc endpoint to choose, add yuv template --- class/video/usb_video.h | 349 +++-- demo/CherryUSB.h264 | Bin 0 -> 20750 bytes demo/CherryUSB.jpg | Bin 0 -> 24775 bytes demo/CherryUSB_64x48.YUYV | 1 + demo/cherryusb_h264.h | 1734 +++++++++++++++++++++++ demo/cherryusb_mjpeg.h | 2067 ++++++++++++++++++++++++++++ demo/cherryusb_yuyv.h | 514 +++++++ demo/pic_data.h | 1146 --------------- demo/video_static_h264_template.c | 254 ++++ demo/video_static_mjpeg_template.c | 44 +- demo/video_static_yuyv_template.c | 256 ++++ 11 files changed, 5104 insertions(+), 1261 deletions(-) create mode 100644 demo/CherryUSB.h264 create mode 100644 demo/CherryUSB.jpg create mode 100644 demo/CherryUSB_64x48.YUYV create mode 100644 demo/cherryusb_h264.h create mode 100644 demo/cherryusb_mjpeg.h create mode 100644 demo/cherryusb_yuyv.h delete mode 100644 demo/pic_data.h create mode 100644 demo/video_static_h264_template.c create mode 100644 demo/video_static_yuyv_template.c diff --git a/class/video/usb_video.h b/class/video/usb_video.h index 4997526b..06d6d13c 100644 --- a/class/video/usb_video.h +++ b/class/video/usb_video.h @@ -922,7 +922,7 @@ struct video_cs_if_vs_frame_uncompressed_descriptor { uint8_t bLength; uint8_t bDescriptorType; uint8_t bDescriptorSubType; - uint8_t bFormatIndex; + uint8_t bFrameIndex; uint8_t bmCapabilities; uint16_t wWidth; uint16_t wHeight; @@ -931,10 +931,10 @@ struct video_cs_if_vs_frame_uncompressed_descriptor { uint32_t dwMaxVideoFrameBufferSize; uint32_t dwDefaultFrameInterval; uint8_t bFrameIntervalType; - uint32_t dwFrameInterval; + uint32_t dwFrameInterval[]; } __PACKED; -#define VIDEO_SIZEOF_VS_FRAME_UNCOMPRESSED_DESC 30 +#define VIDEO_SIZEOF_VS_FRAME_UNCOMPRESSED_DESC(n) (26 + 4 * (n)) struct video_cs_if_vs_format_mjpeg_descriptor { uint8_t bLength; @@ -956,7 +956,7 @@ struct video_cs_if_vs_frame_mjpeg_descriptor { uint8_t bLength; uint8_t bDescriptorType; uint8_t bDescriptorSubType; - uint8_t bFormatIndex; + uint8_t bFrameIndex; uint8_t bmCapabilities; uint16_t wWidth; uint16_t wHeight; @@ -965,11 +965,48 @@ struct video_cs_if_vs_frame_mjpeg_descriptor { uint32_t dwMaxVideoFrameBufferSize; uint32_t dwDefaultFrameInterval; uint8_t bFrameIntervalType; - uint32_t dwFrameInterval1; - uint32_t dwFrameInterval2; + uint32_t dwFrameInterval[]; } __PACKED; -#define VIDEO_SIZEOF_VS_FRAME_MJPEG_DESC(n) (26 + n) +#define VIDEO_SIZEOF_VS_FRAME_MJPEG_DESC(n) (26 + 4 * (n)) + +/* H264 Payload - 3.1.1. H264 Video Format Descriptor */ +struct video_cs_if_vs_format_h26x_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFormatIndex; + uint8_t bNumFrameDescriptors; + uint8_t guidFormat[16]; + uint8_t bBitsPerPixel; + uint8_t bDefaultFrameIndex; + uint8_t bAspectRatioX; + uint8_t bAspectRatioY; + uint8_t bmInterfaceFlags; + uint8_t bCopyProtect; + uint8_t bVariableSize; +} __PACKED; + +#define VIDEO_SIZEOF_VS_FORMAT_H264_DESC 28 + +/* H264 Payload - 3.1.2. H264 Video Frame Descriptor */ +struct video_cs_if_vs_frame_h26x_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDescriptorSubType; + uint8_t bFrameIndex; + uint8_t bmCapabilities; + uint16_t wWidth; + uint16_t wHeight; + uint32_t dwMinBitRate; + uint32_t dwMaxBitRate; + uint32_t dwDefaultFrameInterval; + uint8_t bFrameIntervalType; + uint32_t dwBytesPerLine; + uint32_t dwFrameInterval[]; +} __PACKED; + +#define VIDEO_SIZEOF_VS_FRAME_H264_DESC(n) (26 + 4 * (n)) struct video_cs_if_vs_colorformat_descriptor { uint8_t bLength; @@ -1044,71 +1081,140 @@ struct video_autoexposure_mode { #define VIDEO_GUID_M420 0x4D, 0x34, 0x32, 0x30, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 #define VIDEO_GUID_I420 0x49, 0x34, 0x32, 0x30, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 +#define VIDEO_VC_TERMINAL_LEN (13 + 18 + 12 + 9) + +/*Length of template descriptor: 81 bytes*/ +#define VIDEO_VC_DESCRIPTOR_LEN (8 + 9 + VIDEO_VC_TERMINAL_LEN + 7 + 5) +#define VIDEO_VC_NOEP_DESCRIPTOR_LEN (8 + 9 + VIDEO_VC_TERMINAL_LEN) + // clang-format off -#define VIDEO_VC_DESCRIPTOR_INIT(bFirstInterface, bNumEndpoints, bcdUVC, wTotalLength, dwClockFrequency, stridx) \ - /* Interface Association Descriptor */ \ - 0x08, \ - USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, \ - bFirstInterface, \ - 0x02, \ - USB_DEVICE_CLASS_VIDEO, \ - VIDEO_SC_VIDEO_INTERFACE_COLLECTION, \ - 0x00, \ - 0x00, \ - /* VideoControl Interface Descriptor */ \ - 0x09, /* bLength */ \ - USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \ - 0x00, /* bInterfaceNumber */ \ - 0x00, /* bAlternateSetting */ \ - bNumEndpoints, /* bNumEndpoints:1 endpoint (interrupt endpoint) */ \ - USB_DEVICE_CLASS_VIDEO, /* bInterfaceClass : CC_VIDEO */ \ - VIDEO_SC_VIDEOCONTROL, /* bInterfaceSubClass : SC_VIDEOCONTROL */ \ - VIDEO_PC_PROTOCOL_UNDEFINED, /* bInterfaceProtocol : PC_PROTOCOL_UNDEFINED */ \ - stridx, /* iInterface:Index to string descriptor that contains the string */ \ - /*Class-specific VideoControl Interface Descriptor */ \ - 0x0d, /* bLength */ \ - 0x24, /* bDescriptorType : CS_INTERFACE */ \ - VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VC_HEADER subtype */ \ - WBVAL(bcdUVC), /* bcdUVC : Revision of class specification that this device is based upon.*/ \ - WBVAL(wTotalLength), /* wTotalLength */ \ - DBVAL(dwClockFrequency), /* dwClockFrequency : 0x005b8d80 -> 6,000,000 == 6MHz*/ \ - 0x01, /* bInCollection : Number of streaming interfaces. */ \ - (uint8_t)(bFirstInterface + 1), /* baInterfaceNr(0) : VideoStreaming interface 1 belongs to this VideoControl interface.*/ \ - /* Input Terminal 1 -> Processing Unit 2 -> Output Terminal 3 */ \ - 0x12, \ - 0x24, \ - VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \ - 0x01, /* bTerminalID */ \ - WBVAL(VIDEO_ITT_CAMERA), /* wTerminalType : 0x0201 Camera Sensor*/ \ - 0x00, /* bAssocTerminal */ \ - 0x00, /* iTerminal */ \ - WBVAL(0x0000), /* wObjectiveFocalLengthMin */ \ - WBVAL(0x0000), /* wObjectiveFocalLengthMax */ \ - WBVAL(0x0000), /* wOcularFocalLength */ \ - 0x03, /* bControlSize */ \ - 0x00, 0x00, 0x00, /* bmControls */ \ - 0x0c, \ - 0x24, \ - VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE, \ - 0x02, /* bUnitID */ \ - 0x01, /* bSourceID */ \ - 0x00, 0x00, /* wMaxMultiplier */ \ - 0x02, /* bControlSize */ \ - 0x00, 0x00, /* bmControls */ \ - 0x00, /* iProcessing */ \ - 0x00, /* bmVideoStandards */ \ - 0x09, \ - 0x24, \ - VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \ - 0x03, /* bTerminalID */ \ - WBVAL(VIDEO_TT_STREAMING), \ - 0x00, /* bAssocTerminal */ \ - 0x02, /* bSourceID */ \ - 0x00 /* iTerminal */ +#define VIDEO_VC_DESCRIPTOR_INIT(bFirstInterface, bEndpointAddress, bcdUVC, wTotalLength, dwClockFrequency, stridx) \ + /* Interface Association Descriptor */ \ + 0x08, \ + USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, \ + bFirstInterface, \ + 0x02, \ + USB_DEVICE_CLASS_VIDEO, \ + VIDEO_SC_VIDEO_INTERFACE_COLLECTION, \ + 0x00, \ + 0x00, /* VideoControl Interface Descriptor */ \ + 0x09, /* bLength */ \ + USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \ + 0x00, /* bInterfaceNumber */ \ + 0x00, /* bAlternateSetting */ \ + 0x01, /* bNumEndpoints:1 endpoint (interrupt endpoint) */ \ + USB_DEVICE_CLASS_VIDEO, /* bInterfaceClass : CC_VIDEO */ \ + VIDEO_SC_VIDEOCONTROL, /* bInterfaceSubClass : SC_VIDEOCONTROL */ \ + VIDEO_PC_PROTOCOL_UNDEFINED, /* bInterfaceProtocol : PC_PROTOCOL_UNDEFINED */ \ + stridx, /* iInterface:Index to string descriptor that contains the string */ /*Class-specific VideoControl Interface Descriptor */ \ + 0x0d, /* bLength */ \ + 0x24, /* bDescriptorType : CS_INTERFACE */ \ + VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VC_HEADER subtype */ \ + WBVAL(bcdUVC), /* bcdUVC : Revision of class specification that this device is based upon.*/ \ + WBVAL(wTotalLength), /* wTotalLength */ \ + DBVAL(dwClockFrequency), /* dwClockFrequency : 0x005b8d80 -> 6,000,000 == 6MHz*/ \ + 0x01, /* bInCollection : Number of streaming interfaces. */ \ + (uint8_t)(bFirstInterface + 1), /* baInterfaceNr(0) : VideoStreaming interface 1 belongs to this VideoControl interface.*/ /* Input Terminal 1 -> Processing Unit 2 -> Output Terminal 3 */ \ + 0x12, \ + 0x24, \ + VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \ + 0x01, /* bTerminalID */ \ + WBVAL(VIDEO_ITT_CAMERA), /* wTerminalType : 0x0201 Camera Sensor*/ \ + 0x00, /* bAssocTerminal */ \ + 0x00, /* iTerminal */ \ + WBVAL(0x0000), /* wObjectiveFocalLengthMin */ \ + WBVAL(0x0000), /* wObjectiveFocalLengthMax */ \ + WBVAL(0x0000), /* wOcularFocalLength */ \ + 0x03, /* bControlSize */ \ + 0x00, 0x00, 0x00, /* bmControls */ \ + 0x0c, \ + 0x24, \ + VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE, \ + 0x02, /* bUnitID */ \ + 0x01, /* bSourceID */ \ + 0x00, 0x00, /* wMaxMultiplier */ \ + 0x02, /* bControlSize */ \ + 0x00, 0x00, /* bmControls */ \ + 0x00, /* iProcessing */ \ + 0x00, /* bmVideoStandards */ \ + 0x09, \ + 0x24, \ + VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \ + 0x03, /* bTerminalID */ \ + WBVAL(VIDEO_TT_STREAMING), \ + 0x00, /* bAssocTerminal */ \ + 0x02, /* bSourceID */ \ + 0x00, /* iTerminal */ \ + 0x07, /* bLength */ \ + USB_DESCRIPTOR_TYPE_ENDPOINT, /* bDescriptorType */ \ + bEndpointAddress, /* bEndpointAddress */ \ + 0x03, /* bmAttributes */ \ + 0x10, 0x00, /* wMaxPacketSize */ \ + 0x08, /* bInterval */ \ + /* Class-specific VC Interrupt Endpoint Descriptor */ \ + 0x05, 0x25, 0x03, 0x10, 0x00 + +#define VIDEO_VC_NOEP_DESCRIPTOR_INIT(bFirstInterface, bEndpointAddress, bcdUVC, wTotalLength, dwClockFrequency, stridx) \ + /* Interface Association Descriptor */ \ + 0x08, \ + USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION, \ + bFirstInterface, \ + 0x02, \ + USB_DEVICE_CLASS_VIDEO, \ + VIDEO_SC_VIDEO_INTERFACE_COLLECTION, \ + 0x00, \ + 0x00, /* VideoControl Interface Descriptor */ \ + 0x09, /* bLength */ \ + USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType */ \ + 0x00, /* bInterfaceNumber */ \ + 0x00, /* bAlternateSetting */ \ + 0x00, /* bNumEndpoints:1 endpoint (interrupt endpoint) */ \ + USB_DEVICE_CLASS_VIDEO, /* bInterfaceClass : CC_VIDEO */ \ + VIDEO_SC_VIDEOCONTROL, /* bInterfaceSubClass : SC_VIDEOCONTROL */ \ + VIDEO_PC_PROTOCOL_UNDEFINED, /* bInterfaceProtocol : PC_PROTOCOL_UNDEFINED */ \ + stridx, /* iInterface:Index to string descriptor that contains the string */ /*Class-specific VideoControl Interface Descriptor */ \ + 0x0d, /* bLength */ \ + 0x24, /* bDescriptorType : CS_INTERFACE */ \ + VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VC_HEADER subtype */ \ + WBVAL(bcdUVC), /* bcdUVC : Revision of class specification that this device is based upon.*/ \ + WBVAL(wTotalLength), /* wTotalLength */ \ + DBVAL(dwClockFrequency), /* dwClockFrequency : 0x005b8d80 -> 6,000,000 == 6MHz*/ \ + 0x01, /* bInCollection : Number of streaming interfaces. */ \ + (uint8_t)(bFirstInterface + 1), /* baInterfaceNr(0) : VideoStreaming interface 1 belongs to this VideoControl interface.*/ /* Input Terminal 1 -> Processing Unit 2 -> Output Terminal 3 */ \ + 0x12, \ + 0x24, \ + VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \ + 0x01, /* bTerminalID */ \ + WBVAL(VIDEO_ITT_CAMERA), /* wTerminalType : 0x0201 Camera Sensor*/ \ + 0x00, /* bAssocTerminal */ \ + 0x00, /* iTerminal */ \ + WBVAL(0x0000), /* wObjectiveFocalLengthMin */ \ + WBVAL(0x0000), /* wObjectiveFocalLengthMax */ \ + WBVAL(0x0000), /* wOcularFocalLength */ \ + 0x03, /* bControlSize */ \ + 0x00, 0x00, 0x00, /* bmControls */ \ + 0x0c, \ + 0x24, \ + VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE, \ + 0x02, /* bUnitID */ \ + 0x01, /* bSourceID */ \ + 0x00, 0x00, /* wMaxMultiplier */ \ + 0x02, /* bControlSize */ \ + 0x00, 0x00, /* bmControls */ \ + 0x00, /* iProcessing */ \ + 0x00, /* bmVideoStandards */ \ + 0x09, \ + 0x24, \ + VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE, \ + 0x03, /* bTerminalID */ \ + WBVAL(VIDEO_TT_STREAMING), \ + 0x00, /* bAssocTerminal */ \ + 0x02, /* bSourceID */ \ + 0x00 /* iTerminal */ \ #define VIDEO_VS_DESCRIPTOR_INIT(bInterfaceNumber, bAlternateSetting, bNumEndpoints) \ /* Video Streaming (VS) Interface Descriptor */ \ - 0x09, /* bLength */ \ + 0x09, /* bLength */ \ USB_DESCRIPTOR_TYPE_INTERFACE, /* bDescriptorType : INTERFACE */ \ bInterfaceNumber, /* bInterfaceNumber: Index of this interface */ \ bAlternateSetting, /* bAlternateSetting: Index of this alternate setting */ \ @@ -1118,21 +1224,37 @@ struct video_autoexposure_mode { 0x00, /* bInterfaceProtocol : PC_PROTOCOL_UNDEFINED */ \ 0x00 /* iInterface : unused */ -#define VIDEO_VS_HEADER_DESCRIPTOR_INIT(bNumFormats, wTotalLength, bEndpointAddress, ...) \ - /*Class-specific VideoStream Header Descriptor (Input) */ \ - 0x0d + PP_NARG(__VA_ARGS__), \ - 0x24, \ - VIDEO_VS_INPUT_HEADER_DESCRIPTOR_SUBTYPE, \ - bNumFormats, /* bNumFormats : One format descriptor follows. */ \ - WBVAL(wTotalLength), \ - bEndpointAddress, \ - 0x00, /* bmInfo : No dynamic format change supported. */ \ - 0x03, /* bTerminalLink : This VideoStreaming interface supplies terminal ID 2 (Output Terminal). */ \ - 0x00, /* bStillCaptureMethod : Device supports still image capture method 0. */ \ - 0x00, /* bTriggerSupport : Hardware trigger supported for still image capture */ \ - 0x00, /* bTriggerUsage : Hardware trigger should initiate a still image capture. */ \ - PP_NARG(__VA_ARGS__), /* bControlSize : Size of the bmaControls field */ \ - __VA_ARGS__ /* bmaControls : No VideoStreaming specific controls are supported.*/ +#define VIDEO_VS_INPUT_HEADER_DESCRIPTOR_INIT(bNumFormats, wTotalLength, bEndpointAddress, ...) \ + /*Class-specific VideoStream Header Descriptor (Input) */ \ + 0x0d + PP_NARG(__VA_ARGS__), \ + 0x24, \ + VIDEO_VS_INPUT_HEADER_DESCRIPTOR_SUBTYPE, \ + bNumFormats, /* bNumFormats : One format descriptor follows. */ \ + WBVAL(wTotalLength), \ + bEndpointAddress, \ + 0x00, /* bmInfo : No dynamic format change supported. */ \ + 0x03, /* bTerminalLink : This VideoStreaming interface supplies terminal ID 2 (Output Terminal). */ \ + 0x00, /* bStillCaptureMethod : Device supports still image capture method 0. */ \ + 0x00, /* bTriggerSupport : Hardware trigger supported for still image capture */ \ + 0x00, /* bTriggerUsage : Hardware trigger should initiate a still image capture. */ \ + 0x01, /* bControlSize : Size of the bmaControls field */ \ + __VA_ARGS__ /* bmaControls : No VideoStreaming specific controls are supported.*/ + +#define VIDEO_VS_OUTPUT_HEADER_DESCRIPTOR_INIT(bNumFormats, wTotalLength, bEndpointAddress, ...) \ + /*Class-specific VideoStream Header Descriptor (Input) */ \ + 0x0d + PP_NARG(__VA_ARGS__), \ + 0x24, \ + VIDEO_VS_OUTPUT_HEADER_DESCRIPTOR_SUBTYPE, \ + bNumFormats, /* bNumFormats : One format descriptor follows. */ \ + WBVAL(wTotalLength), \ + bEndpointAddress, \ + 0x00, /* bmInfo : No dynamic format change supported. */ \ + 0x03, /* bTerminalLink : This VideoStreaming interface supplies terminal ID 2 (Output Terminal). */ \ + 0x00, /* bStillCaptureMethod : Device supports still image capture method 0. */ \ + 0x00, /* bTriggerSupport : Hardware trigger supported for still image capture */ \ + 0x00, /* bTriggerUsage : Hardware trigger should initiate a still image capture. */ \ + PP_NARG(__VA_ARGS__), /* bControlSize : Size of the bmaControls field */ \ + __VA_ARGS__ /* bmaControls : No VideoStreaming specific controls are supported.*/ #define VIDEO_VS_FORMAT_UNCOMPRESSED_DESCRIPTOR_INIT(bFormatIndex, bNumFrameDescriptors, GUIDFormat) \ /*Payload Format(UNCOMPRESSED) Descriptor */ \ @@ -1142,7 +1264,7 @@ struct video_autoexposure_mode { bFormatIndex, /* bFormatIndex : First (and only) format descriptor */ \ bNumFrameDescriptors, /* bNumFrameDescriptors : One frame descriptor for this format follows. */ \ GUIDFormat, /* GUID Format YUY2 {32595559-0000-0010-8000-00AA00389B71} */ \ - 0x0c, /* bBitsPerPixel : Number of bits per pixel used to specify color in the decoded video frame - 16 for yuy2*/ \ + 0x10, /* bBitsPerPixel : Number of bits per pixel used to specify color in the decoded video frame - 16 for yuy2*/ \ 0x01, /* bDefaultFrameIndex : Default frame index is 1. */ \ 0x00, /* bAspectRatioX : Non-interlaced stream not required. */ \ 0x00, /* bAspectRatioY : Non-interlaced stream not required. */ \ @@ -1150,8 +1272,8 @@ struct video_autoexposure_mode { 0x00 /* bCopyProtect : No restrictions imposed on the duplication of this video stream. */ #define VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_INIT(bFrameIndex, wWidth, wHeight, dwMinBitRate, dwMaxBitRate, \ - dwMaxVideoFrameBufferSize, dwDefaultFrameInterval, dwFrameInterval) \ - 0x1e, \ + dwMaxVideoFrameBufferSize, dwDefaultFrameInterval, bFrameIntervalType, ...) \ + 0x1a + PP_NARG(__VA_ARGS__), \ 0x24, \ VIDEO_VS_FRAME_UNCOMPRESSED_DESCRIPTOR_SUBTYPE, \ bFrameIndex, \ @@ -1161,13 +1283,13 @@ struct video_autoexposure_mode { DBVAL(dwMinBitRate), \ DBVAL(dwMaxBitRate), \ DBVAL(dwMaxVideoFrameBufferSize), \ - DBVAL(dwDefaultFrameInterval), \ - 0x01, \ - DBVAL(dwFrameInterval) + dwDefaultFrameInterval, /* dwDefaultFrameInterval : 1,000,000 * 100ns -> 10 FPS */ \ + bFrameIntervalType, /* bFrameIntervalType : Indicates how the frame interval can be programmed. 0: Continuous frame interval 1..255: The number of discrete frame */ \ + __VA_ARGS__ #define VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_INIT(bFormatIndex, bNumFrameDescriptors) \ /*Payload Format(MJPEG) Descriptor */ \ - 0x0b, /* bLength */ \ + 0x0b, /* bLength */ \ 0x24, /* bDescriptorType : CS_INTERFACE */ \ 0x06, /* bDescriptorSubType : VS_FORMAT_MJPEG subtype */ \ bFormatIndex, /* bFormatIndex : First (and only) format descriptor */ \ @@ -1181,7 +1303,7 @@ struct video_autoexposure_mode { #define VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_INIT(bFrameIndex, wWidth, wHeight, dwMinBitRate, dwMaxBitRate, \ dwMaxVideoFrameBufferSize, dwDefaultFrameInterval, bFrameIntervalType, ...) \ - 0x1a + PP_NARG(__VA_ARGS__), /* bLength */ \ + 0x1a + PP_NARG(__VA_ARGS__), /* bLength */ \ 0x24, /* bDescriptorType : CS_INTERFACE */ \ VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VS_FRAME_MJPEG */ \ bFrameIndex, /* bFrameIndex : First (and only) frame descriptor */ \ @@ -1194,5 +1316,50 @@ struct video_autoexposure_mode { dwDefaultFrameInterval, /* dwDefaultFrameInterval : 1,000,000 * 100ns -> 10 FPS */ \ bFrameIntervalType, /* bFrameIntervalType : Indicates how the frame interval can be programmed. 0: Continuous frame interval 1..255: The number of discrete frame */ \ __VA_ARGS__ + +#define VIDEO_VS_FORMAT_H264_DESCRIPTOR_INIT(bFormatIndex, bNumFrameDescriptors) \ + /*Payload Format(H264) Descriptor */ \ + 0x1c, /* bLength */ \ + 0x24, /* bDescriptorType : CS_INTERFACE */ \ + 0x10, /* bDescriptorSubType : VS_FORMAT_FRAME_BASED subtype */ \ + bFormatIndex, /* bFormatIndex : First (and only) format descriptor */ \ + bNumFrameDescriptors, /* bNumFrameDescriptors : One frame descriptor for this format follows. */ /* guidFormat {34363248-0000-0010-8000-00AA00389B71}(H264) */ \ + 0x48, 0x32, 0x36, 0x34, \ + 0x00, 0x00, \ + 0x10, 0x00, \ + 0x80, 0x00, \ + 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71, \ + 0x10, /* bBitsPerPixel */ \ + 0x01, /* bDefaultFrameIndex : Default frame index is 1. */ \ + 0x00, /* bAspectRatioX : Non-interlaced stream – not required. */ \ + 0x00, /* bAspectRatioY : Non-interlaced stream – not required. */ \ + 0x00, /* bmInterlaceFlags : Non-interlaced stream */ \ + 0x00, /* bCopyProtect : No restrictions imposed on the duplication of this video stream. */ \ + 0x01 /* bVariableSize */ + +#define VIDEO_VS_FRAME_H264_DESCRIPTOR_INIT(bFrameIndex, wWidth, wHeight, dwMinBitRate, dwMaxBitRate, \ + dwDefaultFrameInterval, bFrameIntervalType, ...) \ + 0x1a + PP_NARG(__VA_ARGS__), /* bLength */ \ + 0x24, /* bDescriptorType : CS_INTERFACE */ \ + VIDEO_VS_FRAME_FRAME_BASED_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VS_FRAME_BASED */ \ + bFrameIndex, /* bFrameIndex : First (and only) frame descriptor */ \ + 0x00, /* bmCapabilities : Still images using capture method 0 are supported at this frame setting.D1: Fixed frame-rate. */ \ + WBVAL(wWidth), /* wWidth (2bytes): Width of frame is 128 pixels. */ \ + WBVAL(wHeight), /* wHeight (2bytes): Height of frame is 64 pixels. */ \ + DBVAL(dwMinBitRate), /* dwMinBitRate (4bytes): Min bit rate in bits/s */ \ + DBVAL(dwMaxBitRate), /* dwMaxBitRate (4bytes): Max bit rate in bits/s */ \ + dwDefaultFrameInterval, /* dwDefaultFrameInterval : 1,000,000 * 100ns -> 10 FPS */ \ + bFrameIntervalType, /* bFrameIntervalType : Indicates how the frame interval can be programmed. 0: Continuous frame interval 1..255: The number of discrete frame */ \ + DBVAL(0x00), /* dwBytesPerLine (4bytes) */ \ + __VA_ARGS__ + +#define VIDEO_VS_COLOR_MATCHING_DESCRIPTOR_INIT() \ + 0x06, /* bLength */ \ + 0x24, /* bDescriptorType : CS_INTERFACE */ \ + VIDEO_VS_COLORFORMAT_DESCRIPTOR_SUBTYPE, /* bDescriptorSubType : VS_COLORFORMAT */ \ + 0x01, /* bColorPrimaries */ \ + 0x01, /* bTransferCharacteristics */ \ + 0x04 /* bMatrixCoefficients */ + // clang-format on #endif /*USB_VIDEO_H */ \ No newline at end of file diff --git a/demo/CherryUSB.h264 b/demo/CherryUSB.h264 new file mode 100644 index 0000000000000000000000000000000000000000..93d8ccf1c9d8b6a543d708208d7bbdac44d09295 GIT binary patch literal 20750 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 literal 0 HcmV?d00001 diff --git a/demo/CherryUSB.jpg b/demo/CherryUSB.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0943f55583253927816ddf44377a95549f52d62 GIT binary patch literal 24775 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.|000000000Y00}-167}00}00}00000000001111111110-0}00}/5};/}00}R111111111.}.|000000000~Z//}*~5|/~7}//}/1}002*2000104000541)01,2}22}17}9.}22}R000000000.}.|0000000002000000000000RVgsDq/Tlu^/,00000000000.000000000.}.}0000000000000000000000000000000000-00+0000000000000000000000.}UXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXS~rwakakakakakakakakakakakakakakhpmhhhhhhhhhhhhhhwrwakakakakakakakakakakakakakakhpmhhhhhhhhhhhhhhwqwakakbkksipinkshkiphpgnckakakhmmhhkƓqlpsm“pmkhhhwtzdidididhdhdidhcidhdhdidididignniiihihhhhiiiiizx|pupupupupupupupupupupupupupuqvvuuuuuuuuuuuuuu{~~000003000004000000000000000000-00000ā/00000^/000000}~01.5030/0-1400./.00++.1004-400-02010Ā/0+240^/00+000~0-50309h314001.00dрU100,