diff --git a/class/video/usbd_video.c b/class/video/usbd_video.c index b4d24a08..e5b134bf 100644 --- a/class/video/usbd_video.c +++ b/class/video/usbd_video.c @@ -19,9 +19,12 @@ struct usbd_video_priv { uint8_t error_code; struct video_entity_info info[3]; uint8_t *ep_buffer; + uint32_t max_packets; uint8_t *stream_buf; uint32_t stream_len; uint32_t stream_offset; + uint8_t stream_frameid; + uint32_t stream_headerlen; } g_usbd_video[CONFIG_USBDEV_MAX_BUS]; static int usbd_video_control_request_handler(uint8_t busid, struct usb_setup_packet *setup, uint8_t **data, uint32_t *len) @@ -741,6 +744,9 @@ static void usbd_video_probe_and_commit_controls_init(uint8_t busid, uint32_t dw g_usbd_video[busid].commit.bPreferedVersion = 0; g_usbd_video[busid].commit.bMinVersion = 0; g_usbd_video[busid].commit.bMaxVersion = 0; + + g_usbd_video[busid].stream_frameid = 0; + g_usbd_video[busid].stream_headerlen = 2; } struct usbd_interface *usbd_video_init_intf(uint8_t busid, @@ -770,76 +776,60 @@ struct usbd_interface *usbd_video_init_intf(uint8_t busid, bool usbd_video_stream_split_transfer(uint8_t busid, uint8_t ep) { - struct video_payload_header *header = (struct video_payload_header *)g_usbd_video[busid].ep_buffer; + struct video_payload_header *header; uint32_t remain; uint32_t len; + uint32_t offset; remain = g_usbd_video[busid].stream_len - g_usbd_video[busid].stream_offset; if (remain == 0) { + g_usbd_video[busid].stream_frameid ^= 1; return true; } - header->bHeaderLength = 2; - header->headerInfoUnion.headerInfoBits.endOfHeader = 1; + len = MIN(remain, (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - g_usbd_video[busid].stream_headerlen) * g_usbd_video[busid].max_packets); + + offset = 0; + while (len > 0) { + header = (struct video_payload_header *)&g_usbd_video[busid].ep_buffer[offset]; + header->bHeaderLength = g_usbd_video[busid].stream_headerlen; + header->headerInfoUnion.bmheaderInfo = 0; + header->headerInfoUnion.headerInfoBits.endOfHeader = 1; + header->headerInfoUnion.headerInfoBits.endOfFrame = 0; + header->headerInfoUnion.headerInfoBits.frameIdentifier = g_usbd_video[busid].stream_frameid; + + uint32_t len2 = MIN(len, g_usbd_video[busid].probe.dwMaxPayloadTransferSize - g_usbd_video[busid].stream_headerlen); - len = MIN(remain, g_usbd_video[busid].probe.dwMaxPayloadTransferSize - header->bHeaderLength); - memcpy(&g_usbd_video[busid].ep_buffer[header->bHeaderLength], - &g_usbd_video[busid].stream_buf[g_usbd_video[busid].stream_offset], - len); + memcpy(&g_usbd_video[busid].ep_buffer[offset + g_usbd_video[busid].stream_headerlen], + &g_usbd_video[busid].stream_buf[g_usbd_video[busid].stream_offset], + len2); - g_usbd_video[busid].stream_offset += len; + g_usbd_video[busid].stream_offset += len2; + len -= len2; + offset += (len2 + g_usbd_video[busid].stream_headerlen); - if (g_usbd_video[busid].stream_offset == g_usbd_video[busid].stream_len) { - header->headerInfoUnion.headerInfoBits.endOfFrame = 1; + if (g_usbd_video[busid].stream_offset == g_usbd_video[busid].stream_len) { + header->headerInfoUnion.headerInfoBits.endOfFrame = 1; + } } - usbd_ep_start_write(busid, ep, g_usbd_video[busid].ep_buffer, len + header->bHeaderLength); + usbd_ep_start_write(busid, ep, g_usbd_video[busid].ep_buffer, offset); return false; } -int usbd_video_stream_start_write(uint8_t busid, uint8_t ep, uint8_t *ep_buffer, uint8_t *buf, uint32_t len) +int usbd_video_stream_start_write(uint8_t busid, uint8_t ep, uint8_t *ep_buffer, uint32_t ep_bufsize, uint8_t *stream_buf, uint32_t stream_len) { if (usb_device_is_configured(busid) == 0) { return -1; } g_usbd_video[busid].ep_buffer = ep_buffer; - g_usbd_video[busid].stream_buf = buf; - g_usbd_video[busid].stream_len = len; + g_usbd_video[busid].max_packets = ep_bufsize / g_usbd_video[busid].probe.dwMaxPayloadTransferSize; + g_usbd_video[busid].stream_buf = stream_buf; + g_usbd_video[busid].stream_len = stream_len; g_usbd_video[busid].stream_offset = 0; - struct video_payload_header *header = (struct video_payload_header *)g_usbd_video[busid].ep_buffer; - - header->headerInfoUnion.headerInfoBits.frameIdentifier ^= 1; - header->headerInfoUnion.headerInfoBits.endOfFrame = 0; - usbd_video_stream_split_transfer(busid, ep); return 0; -} - -uint32_t usbd_video_payload_fill(uint8_t busid, uint8_t *input, uint32_t input_len, uint8_t *output, uint32_t *out_len) -{ - uint32_t packets; - uint32_t last_packet_size; - uint32_t picture_pos = 0; - static uint8_t uvc_header[2] = { 0x02, 0x80 }; - - packets = (input_len + (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2)) / (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2); - last_packet_size = input_len - ((packets - 1) * (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2)); - - for (size_t i = 0; i < packets; i++) { - output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i] = uvc_header[0]; - output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i + 1] = uvc_header[1]; - if (i == (packets - 1)) { - memcpy(&output[2 + g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i], &input[picture_pos], last_packet_size); - output[g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i + 1] |= (1 << 1); - } else { - memcpy(&output[2 + g_usbd_video[busid].probe.dwMaxPayloadTransferSize * i], &input[picture_pos], g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2); - picture_pos += g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2; - } - } - uvc_header[1] ^= 1; - *out_len = (input_len + 2 * packets); - return packets; } \ No newline at end of file diff --git a/class/video/usbd_video.h b/class/video/usbd_video.h index 24855c89..75f9dfca 100644 --- a/class/video/usbd_video.h +++ b/class/video/usbd_video.h @@ -22,9 +22,7 @@ void usbd_video_open(uint8_t busid, uint8_t intf); void usbd_video_close(uint8_t busid, uint8_t intf); bool usbd_video_stream_split_transfer(uint8_t busid, uint8_t ep); -int usbd_video_stream_start_write(uint8_t busid, uint8_t ep, uint8_t *ep_buffer, uint8_t *buf, uint32_t len); - -uint32_t usbd_video_payload_fill(uint8_t busid, uint8_t *input, uint32_t input_len, uint8_t *output, uint32_t *out_len); +int usbd_video_stream_start_write(uint8_t busid, uint8_t ep, uint8_t *ep_buffer, uint32_t ep_bufsize, uint8_t *stream_buf, uint32_t stream_len); #ifdef __cplusplus } diff --git a/demo/video_audiov1_hid_template.c b/demo/video_audiov1_hid_template.c index bccffeac..7972e7ef 100644 --- a/demo/video_audiov1_hid_template.c +++ b/demo/video_audiov1_hid_template.c @@ -9,6 +9,8 @@ #include "usbd_hid.h" #include "cherryusb_mjpeg.h" +#define MAX_PACKETS_IN_ONE_TRANSFER 1 + #define VIDEO_IN_EP 0x81 #define VIDEO_INT_EP 0x86 @@ -267,7 +269,7 @@ static const uint8_t hid_keyboard_report_desc[HID_KEYBOARD_REPORT_DESC_SIZE] = { USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t audio_read_buffer[AUDIO_OUT_PACKET]; USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t audio_write_buffer[AUDIO_IN_PACKET]; -USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t video_packet_buffer[40 * 1024]; +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t video_packet_buffer[MAX_PACKETS_IN_ONE_TRANSFER * MAX_PAYLOAD_SIZE]; volatile bool video_tx_flag = 0; volatile bool audio_tx_flag = 0; @@ -331,8 +333,10 @@ void usbd_video_close(uint8_t busid, uint8_t intf) void usbd_video_iso_callback(uint8_t busid, uint8_t ep, uint32_t nbytes) { - //USB_LOG_RAW("actual in len:%d\r\n", nbytes); - video_iso_tx_busy = false; + if (usbd_video_stream_split_transfer(busid, ep)) { + /* one frame has done */ + video_iso_tx_busy = false; + } } static struct usbd_endpoint video_in_ep = { @@ -471,44 +475,17 @@ void hid_keyboard_test(uint8_t busid) void video_test(uint8_t busid) { - uint32_t out_len; - uint32_t packets; + memset(video_packet_buffer, 0, sizeof(video_packet_buffer)); - (void)packets; - memset(video_packet_buffer, 0, 40 * 1024); while (1) { if (video_tx_flag) { - packets = usbd_video_payload_fill(busid, (uint8_t *)cherryusb_mjpeg, sizeof(cherryusb_mjpeg), video_packet_buffer, &out_len); -#if 1 video_iso_tx_busy = true; - usbd_ep_start_write(busid, VIDEO_IN_EP, video_packet_buffer, out_len); + usbd_video_stream_start_write(busid, VIDEO_IN_EP, video_packet_buffer, MAX_PACKETS_IN_ONE_TRANSFER * MAX_PAYLOAD_SIZE, (uint8_t *)cherryusb_mjpeg, sizeof(cherryusb_mjpeg)); while (video_iso_tx_busy) { if (video_tx_flag == 0) { break; } } -#else - /* dwc2 must use this method */ - for (uint32_t i = 0; i < packets; i++) { - if (i == (packets - 1)) { - video_iso_tx_busy = true; - usbd_ep_start_write(busid, VIDEO_IN_EP, &video_packet_buffer[i * MAX_PAYLOAD_SIZE], out_len - (packets - 1) * MAX_PAYLOAD_SIZE); - while (video_iso_tx_busy) { - if (video_tx_flag == 0) { - break; - } - } - } else { - video_iso_tx_busy = true; - usbd_ep_start_write(busid, VIDEO_IN_EP, &video_packet_buffer[i * MAX_PAYLOAD_SIZE], MAX_PAYLOAD_SIZE); - while (video_iso_tx_busy) { - if (video_tx_flag == 0) { - break; - } - } - } - } -#endif } } } \ No newline at end of file diff --git a/demo/video_static_h264_template.c b/demo/video_static_h264_template.c index 376068ed..caed10aa 100644 --- a/demo/video_static_h264_template.c +++ b/demo/video_static_h264_template.c @@ -7,6 +7,8 @@ #include "usbd_video.h" #include "cherryusb_h264.h" +#define MAX_PACKETS_IN_ONE_TRANSFER 1 + #define VIDEO_IN_EP 0x81 #define VIDEO_INT_EP 0x83 @@ -180,8 +182,10 @@ void usbd_video_close(uint8_t busid, uint8_t intf) void usbd_video_iso_callback(uint8_t busid, uint8_t ep, uint32_t nbytes) { - //USB_LOG_RAW("actual in len:%d\r\n", nbytes); - iso_tx_busy = false; + if (usbd_video_stream_split_transfer(busid, ep)) { + /* one frame has done */ + iso_tx_busy = false; + } } static struct usbd_endpoint video_in_ep = { @@ -213,37 +217,14 @@ void video_test(uint8_t busid) memset(packet_buffer, 0, 40 * 1024); while (1) { if (tx_flag) { - packets = usbd_video_payload_fill(busid, (uint8_t *)cherryusb_h264, sizeof(cherryusb_h264), packet_buffer, &out_len); -#if 1 iso_tx_busy = true; - usbd_ep_start_write(busid, VIDEO_IN_EP, packet_buffer, out_len); + usbd_video_stream_start_write(busid, VIDEO_IN_EP, packet_buffer, MAX_PACKETS_IN_ONE_TRANSFER * MAX_PAYLOAD_SIZE, (uint8_t *)cherryusb_h264, sizeof(cherryusb_h264)); while (iso_tx_busy) { if (tx_flag == 0) { break; } } -#else - /* dwc2 must use this method */ - for (uint32_t i = 0; i < packets; i++) { - if (i == (packets - 1)) { - iso_tx_busy = true; - usbd_ep_start_write(busid, VIDEO_IN_EP, &packet_buffer[i * MAX_PAYLOAD_SIZE], out_len - (packets - 1) * MAX_PAYLOAD_SIZE); - while (iso_tx_busy) { - if (tx_flag == 0) { - break; - } - } - } else { - iso_tx_busy = true; - usbd_ep_start_write(busid, VIDEO_IN_EP, &packet_buffer[i * MAX_PAYLOAD_SIZE], MAX_PAYLOAD_SIZE); - while (iso_tx_busy) { - if (tx_flag == 0) { - break; - } - } - } - } -#endif + } } } } \ No newline at end of file diff --git a/demo/video_static_mjpeg_template.c b/demo/video_static_mjpeg_template.c index 51a44226..8c9b4a51 100644 --- a/demo/video_static_mjpeg_template.c +++ b/demo/video_static_mjpeg_template.c @@ -7,7 +7,7 @@ #include "usbd_video.h" #include "cherryusb_mjpeg.h" -#define VIDEO_STREAM_SPLIT_ENABLE 1 +#define MAX_PACKETS_IN_ONE_TRANSFER 1 #define VIDEO_IN_EP 0x81 #define VIDEO_INT_EP 0x83 @@ -182,14 +182,10 @@ void usbd_video_close(uint8_t busid, uint8_t intf) void usbd_video_iso_callback(uint8_t busid, uint8_t ep, uint32_t nbytes) { -#if VIDEO_STREAM_SPLIT_ENABLE if (usbd_video_stream_split_transfer(busid, ep)) { /* one frame has done */ iso_tx_busy = false; } -#else - iso_tx_busy = false; -#endif } static struct usbd_endpoint video_in_ep = { @@ -210,42 +206,21 @@ void video_init(uint8_t busid, uintptr_t reg_base) usbd_initialize(busid, reg_base, usbd_event_handler); } -#if VIDEO_STREAM_SPLIT_ENABLE -USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t packet_buffer[MAX_PAYLOAD_SIZE]; -#else -USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t packet_buffer[40 * 1024]; -#endif +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t packet_buffer[MAX_PACKETS_IN_ONE_TRANSFER * MAX_PAYLOAD_SIZE]; void video_test(uint8_t busid) { - uint32_t out_len; - uint32_t packets; - - (void)packets; - (void)out_len; memset(packet_buffer, 0, sizeof(packet_buffer)); while (1) { if (tx_flag) { -#if VIDEO_STREAM_SPLIT_ENABLE iso_tx_busy = true; - usbd_video_stream_start_write(busid, VIDEO_IN_EP, packet_buffer, (uint8_t *)cherryusb_mjpeg, sizeof(cherryusb_mjpeg)); + usbd_video_stream_start_write(busid, VIDEO_IN_EP, packet_buffer, MAX_PACKETS_IN_ONE_TRANSFER * MAX_PAYLOAD_SIZE, (uint8_t *)cherryusb_mjpeg, sizeof(cherryusb_mjpeg)); while (iso_tx_busy) { if (tx_flag == 0) { break; } } -#else - packets = usbd_video_payload_fill(busid, (uint8_t *)cherryusb_mjpeg, sizeof(cherryusb_mjpeg), packet_buffer, &out_len); - - iso_tx_busy = true; - usbd_ep_start_write(busid, VIDEO_IN_EP, packet_buffer, out_len); - while (iso_tx_busy) { - if (tx_flag == 0) { - break; - } - } -#endif } } } \ No newline at end of file diff --git a/demo/video_static_yuyv_template.c b/demo/video_static_yuyv_template.c index f90344d1..a83dbbd6 100644 --- a/demo/video_static_yuyv_template.c +++ b/demo/video_static_yuyv_template.c @@ -7,6 +7,8 @@ #include "usbd_video.h" #include "cherryusb_yuyv.h" +#define MAX_PACKETS_IN_ONE_TRANSFER 1 + #define VIDEO_IN_EP 0x81 #define VIDEO_INT_EP 0x83 @@ -182,8 +184,10 @@ void usbd_video_close(uint8_t busid, uint8_t intf) void usbd_video_iso_callback(uint8_t busid, uint8_t ep, uint32_t nbytes) { - //USB_LOG_RAW("actual in len:%d\r\n", nbytes); - iso_tx_busy = false; + if (usbd_video_stream_split_transfer(busid, ep)) { + /* one frame has done */ + iso_tx_busy = false; + } } static struct usbd_endpoint video_in_ep = { @@ -204,48 +208,21 @@ void video_init(uint8_t busid, uintptr_t reg_base) usbd_initialize(busid, reg_base, usbd_event_handler); } -USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t packet_buffer[40 * 1024]; +USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t packet_buffer[MAX_PACKETS_IN_ONE_TRANSFER * MAX_PAYLOAD_SIZE]; void video_test(uint8_t busid) { - uint32_t out_len; - uint32_t packets; + memset(packet_buffer, 0, sizeof(packet_buffer)); - (void)packets; - memset(packet_buffer, 0, 40 * 1024); while (1) { if (tx_flag) { - packets = usbd_video_payload_fill(busid, (uint8_t *)cherryusb_yuyv, sizeof(cherryusb_yuyv), packet_buffer, &out_len); -#if 1 iso_tx_busy = true; - usbd_ep_start_write(busid, VIDEO_IN_EP, packet_buffer, out_len); + usbd_video_stream_start_write(busid, VIDEO_IN_EP, packet_buffer, MAX_PACKETS_IN_ONE_TRANSFER * MAX_PAYLOAD_SIZE, (uint8_t *)cherryusb_yuyv, sizeof(cherryusb_yuyv)); while (iso_tx_busy) { if (tx_flag == 0) { break; } } -#else - /* dwc2 must use this method */ - for (uint32_t i = 0; i < packets; i++) { - if (i == (packets - 1)) { - iso_tx_busy = true; - usbd_ep_start_write(busid, VIDEO_IN_EP, &packet_buffer[i * MAX_PAYLOAD_SIZE], out_len - (packets - 1) * MAX_PAYLOAD_SIZE); - while (iso_tx_busy) { - if (tx_flag == 0) { - break; - } - } - } else { - iso_tx_busy = true; - usbd_ep_start_write(busid, VIDEO_IN_EP, &packet_buffer[i * MAX_PAYLOAD_SIZE], MAX_PAYLOAD_SIZE); - while (iso_tx_busy) { - if (tx_flag == 0) { - break; - } - } - } - } -#endif } } } \ No newline at end of file