Files
TAIXIN/sdk/lib/bus/rttusb/usbdevice/class/usbd_video.c

2272 lines
110 KiB
C
Raw Permalink Normal View History

/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <rtthread.h>
#ifdef RT_USB_DEVICE_VIDEO
#include "include/rttusb_device.h"
#include "usbd_video.h"
#include "stream_define.h"
#include "video_app_h264_msi.h"
#include "jpg_concat_msi.h"
#define CONFIG_USB_HS //默认设置为USB HS模式
#ifdef CONFIG_USB_HS
#define MAX_PAYLOAD_SIZE 1024 // for high speed with one transcations every one micro frame
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
// #define MAX_PAYLOAD_SIZE 2048 // for high speed with two transcations every one micro frame
// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 2)) | (0x01 << 11))
// #define MAX_PAYLOAD_SIZE 3072 // for high speed with three transcations every one micro frame
// #define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 3)) | (0x02 << 11))
#else
#define MAX_PAYLOAD_SIZE 1020
#define VIDEO_PACKET_SIZE (unsigned int)(((MAX_PAYLOAD_SIZE / 1)) | (0x00 << 11))
#endif
#define VIDEO_IN_EP 0x81
/* --------- Video MJPEG Format --------- */
#define VIDEO_MJPEG_bNumFrameDescriptors (2)
#if VIDEO_MJPEG_bNumFrameDescriptors >= 1
#define VIDEO_MJPEG_Frame1_WIDTH (unsigned int)(640)
#define VIDEO_MJPEG_Frame1_HEIGHT (unsigned int)(360)
#endif
#if VIDEO_MJPEG_bNumFrameDescriptors >= 2
#define VIDEO_MJPEG_Frame2_WIDTH (unsigned int)(1280)
#define VIDEO_MJPEG_Frame2_HEIGHT (unsigned int)(720)
#endif
/* --------- Video H26x Format --------- */
#define VIDEO_H26x__bNumFrameDescriptors (2)
#if VIDEO_H26x__bNumFrameDescriptors >= 1
#define VIDEO_H26x_Frame1_WIDTH (unsigned int)(1280)
#define VIDEO_H26x_Frame1_HEIGHT (unsigned int)(720)
#endif
#if VIDEO_H26x__bNumFrameDescriptors >= 2
#define VIDEO_H26x_Frame2_WIDTH (unsigned int)(1920)
#define VIDEO_H26x_Frame2_HEIGHT (unsigned int)(1080)
#endif
#define CAM_FPS (30)
#define INTERVAL (unsigned long)(10000000 / CAM_FPS)
#define MIN_BIT_RATE(width, height) (unsigned long)(width * height * 16 * CAM_FPS) //16 bit
#define MAX_BIT_RATE(width, height) (unsigned long)(width * height * 16 * CAM_FPS)
#define MAX_FRAME_SIZE(width, height) (unsigned long)(width * height * 2)
#define UVC_MAX_PACKET_SIZE 64
#define UVC_INTF_STR_INDEX 0x02
#define VIDEO_BUFFER_SZ MAX_PAYLOAD_SIZE //USB发送缓存大小
#define EVENT_VIDEO_START (1 << 0)
#define EVENT_VIDEO_STOP (1 << 1)
#define EVENT_VIDEO_DATA (1 << 2)
#define EVENT_VIDEO_COMPLITE (1 << 3)
#define CONFIG_USBDEV_MAX_BUS 1
static struct usbd_video_priv g_usbd_video[CONFIG_USBDEV_MAX_BUS];
static struct uvc_class_device usbd_uvc;
struct uvc_vc_noep_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
struct uiad_descriptor iad_desc;
#endif
struct uinterface_descriptor intf_desc;
struct video_cs_if_vc_header_descriptor hdr_desc;
struct video_cs_if_vc_input_terminal_descriptor it_desc;
struct video_cs_if_vc_processing_unit_descriptor pu_desc;
struct video_cs_if_vc_output_terminal_descriptor ot_desc;
};
struct uvc_vs_noep_descriptor
{
struct uinterface_descriptor intf_desc;
struct video_cs_if_vs_input_header_descriptor it_desc;
#if VIDEO_MJPEG_bNumFrameDescriptors >= 1
struct video_cs_if_vs_format_mjpeg_descriptor fmt_desc;
struct video_cs_if_vs_frame_mjpeg_descriptor frame_desc;
#endif
#if VIDEO_MJPEG_bNumFrameDescriptors >= 2
struct video_cs_if_vs_frame_mjpeg_descriptor frame2_desc;
#endif
#if VIDEO_H26x__bNumFrameDescriptors >= 1
struct video_cs_if_vs_format_h26x_descriptor h264_desc;
struct video_cs_if_vs_frame_h26x_descriptor h264_frame_desc;
#endif
#if VIDEO_H26x__bNumFrameDescriptors >= 2
struct video_cs_if_vs_frame_h26x_descriptor h264_frame2_desc;
#endif
};
struct uvc_vs_ep_descriptor
{
struct uinterface_descriptor intf_desc;
struct uendpoint_descriptor ep_desc;
};
rt_align(4)
static struct udevice_descriptor dev_desc =
{
USB_DESC_LENGTH_DEVICE, //bLength;
USB_DESC_TYPE_DEVICE, //type;
USB_BCD_VERSION, //bcdUSB;
USB_CLASS_MISC, //bDeviceClass;
0x02, //bDeviceSubClass;
0x01, //bDeviceProtocol;
UVC_MAX_PACKET_SIZE, //bMaxPacketSize0;
_VENDOR_ID, //idVendor;
_PRODUCT_ID, //idProduct;
USB_BCD_DEVICE, //bcdDevice;
USB_STRING_MANU_INDEX, //iManufacturer;
USB_STRING_PRODUCT_INDEX, //iProduct;
USB_STRING_SERIAL_INDEX, //iSerialNumber;Unused.
0x00, //bNumConfigurations;
};
//FS and HS needed
rt_align(4)
static struct usb_qualifier_descriptor dev_qualifier =
{
sizeof(dev_qualifier), //bLength
USB_DESC_TYPE_DEVICEQUALIFIER, //bDescriptorType
0x0200, //bcdUSB
USB_CLASS_VIDEO, //bDeviceClass
0x00, //bDeviceSubClass
0x00, //bDeviceProtocol
64, //bMaxPacketSize0
0x01, //bNumConfigurations
0,
};
rt_align(4)
const static char *_ustring[] =
{
"Language",
"USBZH", //"Cherry USB",
"USB2.0 Camera", //"USB Composite Device",
"20240411",
};
rt_align(4)
static struct uvc_vc_noep_descriptor vc_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
{
USB_DESC_LENGTH_IAD,
USB_DESC_TYPE_IAD,
USB_DYNAMIC,
0x02,
USB_CLASS_VIDEO,
VIDEO_SC_VIDEO_INTERFACE_COLLECTION,
0x00,
0x00,
},
#endif
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
USB_DYNAMIC,
0x00,
0x00,
USB_CLASS_VIDEO,
VIDEO_SC_VIDEOCONTROL,
VIDEO_PC_PROTOCOL_UNDEFINED,
#ifdef RT_USB_DEVICE_COMPOSITE
UVC_INTF_STR_INDEX,
#else
0x00,
#endif
},
/* Header Descriptor */
{
sizeof(struct video_cs_if_vc_header_descriptor), //0x0d,
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE,
0x0100,
VIDEO_VC_TERMINAL_LEN,
48000000,
0x01,
{0x01},
},
/* Input Terminal Descriptor */
{
sizeof(struct video_cs_if_vc_input_terminal_descriptor), //0x12,
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE,
0x01,
VIDEO_ITT_CAMERA,
0x00,
0x00,
0x0000,
0x0000,
0x0000,
0x03,
{0x00, 0x00, 0x00},
},
/* Processing Unit Descriptor */
{
sizeof(struct video_cs_if_vc_processing_unit_descriptor), //0x0c,
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE,
0x02,
0x01,
0x0000,
0x02,
{0xFF,0xFF},
0x00,
0x00,
},
/* Output Terminal Descriptor */
{
sizeof(struct video_cs_if_vc_output_terminal_descriptor), //0x09,
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE,
0x03,
VIDEO_TT_STREAMING,
0x00,
0x02,
0x00,
},
};
#define VIDEO_VS_INPUT_HEADER_DESC_LEN (sizeof(struct video_cs_if_vs_input_header_descriptor))
#if (VIDEO_MJPEG_bNumFrameDescriptors >= 1)
#define VIDEO_MJPEG_HEADER_LEN (sizeof(struct video_cs_if_vs_format_mjpeg_descriptor) + \
sizeof(struct video_cs_if_vs_frame_mjpeg_descriptor) * VIDEO_MJPEG_bNumFrameDescriptors)
#else
#define VIDEO_MJPEG_HEADER_LEN 0
#endif
#if (VIDEO_H26x__bNumFrameDescriptors >= 1)
#define VIDEO_H26X_HEADER_LEN (sizeof(struct video_cs_if_vs_format_h26x_descriptor) + \
sizeof(struct video_cs_if_vs_frame_h26x_descriptor) * VIDEO_H26x__bNumFrameDescriptors)
#else
#define VIDEO_H26X_HEADER_LEN 0
#endif
#define VIDEO_VS_INPUT_HEADER_wTotalLength (VIDEO_VS_INPUT_HEADER_DESC_LEN + VIDEO_MJPEG_HEADER_LEN + VIDEO_H26X_HEADER_LEN)
#define VIDEO_VS_INPUT_HEADER_bNumFormats ( ((VIDEO_MJPEG_bNumFrameDescriptors) ? 1 : 0) + \
((VIDEO_H26x__bNumFrameDescriptors) ? 1 : 0) )
#define VIDEO_VS_INPUT_HEADER_bControlSize ((VIDEO_VS_INPUT_HEADER_bNumFormats >= 2) ? 1 : 2)
rt_align(4)
static struct uvc_vs_noep_descriptor vs_noep_desc =
{
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
0x01,
0x00,
0x00,
USB_CLASS_VIDEO,
VIDEO_SC_VIDEOSTREAMING,
0x00,
0x00,
},
/* Header Descriptor */
{
sizeof(struct video_cs_if_vs_input_header_descriptor), //0x0d,
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
VIDEO_VS_INPUT_HEADER_DESCRIPTOR_SUBTYPE,
VIDEO_VS_INPUT_HEADER_bNumFormats,
VIDEO_VS_INPUT_HEADER_wTotalLength,
VIDEO_IN_EP,
0x00,
0x03,
0x00,
0x00,
0x00,
VIDEO_VS_INPUT_HEADER_bControlSize,
{0x00,0x00},/* bmaControls : No VideoStreaming specific controls are supported.*/
},
#if VIDEO_MJPEG_bNumFrameDescriptors >= 1
/* VS Format Descriptor */
{
sizeof(struct video_cs_if_vs_format_mjpeg_descriptor), //0x0b,
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
VIDEO_VS_FORMAT_MJPEG_DESCRIPTOR_SUBTYPE,
0x01,
VIDEO_MJPEG_bNumFrameDescriptors,
0x00,
0x01,
0x00,
0x00,
0x00,
0x00,
},
/* VS Frame 640x360 Descriptor */
{
sizeof(struct video_cs_if_vs_frame_mjpeg_descriptor), //0x1a,
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_SUBTYPE,
0x01,
0x00,
VIDEO_MJPEG_Frame1_WIDTH,
VIDEO_MJPEG_Frame1_HEIGHT,
MIN_BIT_RATE(VIDEO_MJPEG_Frame1_WIDTH,VIDEO_MJPEG_Frame1_HEIGHT),
MAX_BIT_RATE(VIDEO_MJPEG_Frame1_WIDTH,VIDEO_MJPEG_Frame1_HEIGHT),
MAX_FRAME_SIZE(VIDEO_MJPEG_Frame1_WIDTH,VIDEO_MJPEG_Frame1_HEIGHT),
INTERVAL,
0x01,
{INTERVAL},
},
#endif
#if VIDEO_MJPEG_bNumFrameDescriptors >= 2
/* VS Frame 1280x720 Descriptor */
{
sizeof(struct video_cs_if_vs_frame_mjpeg_descriptor), //0x1a,
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE,
VIDEO_VS_FRAME_MJPEG_DESCRIPTOR_SUBTYPE,
0x02,
0x00,
VIDEO_MJPEG_Frame2_WIDTH,
VIDEO_MJPEG_Frame2_HEIGHT,
MIN_BIT_RATE(VIDEO_MJPEG_Frame2_WIDTH,VIDEO_MJPEG_Frame2_HEIGHT),
MAX_BIT_RATE(VIDEO_MJPEG_Frame2_WIDTH,VIDEO_MJPEG_Frame2_HEIGHT),
MAX_FRAME_SIZE(VIDEO_MJPEG_Frame2_WIDTH,VIDEO_MJPEG_Frame2_HEIGHT),
INTERVAL,
0x01,
{INTERVAL},
},
#endif
#if VIDEO_H26x__bNumFrameDescriptors >= 1
/* VS H264 Format Descriptor */
{
sizeof(struct video_cs_if_vs_format_h26x_descriptor), //bLength
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE, //bDescriptorType
VIDEO_VS_FORMAT_FRAME_BASED_DESCRIPTOR_SUBTYPE, //bDescriptorSubType
0x02, //bFormatIndex
VIDEO_H26x__bNumFrameDescriptors, //bNumFrameDescriptors
{VIDEO_GUID_H264}, //guidFormat[16]
0x00, //bBitsPerPixel
0x01, //bDefaultFrameIndex
0x00, //bAspectRatioX
0x00, //bAspectRatioY
0x00, //bmInterfaceFlags
0x00, //bCopyProtect
0x01, //bVariableSize
},
/* VS Frame 1280x720 Descriptor */
{
sizeof(struct video_cs_if_vs_frame_h26x_descriptor), //bLength
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE, //bDescriptorType
VIDEO_VS_FRAME_FRAME_BASED_DESCRIPTOR_SUBTYPE, //bDescriptorSubType
0x01, //bFrameIndex
0x00, //bmCapabilities
VIDEO_H26x_Frame1_WIDTH, //wWidth
VIDEO_H26x_Frame1_HEIGHT, //wHeight
MIN_BIT_RATE(VIDEO_H26x_Frame1_WIDTH, VIDEO_H26x_Frame1_HEIGHT), //dwMinBitRate
MAX_BIT_RATE(VIDEO_H26x_Frame1_WIDTH, VIDEO_H26x_Frame1_HEIGHT), //dwMaxBitRate
INTERVAL, //dwDefaultFrameInterval
0x01, //bFrameIntervalType
0x00, //dwBytesPerLine
{INTERVAL}, //dwFrameInterval
},
#endif
#if VIDEO_H26x__bNumFrameDescriptors >= 2
/* VS Frame 1920x1080 Descriptor */
{
sizeof(struct video_cs_if_vs_frame_h26x_descriptor), //bLength
VIDEO_CS_INTERFACE_DESCRIPTOR_TYPE, //bDescriptorType
VIDEO_VS_FRAME_FRAME_BASED_DESCRIPTOR_SUBTYPE, //bDescriptorSubType
0x02, //bFrameIndex
0x00, //bmCapabilities
VIDEO_H26x_Frame2_WIDTH, //wWidth
VIDEO_H26x_Frame2_HEIGHT, //wHeight
MIN_BIT_RATE(VIDEO_H26x_Frame2_WIDTH, VIDEO_H26x_Frame2_HEIGHT), //dwMinBitRate
MAX_BIT_RATE(VIDEO_H26x_Frame2_WIDTH, VIDEO_H26x_Frame2_HEIGHT), //dwMaxBitRate
INTERVAL, //dwDefaultFrameInterval
0x01, //bFrameIntervalType
0x00, //dwBytesPerLine
{INTERVAL}, //dwFrameInterval
},
#endif
};
rt_align(4)
static struct uvc_vs_ep_descriptor vs_ep_desc =
{
/* Interface Descriptor */
{
USB_DESC_LENGTH_INTERFACE,
USB_DESC_TYPE_INTERFACE,
0x01,
0x01,
0x01,
USB_CLASS_VIDEO,
VIDEO_SC_VIDEOSTREAMING,
0x00,
0x00,
},
/* Endpoint Descriptor */
{
USB_DESC_LENGTH_ENDPOINT,
USB_DESC_TYPE_ENDPOINT,
USB_DYNAMIC | USB_DIR_IN,
0x05,
VIDEO_PACKET_SIZE,
0x01,
},
};
static rt_err_t rt_usbd_video_send_msg(struct usbd_video_msg *msg)
{
return rt_mq_send(&g_usbd_video[0].video_mq, (void*)msg, sizeof(struct usbd_video_msg));
}
static rt_err_t rt_usbd_video_recv_msg(struct usbd_video_msg *msg)
{
return rt_mq_recv(&g_usbd_video[0].video_mq, msg, sizeof(struct usbd_video_msg), 100);
}
static rt_err_t _ep0_cmd_handler(udevice_t device, rt_size_t size)
{
struct usbd_video_msg msg;
LOG_D("_ep0_cmd_handler");
if(rt_usbd_video_recv_msg(&msg) < 0)
{
os_printf("%s %d: Not recv msg!\n");
}
else
{
if((msg.flush_info_addr != RT_NULL) && (msg.dma_buff != RT_NULL) && (msg.copy_len != 0))
{
memcpy(msg.flush_info_addr, msg.dma_buff, msg.copy_len);
}
}
dcd_ep0_send_status(device->dcd);
return RT_EOK;
}
static rt_bool_t usbd_video_control_request_handler(rt_uint8_t busid, ufunction_t func, ureq_t setup)
{
rt_uint8_t control_selector = (rt_uint8_t)(setup->wValue >> 8);
static rt_uint8_t buf[26] __attribute__((aligned(4)));
os_printf("%s %d\n",__FUNCTION__,__LINE__);
switch (control_selector) {
case VIDEO_VC_VIDEO_POWER_MODE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR:
break;
case VIDEO_REQUEST_GET_CUR:
break;
case VIDEO_REQUEST_GET_INFO:
break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_VC_REQUEST_ERROR_CODE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_GET_CUR:
buf[0] = 0x06;
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
break;
case VIDEO_REQUEST_GET_INFO:
break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
default:
break;
}
return 0;
}
static rt_bool_t usbd_video_control_unit_terminal_request_handler(rt_uint8_t busid, ufunction_t func, ureq_t setup)
{
rt_uint8_t entity_id = (rt_uint8_t)(setup->wIndex >> 8);
rt_uint8_t control_selector = (rt_uint8_t)(setup->wValue >> 8);
struct usbd_video_msg msg;
static rt_uint8_t data[26] __attribute__((aligned(4)));
for (rt_uint8_t i = 0; i < 3; i++) {
struct video_entity_info *entity_info = &g_usbd_video[busid].info[i];
if (entity_info->bEntityId == entity_id) {
switch (entity_info->bDescriptorSubtype) {
case VIDEO_VC_HEADER_DESCRIPTOR_SUBTYPE:
break;
case VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE:
if (entity_info->wTerminalType == VIDEO_ITT_CAMERA) {
switch (control_selector) {
case VIDEO_CT_AE_MODE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_GET_CUR:
data[0] = 0x08;
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_GET_CUR: {
rt_uint32_t dwExposureTimeAbsolute = 2500;
memcpy(data, (rt_uint8_t *)&dwExposureTimeAbsolute, 4);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint32_t dwExposureTimeAbsolute = 5; //0.0005sec
memcpy(data, (rt_uint8_t *)&dwExposureTimeAbsolute, 4);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint32_t dwExposureTimeAbsolute = 2500; //0.2500sec
memcpy(data, (rt_uint8_t *)&dwExposureTimeAbsolute, 4);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint32_t dwExposureTimeAbsolute = 5; //0.0005sec
memcpy(data, (rt_uint8_t *)&dwExposureTimeAbsolute, 4);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint32_t dwExposureTimeAbsolute = 2500; //0.2500sec
memcpy(data, (rt_uint8_t *)&dwExposureTimeAbsolute, 4);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_CT_FOCUS_ABSOLUTE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wFocusAbsolute = 0x0080;
memcpy(data, (rt_uint8_t *)&wFocusAbsolute, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wFocusAbsolute = 0;
memcpy(data, (rt_uint8_t *)&wFocusAbsolute, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wFocusAbsolute = 0x00ff;
memcpy(data, (rt_uint8_t *)&wFocusAbsolute, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wFocusAbsolute = 0x0001;
memcpy(data, (rt_uint8_t *)&wFocusAbsolute, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wFocusAbsolute = 0x0080;
memcpy(data, (rt_uint8_t *)&wFocusAbsolute, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_CT_ZOOM_ABSOLUTE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wObjectiveFocalLength = 0x0064;
memcpy(data, (rt_uint8_t *)&wObjectiveFocalLength, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wObjectiveFocalLength = 0x0064;
memcpy(data, (rt_uint8_t *)&wObjectiveFocalLength, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wObjectiveFocalLength = 0x00c8;
memcpy(data, (rt_uint8_t *)&wObjectiveFocalLength, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wObjectiveFocalLength = 0x0001;
memcpy(data, (rt_uint8_t *)&wObjectiveFocalLength, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wObjectiveFocalLength = 0x0064;
memcpy(data, (rt_uint8_t *)&wObjectiveFocalLength, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_CT_ROLL_ABSOLUTE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wRollAbsolute = 0x0000;
memcpy(data, (rt_uint8_t *)&wRollAbsolute, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wRollAbsolute = 0x0000;
memcpy(data, (rt_uint8_t *)&wRollAbsolute, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wRollAbsolute = 0x00ff;
memcpy(data, (rt_uint8_t *)&wRollAbsolute, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wRollAbsolute = 0x0001;
memcpy(data, (rt_uint8_t *)&wRollAbsolute, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wRollAbsolute = 0x0000;
memcpy(data, (rt_uint8_t *)&wRollAbsolute, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_CT_FOCUS_AUTO_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wFocusAuto = 0x0000;
memcpy(data, (rt_uint8_t *)&wFocusAuto, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
default:
LOG_D("Unhandled Video Class control selector 0x%02x\r\n", control_selector);
return -1;
}
} else {
LOG_D("Unhandled Video Class wTerminalType 0x%02x\r\n", entity_info->wTerminalType);
return -2;
}
break;
case VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE:
break;
case VIDEO_VC_SELECTOR_UNIT_DESCRIPTOR_SUBTYPE:
break;
case VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE:
switch (control_selector) {
case VIDEO_PU_BACKLIGHT_COMPENSATION_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wBacklightCompensation;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 2;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wBacklightCompensation = g_usbd_video[busid].process_unit_info.wBacklightCompensation;
memcpy(data, (rt_uint8_t *)&wBacklightCompensation, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wBacklightCompensation = 0;
memcpy(data, (rt_uint8_t *)&wBacklightCompensation, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wBacklightCompensation = 8;
memcpy(data, (rt_uint8_t *)&wBacklightCompensation, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wBacklightCompensation = 1;
memcpy(data, (rt_uint8_t *)&wBacklightCompensation, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wBacklightCompensation = 4;
memcpy(data, (rt_uint8_t *)&wBacklightCompensation, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_BRIGHTNESS_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
//rt_uint16_t wBrightness = (rt_uint16_t)(*data)[1] << 8 | (rt_uint16_t)(*data)[0];
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wBrightness;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 2;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wBrightness = g_usbd_video[busid].process_unit_info.wBrightness;
memcpy(data, (rt_uint8_t *)&wBrightness, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wBrightness = 0x0001;
memcpy(data, (rt_uint8_t *)&wBrightness, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wBrightness = 0x00ff;
memcpy(data, (rt_uint8_t *)&wBrightness, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wBrightness = 0x0001;
memcpy(data, (rt_uint8_t *)&wBrightness, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wBrightness = 0x0080;
memcpy(data, (rt_uint8_t *)&wBrightness, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_CONTRAST_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wContrast;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 2;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wContrast = g_usbd_video[busid].process_unit_info.wContrast;
memcpy(data, (rt_uint8_t *)&wContrast, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wContrast = 0x0001;
memcpy(data, (rt_uint8_t *)&wContrast, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wContrast = 0x00ff;
memcpy(data, (rt_uint8_t *)&wContrast, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wContrast = 0x0001;
memcpy(data, (rt_uint8_t *)&wContrast, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wContrast = 0x0080;
memcpy(data, (rt_uint8_t *)&wContrast, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_HUE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wHue;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 2;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wHue = g_usbd_video[busid].process_unit_info.wHue;
memcpy(data, (rt_uint8_t *)&wHue, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wHue = 0x0001;
memcpy(data, (rt_uint8_t *)&wHue, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wHue = 0x00ff;
memcpy(data, (rt_uint8_t *)&wHue, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wHue = 0x0001;
memcpy(data, (rt_uint8_t *)&wHue, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wHue = 0x0080;
memcpy(data, (rt_uint8_t *)&wHue, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_HUE_AUTO_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wHue_Auto;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 1;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wHue_Auto = g_usbd_video[busid].process_unit_info.wHue_Auto;
memcpy(data, (rt_uint8_t *)&wHue_Auto, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wHue_Auto = 0x0001;
memcpy(data, (rt_uint8_t *)&wHue_Auto, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO: {
data[0] = 0x0; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wHue_Auto = 0x0;
memcpy(data, (rt_uint8_t *)&wHue_Auto, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_SATURATION_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wSaturation;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 2;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wSaturation = g_usbd_video[busid].process_unit_info.wSaturation;
memcpy(data, (rt_uint8_t *)&wSaturation, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wSaturation = 0x0001;
memcpy(data, (rt_uint8_t *)&wSaturation, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wSaturation = 0x00ff;
memcpy(data, (rt_uint8_t *)&wSaturation, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wSaturation = 0x0001;
memcpy(data, (rt_uint8_t *)&wSaturation, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wSaturation = 0x0080;
memcpy(data, (rt_uint8_t *)&wSaturation, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_SHARPNESS_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wSharpness;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 2;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wSharpness = g_usbd_video[busid].process_unit_info.wSharpness;
memcpy(data, (rt_uint8_t *)&wSharpness, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wSharpness = 0x0001;
memcpy(data, (rt_uint8_t *)&wSharpness, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wSharpness = 0x00ff;
memcpy(data, (rt_uint8_t *)&wSharpness, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wSharpness = 0x0001;
memcpy(data, (rt_uint8_t *)&wSharpness, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wSharpness = 0x0080;
memcpy(data, (rt_uint8_t *)&wSharpness, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_GAMMA_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wGamma;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 2;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wGamma = g_usbd_video[busid].process_unit_info.wGamma;
memcpy(data, (rt_uint8_t *)&wGamma, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wGamma = 0x0001;
memcpy(data, (rt_uint8_t *)&wGamma, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wGamma = 0x0064;
memcpy(data, (rt_uint8_t *)&wGamma, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wGamma = 0x0001;
memcpy(data, (rt_uint8_t *)&wGamma, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wGamma = 0x0032;
memcpy(data, (rt_uint8_t *)&wGamma, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_GAIN_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wGain;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 2;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wGain = g_usbd_video[busid].process_unit_info.wGain;
memcpy(data, (rt_uint8_t *)&wGain, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wGain = 0;
memcpy(data, (rt_uint8_t *)&wGain, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wGain = 255;
memcpy(data, (rt_uint8_t *)&wGain, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wGain = 1;
memcpy(data, (rt_uint8_t *)&wGain, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wGain = 255;
memcpy(data, (rt_uint8_t *)&wGain, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_POWER_LINE_FREQUENCY_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.bPowerLineFrequency;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 1;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint8_t bPowerLineFrequency = g_usbd_video[busid].process_unit_info.bPowerLineFrequency;
memcpy(data, (rt_uint8_t *)&bPowerLineFrequency, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint8_t bPowerLineFrequency = 1;
memcpy(data, (rt_uint8_t *)&bPowerLineFrequency, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint8_t bPowerLineFrequency = 2;
memcpy(data, (rt_uint8_t *)&bPowerLineFrequency, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint8_t bPowerLineFrequency = 1;
memcpy(data, (rt_uint8_t *)&bPowerLineFrequency, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint8_t bPowerLineFrequency = 1;
memcpy(data, (rt_uint8_t *)&bPowerLineFrequency, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_WHITE_BALANCE_TEMPERATURE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wWhiteBalance_Temprature;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 2;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wWhiteBalance_Temprature = g_usbd_video[busid].process_unit_info.wWhiteBalance_Temprature;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wWhiteBalance_Temprature = 300;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wWhiteBalance_Temprature = 600;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wWhiteBalance_Temprature = 1;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO: {
data[0] = 0x03; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wWhiteBalance_Temprature = 417;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wWhiteBalance_Temprature_Auto;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 1;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wWhiteBalance_Temprature_Auto = g_usbd_video[busid].process_unit_info.wWhiteBalance_Temprature_Auto;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature_Auto, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_INFO: {
data[0] = 0x0; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wWhiteBalance_Temprature_Auto = 0;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Temprature_Auto, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_WHITE_BALANCE_COMPONENT_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wWhiteBalance_Component;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 4;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint32_t wWhiteBalance_Component = g_usbd_video[busid].process_unit_info.wWhiteBalance_Component;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Component, 4);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint32_t wWhiteBalance_Component = 5;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Component, 4);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint32_t wWhiteBalance_Component = 5;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Component, 4);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint32_t wWhiteBalance_Component = 5;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Component, 4);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x05; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint32_t wWhiteBalance_Component = 5;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Component, 4);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 4);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wWhiteBalance_Component_Auto;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 1;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wWhiteBalance_Component_Auto = g_usbd_video[busid].process_unit_info.wWhiteBalance_Component_Auto;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Component_Auto, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_INFO: {
data[0] = 0x0; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wWhiteBalance_Component_Auto = 0;
memcpy(data, (rt_uint8_t *)&wWhiteBalance_Component_Auto, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_DIGITAL_MULTIPLIER_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wDigital_Multiplier;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 2;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint16_t wDigital_Multiplier = g_usbd_video[busid].process_unit_info.wDigital_Multiplier;
memcpy(data, (rt_uint8_t *)&wDigital_Multiplier, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wDigital_Multiplier = 5;
memcpy(data, (rt_uint8_t *)&wDigital_Multiplier, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wDigital_Multiplier = 5;
memcpy(data, (rt_uint8_t *)&wDigital_Multiplier, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wDigital_Multiplier = 5;
memcpy(data, (rt_uint8_t *)&wDigital_Multiplier, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO:
data[0] = 0x05; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wDigital_Multiplier = 5;
memcpy(data, (rt_uint8_t *)&wDigital_Multiplier, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR: {
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&data, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].process_unit_info.wDigital_Multiplier_Limit;
msg.dma_buff = (rt_uint8_t *)&data;
msg.copy_len = 1;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
} break;
case VIDEO_REQUEST_GET_CUR: {
rt_uint8_t wDigital_Multiplier_Limit = g_usbd_video[busid].process_unit_info.wDigital_Multiplier_Limit;
memcpy(data, (rt_uint8_t *)&wDigital_Multiplier_Limit, 1);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_MIN: {
rt_uint16_t wDigital_Multiplier_Limit = 0;
memcpy(data, (rt_uint8_t *)&wDigital_Multiplier_Limit, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_MAX: {
rt_uint16_t wDigital_Multiplier_Limit = 5;
memcpy(data, (rt_uint8_t *)&wDigital_Multiplier_Limit, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_INFO: {
data[0] = 0x0; //struct video_camera_capabilities
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 1);
} break;
case VIDEO_REQUEST_GET_RES: {
rt_uint16_t wDigital_Multiplier_Limit = 0;
memcpy(data, (rt_uint8_t *)&wDigital_Multiplier_Limit, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
case VIDEO_REQUEST_GET_DEF: {
rt_uint16_t wDigital_Multiplier_Limit = 0;
memcpy(data, (rt_uint8_t *)&wDigital_Multiplier_Limit, 2);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)data, 2);
} break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
default:
g_usbd_video[busid].error_code = 0x06;
LOG_D("Unhandled Video Class control selector 0x%02x\r\n", control_selector);
return -1;
}
break;
case VIDEO_VC_EXTENSION_UNIT_DESCRIPTOR_SUBTYPE:
break;
case VIDEO_VC_ENCODING_UNIT_DESCRIPTOR_SUBTYPE:
break;
default:
break;
}
}
}
return 0;
}
static rt_uint32_t usbd_video_mjpeg_payload_fill(rt_uint8_t busid, rt_uint8_t *input, rt_uint32_t input_len, rt_uint8_t *output, rt_uint32_t *out_len)
{
rt_uint32_t packets;
rt_uint32_t last_packet_size;
rt_uint32_t picture_pos = 0;
static rt_uint8_t uvc_header[2] = { 0x02, 0x80 };
packets = (input_len + (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2) ) / (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2);
//os_printf("packets:%d input len:%d dwMaxPayloadSize:%d \n",packets,input_len,g_usbd_video[busid].probe.dwMaxPayloadTransferSize);
last_packet_size = input_len - ((packets - 1) * (g_usbd_video[busid].probe.dwMaxPayloadTransferSize - 2));
for (rt_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)) {
hw_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 {
hw_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;
}
static rt_uint32_t usbd_video_mjpeg_payload_header_fill(rt_uint8_t *input, rt_uint32_t input_len, rt_uint8_t *output, rt_uint8_t *uvc_header, rt_uint8_t uvc_header_len)
{
//os_printf("uvc header len:%d\n",uvc_header_len);
if(input_len < VIDEO_PACKET_SIZE - uvc_header_len) //2为header的长度
{
output[0] = uvc_header[0];
output[1] = uvc_header[1];
output[1] |= (1 << 1);
os_memcpy(&output[2], input, input_len);
uvc_header[1] ^= 1;
}
else
{
output[0] = uvc_header[0];
output[1] = uvc_header[1];
os_memcpy(&output[2], input, input_len);
}
return input_len + uvc_header_len;
}
static rt_err_t usbd_video_open(rt_uint8_t busid, ufunction_t func)
{
os_printf("usbd video open\r\n");
os_printf("g_usbd_video[busid].probe.bFormatIndex:%d\n",g_usbd_video[busid].probe.bFormatIndex);
switch((g_usbd_video[busid].probe.bFormatIndex))
{
case 1:
{
switch(g_usbd_video[busid].probe.bFrameIndex){
#if VIDEO_MJPEG_bNumFrameDescriptors >= 1
case 1:
os_printf("MJPEG set interface 360p\r\n");
if (g_usbd_video[busid].ops.mjpeg_set_resolution) {
g_usbd_video[busid].ops.mjpeg_set_resolution(1280, 720, VIDEO_MJPEG_Frame1_WIDTH, VIDEO_MJPEG_Frame1_HEIGHT, USBD_VIDEO_OPEN);
}
break;
#endif
#if VIDEO_MJPEG_bNumFrameDescriptors >= 2
case 2:
os_printf("MJPEG set interface 720p\r\n");
if (g_usbd_video[busid].ops.mjpeg_set_resolution) {
g_usbd_video[busid].ops.mjpeg_set_resolution(1280, 720, VIDEO_MJPEG_Frame2_WIDTH, VIDEO_MJPEG_Frame2_HEIGHT, USBD_VIDEO_OPEN);
}
break;
#endif
default:
break;
}
}
break;
case 2:
{
switch(g_usbd_video[busid].probe.bFrameIndex){
#if VIDEO_H26x__bNumFrameDescriptors >= 1
case 1:
os_printf("H264 set interface 720p\r\n");
if (g_usbd_video[busid].ops.h264_set_resolution) {
g_usbd_video[busid].ops.h264_set_resolution((uint32_t)RT_NULL, (uint32_t)RT_NULL, VIDEO_H26x_Frame1_WIDTH, VIDEO_H26x_Frame1_HEIGHT, USBD_VIDEO_OPEN);
}
break;
#endif
#if VIDEO_H26x__bNumFrameDescriptors >= 2
case 2:
os_printf("H264 set interface 1080p\r\n");
if (g_usbd_video[busid].ops.h264_set_resolution) {
g_usbd_video[busid].ops.h264_set_resolution((uint32_t)RT_NULL, (uint32_t)RT_NULL, VIDEO_H26x_Frame2_WIDTH, VIDEO_H26x_Frame2_HEIGHT, USBD_VIDEO_OPEN);
}
break;
#endif
default:
break;
}
}
break;
}
usbd_uvc.open_count = 0;
usbd_uvc.open_count++;
rt_event_send(usbd_uvc.event, EVENT_VIDEO_START | EVENT_VIDEO_DATA);
return 0;
}
static rt_err_t usbd_video_close(rt_uint8_t busid, ufunction_t func)
{
os_printf("usbd video close\r\n");
switch((g_usbd_video[busid].probe.bFormatIndex))
{
case 1:
{
switch(g_usbd_video[busid].probe.bFrameIndex){
#if VIDEO_MJPEG_bNumFrameDescriptors >= 1
case 1:
os_printf("MJPEG set interface 360p\r\n");
if (g_usbd_video[busid].ops.mjpeg_set_resolution) {
g_usbd_video[busid].ops.mjpeg_set_resolution((uint32_t)RT_NULL, (uint32_t)RT_NULL, (uint32_t)RT_NULL, (uint32_t)RT_NULL, USBD_VIDEO_CLOSE);
}
break;
#endif
#if VIDEO_MJPEG_bNumFrameDescriptors >= 2
case 2:
os_printf("MJPEG set interface 720p\r\n");
if (g_usbd_video[busid].ops.mjpeg_set_resolution) {
g_usbd_video[busid].ops.mjpeg_set_resolution((uint32_t)RT_NULL, (uint32_t)RT_NULL, (uint32_t)RT_NULL, (uint32_t)RT_NULL, USBD_VIDEO_CLOSE);
}
break;
#endif
default:
break;
}
}
break;
case 2:
{
switch(g_usbd_video[busid].probe.bFrameIndex){
#if VIDEO_H26x__bNumFrameDescriptors >= 1
case 1:
os_printf("H264 set interface 720p\r\n");
if (g_usbd_video[busid].ops.h264_set_resolution) {
g_usbd_video[busid].ops.h264_set_resolution((uint32_t)RT_NULL, (uint32_t)RT_NULL, (uint32_t)RT_NULL, (uint32_t)RT_NULL, USBD_VIDEO_CLOSE);
}
break;
#endif
#if VIDEO_H26x__bNumFrameDescriptors >= 2
case 2:
os_printf("H264 set interface 1080p\r\n");
if (g_usbd_video[busid].ops.h264_set_resolution) {
g_usbd_video[busid].ops.h264_set_resolution((uint32_t)RT_NULL, (uint32_t)RT_NULL, (uint32_t)RT_NULL, (uint32_t)RT_NULL, USBD_VIDEO_CLOSE);
}
break;
#endif
default:
break;
}
}
break;
}
usbd_uvc.open_count--;
rt_event_send(usbd_uvc.event, EVENT_VIDEO_STOP);
return 0;
}
static void usbd_video_process_unit_info_init(rt_uint8_t busid)
{
g_usbd_video[busid].process_unit_info.wWhiteBalance_Component = 5;
g_usbd_video[busid].process_unit_info.wBacklightCompensation = 0x0004;
g_usbd_video[busid].process_unit_info.wBrightness = 0x0080;
g_usbd_video[busid].process_unit_info.wContrast = 0x0080;
g_usbd_video[busid].process_unit_info.wHue = 0x0080;
g_usbd_video[busid].process_unit_info.wHue_Auto = 0;
g_usbd_video[busid].process_unit_info.wSaturation = 0x0001;
g_usbd_video[busid].process_unit_info.wSharpness = 0x0001;
g_usbd_video[busid].process_unit_info.wGamma = 0x0032;
g_usbd_video[busid].process_unit_info.wGain = 255;
g_usbd_video[busid].process_unit_info.wWhiteBalance_Temprature = 417;
g_usbd_video[busid].process_unit_info.wWhiteBalance_Temprature_Auto = 0;
g_usbd_video[busid].process_unit_info.wWhiteBalance_Component_Auto = 0;
g_usbd_video[busid].process_unit_info.wDigital_Multiplier = 5;
g_usbd_video[busid].process_unit_info.bPowerLineFrequency = 1;
g_usbd_video[busid].process_unit_info.wDigital_Multiplier_Limit = 1;
}
static void usbd_video_probe_and_commit_controls_init(rt_uint8_t busid, rt_uint32_t dwFrameInterval, rt_uint32_t dwMaxVideoFrameSize, rt_uint32_t dwMaxPayloadTransferSize)
{
g_usbd_video[busid].probe.hintUnion.bmHint = 0x01;
g_usbd_video[busid].probe.hintUnion1.bmHint = 0;
g_usbd_video[busid].probe.bFormatIndex = 1;
g_usbd_video[busid].probe.bFrameIndex = 1;
g_usbd_video[busid].probe.dwFrameInterval = dwFrameInterval;
g_usbd_video[busid].probe.wKeyFrameRate = 0;
g_usbd_video[busid].probe.wPFrameRate = 0;
g_usbd_video[busid].probe.wCompQuality = 0;
g_usbd_video[busid].probe.wCompWindowSize = 0;
g_usbd_video[busid].probe.wDelay = 0;
g_usbd_video[busid].probe.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
g_usbd_video[busid].probe.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
g_usbd_video[busid].probe.dwClockFrequency = 0;
g_usbd_video[busid].probe.bmFramingInfo = 0;
g_usbd_video[busid].probe.bPreferedVersion = 0;
g_usbd_video[busid].probe.bMinVersion = 0;
g_usbd_video[busid].probe.bMaxVersion = 0;
g_usbd_video[busid].commit.hintUnion.bmHint = 0x01;
g_usbd_video[busid].commit.hintUnion1.bmHint = 0;
g_usbd_video[busid].commit.bFormatIndex = 1;
g_usbd_video[busid].commit.bFrameIndex = 1;
g_usbd_video[busid].commit.dwFrameInterval = dwFrameInterval;
g_usbd_video[busid].commit.wKeyFrameRate = 0;
g_usbd_video[busid].commit.wPFrameRate = 0;
g_usbd_video[busid].commit.wCompQuality = 0;
g_usbd_video[busid].commit.wCompWindowSize = 0;
g_usbd_video[busid].commit.wDelay = 0;
g_usbd_video[busid].commit.dwMaxVideoFrameSize = dwMaxVideoFrameSize;
g_usbd_video[busid].commit.dwMaxPayloadTransferSize = dwMaxPayloadTransferSize;
g_usbd_video[busid].commit.dwClockFrequency = 0;
g_usbd_video[busid].commit.bmFramingInfo = 0;
g_usbd_video[busid].commit.bPreferedVersion = 0;
g_usbd_video[busid].commit.bMinVersion = 0;
g_usbd_video[busid].commit.bMaxVersion = 0;
}
static void usbd_video_init_intf(rt_uint8_t busid, rt_uint32_t dwFrameInterval, rt_uint32_t dwMaxVideoFrameSize, rt_uint32_t dwMaxPayloadTransferSize)
{
g_usbd_video[busid].info[0].bDescriptorSubtype = VIDEO_VC_INPUT_TERMINAL_DESCRIPTOR_SUBTYPE;
g_usbd_video[busid].info[0].bEntityId = 0x01;
g_usbd_video[busid].info[0].wTerminalType = VIDEO_ITT_CAMERA;
g_usbd_video[busid].info[1].bDescriptorSubtype = VIDEO_VC_OUTPUT_TERMINAL_DESCRIPTOR_SUBTYPE;
g_usbd_video[busid].info[1].bEntityId = 0x03;
g_usbd_video[busid].info[1].wTerminalType = 0x00;
g_usbd_video[busid].info[2].bDescriptorSubtype = VIDEO_VC_PROCESSING_UNIT_DESCRIPTOR_SUBTYPE;
g_usbd_video[busid].info[2].bEntityId = 0x02;
g_usbd_video[busid].info[2].wTerminalType = 0x00;
usbd_video_probe_and_commit_controls_init(busid, dwFrameInterval, dwMaxVideoFrameSize, dwMaxPayloadTransferSize);
usbd_video_process_unit_info_init(busid);
}
static rt_err_t _vc_interface_as_handler(ufunction_t func, ureq_t setup)
{
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
os_printf("_vc_interface_as_handler\n");
rt_uint8_t entity_id = (rt_uint8_t)(setup->wIndex >> 8);
rt_uint8_t busid = 0;
if (entity_id == 0) {
return usbd_video_control_request_handler(busid, func, setup); /* Interface Control Requests */
} else {
return usbd_video_control_unit_terminal_request_handler(busid, func, setup); /* Unit and Terminal Requests */
}
return RT_EOK;
}
static rt_err_t _vs_interface_as_handler(ufunction_t func, ureq_t setup)
{
RT_ASSERT(func != RT_NULL);
RT_ASSERT(func->device != RT_NULL);
RT_ASSERT(setup != RT_NULL);
struct usbd_video_msg msg;
rt_uint8_t control_selector = (rt_uint8_t)(setup->wValue >> 8);
rt_uint8_t busid = 0;
static rt_uint8_t buf[26] __attribute__((aligned(4)));
memset(buf, 0, 26);
os_printf("_vs_interface_as_handler\n");
os_printf("request_type:%x bRequest:%d control_selector:%d\n",(setup->request_type & USB_REQ_TYPE_MASK), setup->bRequest,control_selector);
#if 1
if ((setup->request_type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
{
switch (setup->bRequest)
{
case USB_REQ_GET_INTERFACE:
break;
case USB_REQ_SET_INTERFACE:
LOG_D("set interface handler");
if (setup->wValue == 1)
{
usbd_video_open(busid, func);
}
else if (setup->wValue == 0)
{
usbd_video_close(busid, func);
}
break;
default:
LOG_D("unknown uac request 0x%x", setup->bRequest);
return -RT_ERROR;
}
}else{
switch (control_selector) {
case VIDEO_VS_PROBE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR:
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&buf, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)&g_usbd_video[busid].probe;
msg.dma_buff = (rt_uint8_t *)&buf;
msg.copy_len = 18;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
os_printf("SET CUR FormatIndex:%x FrameIndex:%x buf[2]:%x %x\n",g_usbd_video[busid].probe.bFormatIndex,g_usbd_video[busid].probe.bFrameIndex,buf[2],buf[3]);
break;
case VIDEO_REQUEST_GET_CUR:
rt_usbd_ep0_write(func->device, (rt_uint8_t *)&g_usbd_video[busid].probe, setup->wLength);
//os_printf("GET CUR payloadsize:%d\n",g_usbd_video[busid].probe.dwMaxPayloadTransferSize);
break;
case VIDEO_REQUEST_GET_MIN:
case VIDEO_REQUEST_GET_MAX:
case VIDEO_REQUEST_GET_RES:
case VIDEO_REQUEST_GET_DEF:
rt_usbd_ep0_write(func->device, (rt_uint8_t *)&g_usbd_video[busid].probe, setup->wLength);
//os_printf("GET = payloadsize:%d\n",g_usbd_video[busid].probe.dwMaxPayloadTransferSize);
break;
case VIDEO_REQUEST_GET_LEN:
buf[0] = sizeof(struct video_probe_and_commit_controls);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
break;
case VIDEO_REQUEST_GET_INFO:;
buf[0] = 0x03;
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_VS_COMMIT_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_SET_CUR:
rt_usbd_ep0_read(func->device, (rt_uint8_t *)&g_usbd_video[busid].commit, setup->wLength, _ep0_cmd_handler);
msg.flush_info_addr = (rt_uint8_t *)RT_NULL;
msg.dma_buff = (rt_uint8_t *)RT_NULL;
msg.copy_len = 0;
msg.control_selector = control_selector;
rt_usbd_video_send_msg(&msg);
break;
case VIDEO_REQUEST_GET_CUR:
rt_usbd_ep0_write(func->device, (rt_uint8_t *)&g_usbd_video[busid].commit, setup->wLength);
break;
case VIDEO_REQUEST_GET_MIN:
case VIDEO_REQUEST_GET_MAX:
case VIDEO_REQUEST_GET_RES:
case VIDEO_REQUEST_GET_DEF:
rt_usbd_ep0_write(func->device, (rt_uint8_t *)&g_usbd_video[busid].commit, setup->wLength);
break;
case VIDEO_REQUEST_GET_LEN:
buf[0] = sizeof(struct video_probe_and_commit_controls);
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
break;
case VIDEO_REQUEST_GET_INFO:;
buf[0] = 0x03;
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
case VIDEO_VS_STREAM_ERROR_CODE_CONTROL:
switch (setup->bRequest) {
case VIDEO_REQUEST_GET_CUR:
buf[0] = g_usbd_video[busid].error_code;
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
break;
case VIDEO_REQUEST_GET_INFO:
buf[0] = 0x01;
rt_usbd_ep0_write(func->device, (rt_uint8_t *)buf, 1);
break;
default:
LOG_D("Unhandled Video Class bRequest 0x%02x\r\n", setup->bRequest);
return -1;
}
break;
default:
break;
}
}
#endif
return RT_EOK;
}
static rt_err_t _ep_data_handler(ufunction_t func, rt_size_t size)
{
RT_ASSERT(func != RT_NULL);
rt_event_send(usbd_uvc.event, EVENT_VIDEO_DATA);
return RT_EOK;
}
static rt_err_t _function_enable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
rt_mq_init(&g_usbd_video[0].video_mq, "video_message", RT_NULL, 32, 16, RT_IPC_FLAG_FIFO);
os_printf("uvc function enable");
return RT_EOK;
}
static rt_err_t _function_disable(ufunction_t func)
{
RT_ASSERT(func != RT_NULL);
rt_mq_detach(&g_usbd_video[0].video_mq);
os_printf("uvc function disable");
return RT_EOK;
}
static struct ufunction_ops ops =
{
_function_enable,
_function_disable,
RT_NULL,
};
/**
* This function will configure uvc descriptor.
*
* @param comm the communication interface number.
* @param data the data interface number.
*
* @return RT_EOK on successful.
*/
static rt_err_t _uvc_descriptor_config(struct uvc_vc_noep_descriptor *vc,
rt_uint8_t cintf_nr, struct uvc_vs_noep_descriptor *vs, rt_uint8_t sintf_nr)
{
vc->hdr_desc.baInterfaceNr[0] = sintf_nr;
#ifdef RT_USB_DEVICE_COMPOSITE
vc->iad_desc.bFirstInterface = cintf_nr;
#endif
return RT_EOK;
}
static void usbd_uvc_entry(void *parameter)
{
rt_uint32_t e;
rt_uint32_t flen = 0;
rt_uint32_t node_len = 0;
rt_uint32_t out_len;
rt_uint32_t packets;
rt_uint32_t timeout = 0;
rt_uint32_t index = 0;
rt_uint8_t *frame_buf_addr = NULL;
struct framebuff *get_f = NULL;
struct ufunction *func = (struct ufunction *)parameter;
static rt_uint8_t uvc_header[2] = { 0x02, 0x80 };
usbd_uvc.buffer = os_malloc(VIDEO_BUFFER_SZ);
if (usbd_uvc.buffer == RT_NULL)
{
LOG_E("malloc failed\r\n");
goto __exit;
}
struct msi *s = msi_new(R_USBD_VIDEO, 2, NULL);
if(s == RT_NULL)
{
LOG_D("open stream failed\n");
goto __exit;
}
usbd_uvc.recv_msi = s;
while(1)
{
if (rt_event_recv(usbd_uvc.event, EVENT_VIDEO_START | EVENT_VIDEO_STOP,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
1000, &e) != RT_EOK)
{
printf("usbd video wait evevnt\r\n");
continue;
}
if (e & EVENT_VIDEO_START)
{
}else
{
continue;
}
LOG_D("video display start\r\n");
while(1){
if (get_f == NULL)
{
get_f = msi_get_fb(s, 0);
}
flen = 0;
if(get_f)
{
// printf("U len : %d type:%d", get_f->len, get_f->stype);
flen = get_f->len;
node_len = get_f->len;
frame_buf_addr = get_f->data;
packets = 0;
out_len = 0;
while(flen)
{
if (rt_event_recv(usbd_uvc.event, EVENT_VIDEO_DATA | EVENT_VIDEO_STOP,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
1000, &e) != RT_EOK)
{
//一般为上位机软件视频处于暂停状态主机未发出IN请求从机等待DMA中断
os_printf(KERN_DEBUG"uvc_video_thread: recv event timeout\n");
}
if (e & EVENT_VIDEO_STOP)
{
_os_printf("P");
flen = 0;
index = 0;
timeout = 0;
break;
}
if (e & EVENT_VIDEO_DATA)
{
//printf("D");
if(flen > (VIDEO_PACKET_SIZE-sizeof(uvc_header)))
{
out_len = usbd_video_mjpeg_payload_header_fill((rt_uint8_t *)(frame_buf_addr + index), (VIDEO_PACKET_SIZE-sizeof(uvc_header)), usbd_uvc.buffer, (rt_uint8_t*)&uvc_header,sizeof(uvc_header));
//os_printf("1 out len:%d buffer:%x [0]:%x [1]:%x [2]:%x [3]:%x\n",out_len,frame_buf_addr + index, usbd_uvc.buffer[0], usbd_uvc.buffer[1],usbd_uvc.buffer[2],usbd_uvc.buffer[3]);
usbd_uvc.ep->request.buffer = usbd_uvc.buffer;
usbd_uvc.ep->request.size = VIDEO_PACKET_SIZE;
usbd_uvc.ep->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, usbd_uvc.ep, &usbd_uvc.ep->request);
flen -= (VIDEO_PACKET_SIZE-sizeof(uvc_header));
index += (VIDEO_PACKET_SIZE-sizeof(uvc_header));
}else{
out_len = usbd_video_mjpeg_payload_header_fill((rt_uint8_t *)(frame_buf_addr + index), flen, usbd_uvc.buffer, (rt_uint8_t*)&uvc_header,sizeof(uvc_header));
// os_printf("2 out len:%d buffer:%x [0]:%x [1]:%x [2]:%x [3]:%x\n",out_len,frame_buf_addr + index, usbd_uvc.buffer[0], usbd_uvc.buffer[1],usbd_uvc.buffer[2],usbd_uvc.buffer[3]);
usbd_uvc.ep->request.buffer = usbd_uvc.buffer;
usbd_uvc.ep->request.size = out_len;
usbd_uvc.ep->request.req_type = UIO_REQUEST_WRITE;
rt_usbd_io_request(func->device, usbd_uvc.ep, &usbd_uvc.ep->request);
flen = 0;
index = 0;
break;
}
}
}
if(get_f)
{
msi_delete_fb(NULL, get_f);
get_f = NULL;
}
timeout = 0;
}
else
{
timeout++;
_os_printf("n");
os_sleep_ms(5);
if(timeout > 100)
{
//通知设置分辨率的线程可重新打开硬件msi
s->enable = 0;
rt_event_send(usbd_uvc.event, EVENT_VIDEO_COMPLITE);
timeout = 0;
break;
}
}
}
}
__exit:
if (usbd_uvc.buffer)
{
os_free(usbd_uvc.buffer);
}
if (s)
{
usbd_uvc.recv_msi = RT_NULL;
msi_destroy(s);
}
}
/**
* This function will create a uvc function instance.
*
* @param device the usb device object.
*
* @return RT_EOK on successful.
*/
static ufunction_t rt_usbd_function_uvc_device_create(udevice_t device)
{
ufunction_t func;
uintf_t intf_vc, intf_vs;
ualtsetting_t setting_vs_noep;
ualtsetting_t setting_vc, setting_vs_ep;
struct uvc_vs_ep_descriptor *vs_ep_desc_t;
/* parameter check */
RT_ASSERT(device != RT_NULL);
#ifdef RT_USB_DEVICE_COMPOSITE
rt_usbd_device_set_interface_string(device, UVC_INTF_STR_INDEX, _ustring[2]);
#else
/* set usb device string description */
rt_usbd_device_set_string(device, _ustring);
#endif
/* create a uac function */
func = rt_usbd_function_new(device, &dev_desc, &ops);
//not support HS
//rt_usbd_device_set_qualifier(device, &dev_qualifier);
usbd_uvc_init(func);
/* create interface */
intf_vc = rt_usbd_interface_new(device, _vc_interface_as_handler); //配置接口handler
intf_vs = rt_usbd_interface_new(device, _vs_interface_as_handler); //配置接口handler
// os_printf("===sizeof:%d %d %d\n",sizeof(struct uvc_vc_noep_descriptor),sizeof(struct uvc_vs_noep_descriptor),sizeof(struct uvc_vs_ep_descriptor));
/* create alternate setting */
setting_vc = rt_usbd_altsetting_new(sizeof(struct uvc_vc_noep_descriptor));
setting_vs_noep = rt_usbd_altsetting_new(sizeof(struct uvc_vs_noep_descriptor));
setting_vs_ep = rt_usbd_altsetting_new(sizeof(struct uvc_vs_ep_descriptor));
/* config desc in alternate setting */
rt_usbd_altsetting_config_descriptor(setting_vc, &vc_desc,
(rt_off_t) & ((struct uvc_vc_noep_descriptor *)0)->intf_desc);
// os_printf("intf_desc[0]:%x\n",&(vc_desc.intf_desc));
rt_usbd_altsetting_config_descriptor(setting_vs_noep, &vs_noep_desc,
(rt_off_t) & ((struct uvc_vs_noep_descriptor *)0)->intf_desc);
rt_usbd_altsetting_config_descriptor(setting_vs_ep, &vs_ep_desc,
(rt_off_t) & ((struct uvc_vs_ep_descriptor *)0)->intf_desc);
/* configure the uac interface descriptor */
_uvc_descriptor_config(setting_vc->desc, intf_vc->intf_num, setting_vs_noep->desc, intf_vs->intf_num);
//_uac_samplerate_config(setting_vs_ep->desc, AUDIO_SAMPLERATE);
/* create endpoint */
vs_ep_desc_t = (struct uvc_vs_ep_descriptor *)setting_vs_ep->desc;
usbd_uvc.ep = rt_usbd_endpoint_new(&vs_ep_desc_t->ep_desc, _ep_data_handler); //配置端点handler
/* add the endpoint to the alternate setting */
rt_usbd_altsetting_add_endpoint(setting_vs_ep, usbd_uvc.ep);
/* add the alternate setting to the interface, then set default setting of the interface */
rt_usbd_interface_add_altsetting(intf_vc, setting_vc);
rt_usbd_set_altsetting(intf_vc, 0);
rt_usbd_interface_add_altsetting(intf_vs, setting_vs_noep);
rt_usbd_interface_add_altsetting(intf_vs, setting_vs_ep);
rt_usbd_set_altsetting(intf_vs, 0);
/* add the interface to the uac function */
rt_usbd_function_add_interface(func, intf_vc);
rt_usbd_function_add_interface(func, intf_vs);
return func;
}
static void usbd_video_mjpeg_set_resolution(uint32_t in_weight, uint32_t in_height, uint32_t out_weight, uint32_t out_height, uint32_t en)
{
rt_uint32_t e;
if(en)
{
if (usbd_uvc.cur_msi) {
usbd_uvc.recv_msi->enable = 0;
msi_put(usbd_uvc.cur_msi);
//确保所有fb都被释放
struct framebuff *fb = NULL;
do{
fb = msi_get_fb(usbd_uvc.cur_msi, 0);
if(fb)
msi_delete_fb(NULL, fb);
}while(fb != NULL);
msi_del_output(usbd_uvc.cur_msi, NULL, R_USBD_VIDEO);
usbd_uvc.cur_msi = RT_NULL;
os_sleep_ms(100); //等待 auto_h264 / auto_jpg work 完全停止
}
//等待UVC接收msi完全释放fb
if(rt_event_recv(usbd_uvc.event, EVENT_VIDEO_COMPLITE, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 5000, &e) != RT_EOK) {
//此处有可能触发超时,上位机重新打开摄像头可以恢复
os_printf("%s %d timeout\n",__FUNCTION__,__LINE__);
return;
}
if((in_weight != out_weight) || (in_height != out_height))
{
usbd_uvc.cur_msi = msi_find(AUTO_JPG,1); //VPP DATA1 按比例裁剪后的分辨率默认1/2
msi_do_cmd(usbd_uvc.cur_msi, MSI_CMD_AUTO_JPG, MSI_AUTO_JPG_SWITCH_ENCODE_SRC, VPP_DATA1);
}
else
{
usbd_uvc.cur_msi = msi_find(AUTO_JPG,1); //VPP DATA0 摄像头原分辨率
msi_do_cmd(usbd_uvc.cur_msi, MSI_CMD_AUTO_JPG, MSI_AUTO_JPG_SWITCH_ENCODE_SRC, VPP_DATA0);
}
usbd_uvc.recv_msi->enable = 1;
msi_add_output(usbd_uvc.cur_msi, NULL, R_USBD_VIDEO);
}
else
{
usbd_uvc.recv_msi->enable = 0;
if (usbd_uvc.cur_msi) {
msi_put(usbd_uvc.cur_msi);
//确保所有fb都被释放
struct framebuff *fb = NULL;
do{
fb = msi_get_fb(usbd_uvc.cur_msi, 0);
if(fb)
msi_delete_fb(NULL, fb);
}while(fb != NULL);
msi_del_output(usbd_uvc.cur_msi, NULL, R_USBD_VIDEO);
}
usbd_uvc.cur_msi = RT_NULL;
}
}
static void usbd_video_h264_set_resolution(uint32_t in_weight, uint32_t in_height, uint32_t out_weight, uint32_t out_height, uint32_t en)
{
rt_uint32_t e;
if(en)
{
if (usbd_uvc.cur_msi) {
usbd_uvc.recv_msi->enable = 0;
msi_put(usbd_uvc.cur_msi);
//确保所有fb都被释放
struct framebuff *fb = NULL;
do{
fb = msi_get_fb(usbd_uvc.cur_msi, 0);
if(fb)
msi_delete_fb(NULL, fb);
}while(fb != NULL);
msi_del_output(usbd_uvc.cur_msi, NULL, R_USBD_VIDEO);
usbd_uvc.cur_msi = RT_NULL;
os_sleep_ms(100); //等待 auto_h264 / auto_jpg work 完全停止
}
//等待UVC接收msi完全释放fb
if(rt_event_recv(usbd_uvc.event, EVENT_VIDEO_COMPLITE, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 5000, &e) != RT_EOK) {
//此处有可能触发超时,上位机重新打开摄像头可以恢复
os_printf("%s %d timeout\n",__FUNCTION__,__LINE__);
return;
}
/* 此处可添加 H264 分辨率切换代码
...
*/
usbd_uvc.cur_msi = msi_find(AUTO_H264, 1); //VPP DATA0 摄像头原分辨率
usbd_uvc.recv_msi->enable = 1;
msi_add_output(usbd_uvc.cur_msi, NULL, R_USBD_VIDEO);
}
else
{
usbd_uvc.recv_msi->enable = 0;
if (usbd_uvc.cur_msi) {
msi_put(usbd_uvc.cur_msi);
//确保所有fb都被释放
struct framebuff *fb = NULL;
do{
fb = msi_get_fb(usbd_uvc.cur_msi, 0);
if(fb)
msi_delete_fb(NULL, fb);
}while(fb != NULL);
msi_del_output(usbd_uvc.cur_msi, NULL, R_USBD_VIDEO);
}
usbd_uvc.cur_msi = RT_NULL;
}
}
static rt_bool_t usbd_uvc_init(struct ufunction *func)
{
rt_uint8_t busid = 0;
rt_thread_t usbd_uvc_thread;
g_usbd_video[busid].ops.mjpeg_set_resolution = usbd_video_mjpeg_set_resolution;
g_usbd_video[busid].ops.h264_set_resolution = usbd_video_h264_set_resolution;
usbd_uvc.cur_msi = RT_NULL;
usbd_uvc.event = rt_event_create("usbd_uvc_event", RT_IPC_FLAG_FIFO);
//保证第一次能够成功打开硬件
rt_event_send(usbd_uvc.event, EVENT_VIDEO_COMPLITE);
usbd_uvc_thread = rt_thread_create("usbd_uvc_thread",
usbd_uvc_entry, func,
1024,
OS_TASK_PRIORITY_NORMAL, 10);
if(usbd_uvc_thread != RT_NULL)
rt_thread_startup(usbd_uvc_thread);
usbd_uvc.thread = usbd_uvc_thread;
return RT_EOK;
}
static void rt_usbd_function_uvc_device_delete()
{
}
/*
* register uvc class
*/
static struct udclass uvc_device_class =
{
.rt_usbd_function_create = rt_usbd_function_uvc_device_create,
.rt_usbd_function_delete = rt_usbd_function_uvc_device_delete,
};
int rt_usbd_uvc_device_class_register(rt_uint32_t dev_id)
{
rt_usbd_class_register(&uvc_device_class, dev_id);
usbd_video_init_intf(0, INTERVAL, MAX_FRAME_SIZE(1920, 1080), MAX_PAYLOAD_SIZE);
return 0;
}
#endif