Files
MXC_A59/ArkmicroFiles/libcpu-amt630hv100/source/usb/usb_uvc.c

704 lines
18 KiB
C

#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdbool.h>
#include "usb_uvc.h"
#include "usb_os_adapter.h"
#include "trace.h"
#include <linux/usb/ch9.h>
#include "scsi.h"
#include "usb.h"
#include "dwc2_compat.h"
#include "ark_dwc2.h"
#include "list.h"
#include "trace.h"
#include "semphr.h"
#include "timers.h"
#include "sysctl.h"
#include "itu.h"
#include "board.h"
#include "ff_stdio.h"
#include "board.h"
#include "lcd.h"
#include "pxp.h"
#include "timer.h"
#include "cp15/cp15.h"
#include "usb.h"
#ifdef USB_UVC_SUPPORT
#pragma data_alignment=64
static char iso_buf[800 * 8] = {0};
#define UVC_VIDEO_WIDTH 1280
#define UVC_VIDEO_HEIGHT 720
//#define UVC_VIDEO_WIDTH 640
//#define UVC_VIDEO_HEIGHT 480
#define UVC0_JPEG_FIFO_COUNT (2)
#define UVC0_JPEG_BUF_SIZE 0x80000
#define UVC0_JPEG_YUV_BUF_SIZE ((UVC_VIDEO_WIDTH * UVC_VIDEO_HEIGHT) * 2 + 2048)
#define SAVE_UVC_FRAME 0
typedef struct _jpeg_frame_s {
char *buf; //图片存放的首地址
char *cur; //每次payload传输数据放在buf中偏移后的地址
char *yuv_buf;
unsigned int yuv_len;
unsigned int len; //图片总长度
unsigned int lock;
unsigned int frame_id;
ListItem_t entry;
} video_frame_s;
typedef struct _MGC_UVC_PROBE_PARAM_ {
uint16_t bmHint;
uint8_t bFormatIndex;
uint8_t bFrameIndex;
uint32_t dwFrameInterval;
uint16_t wKeyFrameRate;
uint16_t wPFrameRate;
uint16_t wCompQuality;
uint16_t wCompWindowSize;
uint16_t wDelay;
uint32_t dwMaxVideoFrameSize;
uint32_t dwMaxPayloadTransferSize;
} MGC_UVC_PROBE_PARAM;
static List_t frame_free_list;
static video_frame_s jpeg_fifos[UVC0_JPEG_FIFO_COUNT];
static char* jpeg_buf = NULL;
static char* jpeg_yuv_buf = NULL;
static SemaphoreHandle_t frame_list_mutex = NULL;
static TaskHandle_t dec_jpeg_handle;
static TaskHandle_t iso_read_handle;
static QueueHandle_t jpeg_frame_queue;
static QueueHandle_t iso_exit;
static int uvc_tast_start = 0;
static int fid;
//static int g_frame_err = 0;
static int g_uvc_dev_ready = 0;
void usb_set_maxpacket_ep_ex(struct usb_device *dev, int if_idx, int alt_idx, int ep_idx);
/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
#define UVC_STREAM_EOH (1 << 7)
#define UVC_STREAM_ERR (1 << 6)
#define UVC_STREAM_STI (1 << 5)
#define UVC_STREAM_RES (1 << 4)
#define UVC_STREAM_SCR (1 << 3)
#define UVC_STREAM_PTS (1 << 2)
#define UVC_STREAM_EOF (1 << 1)
#define UVC_STREAM_FID (1 << 0)
static void uvc_dump_probe_param(MGC_UVC_PROBE_PARAM *ProbeParam)
{
printf("=== MGC_UvcGetProbeControl ===\r\n");
printf("bmHint = 0x%x\r\n", ProbeParam->bmHint);
printf("bFormatIndex = 0x%x\r\n", ProbeParam->bFormatIndex);
printf("bFrameIndex = 0x%x\r\n", ProbeParam->bFrameIndex);
printf("dwFrameInterval = 0x%x\r\n", ProbeParam->dwFrameInterval);
printf("wKeyFrameRate = 0x%x\r\n", ProbeParam->wKeyFrameRate);
printf("wPFrameRate = 0x%x\r\n", ProbeParam->wPFrameRate);
printf("wCompQuality = 0x%x\r\n", ProbeParam->wCompQuality);
printf("wCompWindowSize = 0x%x\r\n", ProbeParam->wCompWindowSize);
printf("wDelay = 0x%x\r\n", ProbeParam->wDelay);
printf("dwMaxVideoFrameSize = 0x%x\r\n", ProbeParam->dwMaxVideoFrameSize);
printf("dwMaxPayloadTransferSize = 0x%x\r\n", ProbeParam->dwMaxPayloadTransferSize);
}
#if 1
static int usb_camera_init(struct usb_device *dev, int *iso_pipe)
{
struct usb_interface *iface;
struct usb_interface *video_stream_iface;
struct usb_endpoint_descriptor *ep_desc;
int i, ret = -1;
char flag_video_ctrl = false;
char flag_video_stream = false;
unsigned char ep_in = 0;
MGC_UVC_PROBE_PARAM ProbeParam = {0};
int alt_if_num = 5;
char data_rcv[128] = {0};
char *pdata = NULL;
for (i = 0; i < USB_MAXINTERFACES; i++) {
iface = &dev->config.if_desc[i];
if (iface->desc.bInterfaceClass == USB_CLASS_VIDEO) {
if (iface->desc.bInterfaceSubClass == 0x01) {
flag_video_ctrl = true;
} else if (iface->desc.bInterfaceSubClass == 0x02) {
flag_video_stream = true;
video_stream_iface = iface;
}
}
}
if (!flag_video_ctrl || !flag_video_stream) {
goto exit;
}
ep_desc = &video_stream_iface->alt_intf[alt_if_num].ep_desc[0];
if ((ep_desc->bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC) {
if (ep_desc->bEndpointAddress & USB_DIR_IN) {
ep_in = ep_desc->bEndpointAddress;
usb_set_maxpacket_ep_ex(dev, 1, alt_if_num, 0);
}
}
ret = usb_set_interface(dev, 1, 0);
if (ret < 0) {
goto exit;
}
mdelay(10);
ret= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x81,
0xA1,
0x100,
0x1, data_rcv,
0x1A, 3000);
if (ret < 0) {
goto exit;
} else {
pdata = data_rcv;
ProbeParam.bmHint = (pdata[1]<<8) | pdata[0];
ProbeParam.bFormatIndex = pdata[2];
ProbeParam.bFrameIndex = pdata[3];
ProbeParam.dwFrameInterval = (pdata[7]<<24)|(pdata[6]<<16)|(pdata[5]<<8) | pdata[4];
ProbeParam.wKeyFrameRate = (pdata[9]<<8) | pdata[8];
ProbeParam.wPFrameRate = (pdata[11]<<8) | pdata[10];
ProbeParam.wCompQuality = (pdata[13]<<8) | pdata[12];
ProbeParam.wCompWindowSize = (pdata[15]<<8) | pdata[14];
ProbeParam.wDelay = (pdata[17]<<8) | pdata[16];
ProbeParam.dwMaxVideoFrameSize = (pdata[21]<<24)|(pdata[20]<<16)|(pdata[19]<<8) | pdata[18];
ProbeParam.dwMaxPayloadTransferSize = (pdata[21]<<25)|(pdata[24]<<16)|(pdata[23]<<8) | pdata[22];
uvc_dump_probe_param(&ProbeParam);
}
ProbeParam.bFormatIndex = 2; //1:mpgj; 2:yuy2 [Depend On Format Type Descriptor ]
#if UVC_VIDEO_WIDTH == 1280 && UVC_VIDEO_HEIGHT == 720
ProbeParam.bFrameIndex = 2; //1:1280X720; 5:640*480
#else
ProbeParam.bFrameIndex = 1;
#endif
ProbeParam.dwMaxVideoFrameSize = 0;//720p:0x001C224D; 640*480:0x0009624D
ProbeParam.dwFrameInterval = 0x051615;
pdata = (char *)&ProbeParam;
ret= usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x1,
0x21,
0x100,
0x1, pdata,
0x1A, 3000);
if (ret < 0) {
goto exit;
}
ret= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x81,
0xA1,
0x100,
0x1, data_rcv,
0x1A, 3000);
if (ret < 0) {
} else {
pdata = data_rcv;
ProbeParam.bmHint = (pdata[1]<<8) | pdata[0];
ProbeParam.bFormatIndex = pdata[2];
ProbeParam.bFrameIndex = pdata[3];
ProbeParam.dwFrameInterval = (pdata[7]<<24)|(pdata[6]<<16)|(pdata[5]<<8) | pdata[4];
ProbeParam.wKeyFrameRate = (pdata[9]<<8) | pdata[8];
ProbeParam.wPFrameRate = (pdata[11]<<8) | pdata[10];
ProbeParam.wCompQuality = (pdata[13]<<8) | pdata[12];
ProbeParam.wCompWindowSize = (pdata[15]<<8) | pdata[14];
ProbeParam.wDelay = (pdata[17]<<8) | pdata[16];
ProbeParam.dwMaxVideoFrameSize = (pdata[21]<<24)|(pdata[20]<<16)|(pdata[19]<<8) | pdata[18];
ProbeParam.dwMaxPayloadTransferSize = (pdata[21]<<25)|(pdata[24]<<16)|(pdata[23]<<8) | pdata[22];
uvc_dump_probe_param(&ProbeParam);
}
pdata = (char *)&ProbeParam;
ret= usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x1,
0x21,
0x200,
0x1, pdata,
0x1A, 3000);
if (ret < 0) {
goto exit;
}
mdelay(10);
ret = usb_set_interface(dev, 1, alt_if_num);
if (ret < 0) {
goto exit;
}
if (iso_pipe)
*iso_pipe = usb_rcvisocpipe(dev, ep_in);
exit:
return ret;
}
#else
static void uvc_get_probe_param(MGC_UVC_PROBE_PARAM *ProbeParam, char *pdata)
{
ProbeParam->bmHint = (pdata[1]<<8) | pdata[0];
ProbeParam->bFormatIndex = pdata[2];
ProbeParam->bFrameIndex = pdata[3];
ProbeParam->dwFrameInterval = (pdata[7]<<24)|(pdata[6]<<16)|(pdata[5]<<8) | pdata[4];
ProbeParam->wKeyFrameRate = (pdata[9]<<8) | pdata[8];
ProbeParam->wPFrameRate = (pdata[11]<<8) | pdata[10];
ProbeParam->wCompQuality = (pdata[13]<<8) | pdata[12];
ProbeParam->wCompWindowSize = (pdata[15]<<8) | pdata[14];
ProbeParam->wDelay = (pdata[17]<<8) | pdata[16];
ProbeParam->dwMaxVideoFrameSize = (pdata[21]<<24)|(pdata[20]<<16)|(pdata[19]<<8) | pdata[18];
ProbeParam->dwMaxPayloadTransferSize = (pdata[21]<<25)|(pdata[24]<<16)|(pdata[23]<<8) | pdata[22];
}
static int usb_camera_init(struct usb_device *dev, int *iso_pipe)
{
struct usb_interface *iface;
struct usb_interface *video_stream_iface;
struct usb_endpoint_descriptor *ep_desc;
int i, ret = -1;
char flag_video_ctrl = false;
char flag_video_stream = false;
unsigned char ep_in = 0;
MGC_UVC_PROBE_PARAM ProbeParam = {0};
int alt_if_num = 5;
char data_rcv[128] = {0};
char *pdata = NULL;
for (i = 0; i < USB_MAXINTERFACES; i++) {
iface = &dev->config.if_desc[i];
if (iface->desc.bInterfaceClass == USB_CLASS_VIDEO) {
if (iface->desc.bInterfaceSubClass == 0x01) {
flag_video_ctrl = true;
} else if (iface->desc.bInterfaceSubClass == 0x02) {
flag_video_stream = true;
video_stream_iface = iface;
}
}
}
if (!flag_video_ctrl || !flag_video_stream) {
goto exit;
}
ep_desc = &video_stream_iface->alt_intf[alt_if_num].ep_desc[0];
if ((ep_desc->bmAttributes &
USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC) {
if (ep_desc->bEndpointAddress & USB_DIR_IN) {
ep_in = ep_desc->bEndpointAddress;
usb_set_maxpacket_ep_ex(dev, 1, alt_if_num, 0);
}
}
ret = usb_set_interface(dev, 1, 0);
if (ret < 0) {
goto exit;
}
mdelay(10);
ret= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x81,
0xA1,
0x100,
0x1, data_rcv,
0x1A, 3000);
if (ret < 0) {
goto exit;
} else {
uvc_get_probe_param(&ProbeParam, data_rcv);
uvc_dump_probe_param(&ProbeParam);
}
ProbeParam.bFormatIndex = 1; //1:mpgj; 2:yuy2 [Depend On Format Type Descriptor ]
#if UVC_VIDEO_WIDTH == 1280 && UVC_VIDEO_HEIGHT == 720
ProbeParam.bFrameIndex = 9; //1:1280X720; 5:640*480
#else
ProbeParam.bFrameIndex = 1;
#endif
ProbeParam.dwMaxVideoFrameSize = 0;//720p:0x001C224D; 640*480:0x0009624D
ProbeParam.dwFrameInterval = 0x051615;
pdata = (char *)&ProbeParam;
ret= usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x1,
0x21,
0x100,
0x1, pdata,
0x1A, 3000);
if (ret < 0) {
goto exit;
}
ret= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x81,
0xA1,
0x100,
0x1, data_rcv,
0x1A, 3000);
if (ret < 0) {
} else {
uvc_get_probe_param(&ProbeParam, data_rcv);
uvc_dump_probe_param(&ProbeParam);
}
pdata = (char *)&ProbeParam;
ret= usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 0x1,
0x21,
0x200,
0x1, pdata,
0x1A, 3000);
if (ret < 0) {
goto exit;
}
mdelay(10);
ret = usb_set_interface(dev, 1, alt_if_num);
if (ret < 0) {
goto exit;
}
if (iso_pipe)
*iso_pipe = usb_rcvisocpipe(dev, ep_in);
exit:
return ret;
}
#endif
static void uvc_frame_list_reset()
{
video_frame_s* frame = NULL;
ListItem_t *pxListItem;
list_for_each_entry(pxListItem, frame, &frame_free_list) {
frame->cur = frame->buf;
frame->len = 0;
}
}
static void uvc_data_receive_proc(void *pvParameters)
{
int ret = -1;
int iso_buf_len = sizeof(iso_buf);
int header_len = 0, payload_len = 0, frame_len = 0;
uint8_t header_info = 0;
uint8_t* payload = NULL;
uint8_t* buf = (uint8_t*)iso_buf;
uint8_t* frame_buf = (uint8_t*)iso_buf;
video_frame_s* frame = NULL;
ListItem_t* item = NULL;
struct usb_device *dev = (struct usb_device *)pvParameters;
int iso_pipe = -1;
if (NULL == dev)
goto exit;
ret = usb_camera_init(dev, &iso_pipe);
if (ret < 0)
goto exit;
while(1) {
if (!g_uvc_dev_ready)
break;
if (list_empty(&frame_free_list)) {
continue;
}
ret = usb_iso_msg(dev, iso_pipe, (void*)buf, iso_buf_len, &payload_len, (int)portMAX_DELAY);
if (ret < 0)
break;
if (payload_len <= 0)
continue;
frame_buf = buf;
payload = (uint8_t*)frame_buf;
header_len = payload[0];
if (header_len > payload_len) {
printf("err pack\r\n");
}
if (header_len < 2) {
header_info = 0;
} else {
header_info = payload[1];
if (header_info & 0x40) {
printf("bad pack: error bit set\r\n");
continue;
}
if ((header_info & UVC_STREAM_FID) != fid) {
fid = (header_info & UVC_STREAM_FID);
//printf("new video frame start\r\n");
}
frame_len = (payload_len - header_len);
frame = list_first_entry(&frame_free_list);
frame_buf += header_len;
memcpy((void *)frame->cur, frame_buf, frame_len);
frame->cur += frame_len;
frame->len += frame_len;
if(header_info & UVC_STREAM_EOF) {
xSemaphoreTake(frame_list_mutex, portMAX_DELAY);
item = listGET_HEAD_ENTRY(&frame_free_list);
uxListRemove(item);
xSemaphoreGive(frame_list_mutex);
xQueueSend(jpeg_frame_queue, (void*)&frame, 0);
//printf("video frame end\r\n");
}
}
}
exit:
frame = NULL;
xQueueSend(jpeg_frame_queue, (void*)&frame, 0);
xQueueSend(iso_exit, NULL, 0);
vTaskDelete(NULL);
}
static void dec_jpeg_task_proc(void *pvParameters)
{
video_frame_s* frame = NULL;
uint32_t yaddr, uvaddr, vaddr, dstaddr;
int format;
uint32_t ts = get_timer(0);
int uvc_lcd_take = 0;
char *yuv_buf = jpeg_yuv_buf;
#if SAVE_UVC_FRAME
int i = 0;
char filename[32] = {0};
#endif
while(uvc_tast_start) {
xQueueReceive(jpeg_frame_queue, (void*)&frame, portMAX_DELAY);
if (frame == NULL) {
if (uvc_lcd_take) {
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 0);
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
vVideoDisplayBufGive();
ark_lcd_osd_enable(LCD_UI_LAYER, 1);
ark_lcd_set_osd_sync(LCD_UI_LAYER);
uvc_lcd_take = 0;
}
xSemaphoreTake(frame_list_mutex, portMAX_DELAY);
uvc_frame_list_reset();
xSemaphoreGive(frame_list_mutex);
xQueueReset(jpeg_frame_queue);
continue;
}
if (uvc_tast_start == 0)
break;
CP15_clean_dcache_for_dma((uint32_t)frame->buf, (uint32_t)(frame->buf + frame->len));
#if SAVE_UVC_FRAME
sprintf(filename, "/sd/uvc/%05d.jpg", i);
if (i++ % 50 == 0) {
FF_FILE *fp = ff_fopen(filename, "w+");
if (fp) {
int ret = ff_fwrite((void*)frame->buf, 1, frame->len, fp);
if (ret < 0){
printf("write failed\r\n");
}
ff_fclose(fp);
} else {
printf("open %s failed\r\n", filename);
}
}
#endif
JpegHeaderInfo jpginfo = {0};
jpginfo.jpg_addr = (uint32_t)frame->buf;
jpginfo.dec_addry = (uint32_t)yuv_buf;
jpginfo.dec_size = (uint32_t)frame->yuv_len;
ts = get_timer(0);
if (jpeg_dec(&jpginfo) < 0) {
printf("dec jpeg failed use %ld\r\n", get_timer(ts));
} else {
yaddr = jpginfo.dec_addry;
uvaddr = jpginfo.dec_addru;
vaddr = jpginfo.dec_addrv;
format = PXP_SRC_FMT_YUV422;
if (uvc_lcd_take == 0) {
uvc_lcd_take = 1;
xVideoDisplayBufTake(portMAX_DELAY);
}
if (uvc_lcd_take) {
if (!ark_lcd_get_osd_info_atomic_isactive(LCD_VIDEO_LAYER)) {
ark_lcd_wait_for_vsync();
}
dstaddr = ulVideoDisplayBufGet();
pxp_scaler_rotate(yaddr, uvaddr, vaddr, format, jpginfo.width, jpginfo.height,
dstaddr, 0, PXP_OUT_FMT_RGB565, LCD_WIDTH, LCD_HEIGHT, 0);
LcdOsdInfo info = {0};
info.x = 0;
info.y = 0;
info.width = LCD_WIDTH;
info.height = LCD_HEIGHT;
info.format = LCD_OSD_FORAMT_RGB565;
info.yaddr = dstaddr;
ark_lcd_set_osd_info_atomic(LCD_VIDEO_LAYER, &info);
ark_lcd_osd_enable(LCD_VIDEO_LAYER, 1);
ark_lcd_set_osd_sync(LCD_VIDEO_LAYER);
ark_lcd_osd_enable(LCD_UI_LAYER, 0);
ark_lcd_set_osd_sync(LCD_UI_LAYER);
vVideoDisplayBufRender(dstaddr);
}
//printf("proc frame:%d use %ld \r\n", frame->len, get_timer(ts));
}
xSemaphoreTake(frame_list_mutex, portMAX_DELAY);
frame->cur = frame->buf;
frame->len = 0;
vListInsertEnd(&frame_free_list, &frame->entry);
xSemaphoreGive(frame_list_mutex);
}
}
int usb_uvc_probe(struct usb_device *dev)
{
struct usb_interface *iface;
int i;
char flag_video_ctrl = false;
char flag_video_stream = false;
for (i = 0; i < USB_MAXINTERFACES; i++) {
iface = &dev->config.if_desc[i];
if (iface->desc.bInterfaceClass == USB_CLASS_VIDEO) {
if (iface->desc.bInterfaceSubClass == 0x01) {
flag_video_ctrl = true;
} else if (iface->desc.bInterfaceSubClass == 0x02) {
flag_video_stream = true;
}
}
}
if (!flag_video_ctrl || !flag_video_stream) {
return 0;
}
printf("found UVC device!\r\n");
g_uvc_dev_ready = 1;
xTaskCreate(uvc_data_receive_proc, "uvc_data_receive_proc", configMINIMAL_STACK_SIZE * 1, (void*)dev, configMAX_PRIORITIES, &iso_read_handle);
return 1;
}
/* 初始化jpeg 数据链表*/
static int g_uvc_init_flag = 0;
void uvc_jpeg_buf_init(void)
{
video_frame_s *buffer;
int i;
if (g_uvc_init_flag)
return;
vListInitialise(&frame_free_list);
buffer = (video_frame_s *)jpeg_fifos;
jpeg_buf = pvPortMalloc(UVC0_JPEG_FIFO_COUNT * UVC0_JPEG_BUF_SIZE);
if (jpeg_buf == NULL) {
printf("malloc jpeg buf failed\r\n");
return;
}
jpeg_yuv_buf = pvPortMalloc(UVC0_JPEG_YUV_BUF_SIZE);
memset((void *)jpeg_yuv_buf, 0, UVC0_JPEG_YUV_BUF_SIZE);
if (jpeg_yuv_buf == NULL) {
printf("malloc jpeg yuv buf failed\r\n");
vPortFree(jpeg_buf);
return;
}
for(i = 0; i < UVC0_JPEG_FIFO_COUNT; i++) {
buffer->buf = (char *)(((unsigned int)jpeg_buf + i * UVC0_JPEG_BUF_SIZE + 1023)&(~1023));
buffer->cur = buffer->buf;
//buffer->yuv_buf = (char *)(((unsigned int)jpeg_yuv_buf + i * UVC0_JPEG_YUV_BUF_SIZE + 1023)&(~1023));
buffer->yuv_len = UVC_VIDEO_WIDTH * UVC_VIDEO_HEIGHT * 2;
buffer->lock = 0;
buffer->frame_id = i;
buffer->len = 0;
vListInitialiseItem(&buffer->entry);
vListInsertEnd(&frame_free_list, &buffer->entry);
listSET_LIST_ITEM_OWNER(&buffer->entry, buffer);
buffer++;
}
g_uvc_init_flag = 0;
}
int usb_uvc_scan()
{
unsigned char i = 0;
struct usb_device *dev = NULL;
int ret = 0;
for (i = 0; i < USB_MAX_DEVICE; i++) {
dev = usb_get_dev_index(i);
if (usb_uvc_probe(dev)) {
ret = 1;
break;
}
}
return ret;
}
void usb_uvc_disconnect()
{
if (g_uvc_dev_ready != 0) {
g_uvc_dev_ready = 0;
xQueueReceive(iso_exit, NULL, portMAX_DELAY);
}
xQueueReset(iso_exit);
}
int usb_uvc_init()
{
BaseType_t ret = -1;
uvc_jpeg_buf_init();
frame_list_mutex = xSemaphoreCreateMutex();
jpeg_frame_queue = xQueueCreate(UVC0_JPEG_FIFO_COUNT, sizeof(uint32_t));
iso_exit = xQueueCreate(1, 0);
uvc_tast_start = 1;
ret = xTaskCreate(dec_jpeg_task_proc, "dec_jpeg_task_task", configMINIMAL_STACK_SIZE * 1, NULL, configMAX_PRIORITIES, &dec_jpeg_handle);
return (int)ret;
}
#else
int usb_uvc_init()
{
return 0;
}
int usb_uvc_scan()
{
return 0;
}
void usb_uvc_disconnect()
{
}
#endif