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

2272 lines
110 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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