704 lines
18 KiB
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
|