Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources
This commit is contained in:
725
sdk/lib/video/uvc/rtt_uvc_host.c
Normal file
725
sdk/lib/video/uvc/rtt_uvc_host.c
Normal file
@@ -0,0 +1,725 @@
|
||||
#include "video/uvc/rtt_uvc_host.h"
|
||||
#include "lib/heap/av_heap.h"
|
||||
#include "lib/heap/av_psram_heap.h"
|
||||
|
||||
|
||||
|
||||
#ifdef PSRAM_HEAP
|
||||
#define UVC_BLANK_MALLOC av_psram_zalloc
|
||||
#define UVC_BLANK_FREE av_psram_free
|
||||
#else
|
||||
#define UVC_BLANK_MALLOC av_zalloc
|
||||
#define UVC_BLANK_FREE av_free
|
||||
#endif
|
||||
|
||||
static UVC_Device *uvc_devices[MAX_DEVICES] = {NULL}; // 设备池
|
||||
static int registered_devices = 0; // 已注册设备数
|
||||
|
||||
static void uvc_device_wait_frame(UVC_Device* uvc_device);
|
||||
|
||||
/* ------------------------------- 设备缓存节点接口 ------------------------------- */
|
||||
static void uvc_device_blank_node_init(UVC_Device* uvc_device)
|
||||
{
|
||||
os_printf("%s %d\n", __FUNCTION__, __LINE__);
|
||||
if (uvc_device->blank_num == 0) {
|
||||
uvc_device->blank_num = UVC_DEFAULT_BLANK_NUM;
|
||||
}
|
||||
if (uvc_device->blank_len == 0) {
|
||||
uvc_device->blank_len = UVC_DEFAULT_BLANK_LEN;
|
||||
}
|
||||
|
||||
uvc_device->blank_buffer = UVC_BLANK_MALLOC(sizeof(UVC_BLANK) * uvc_device->blank_num);
|
||||
|
||||
os_printf("blank_buffer : %x\n", uvc_device->blank_buffer);
|
||||
|
||||
if (!uvc_device->blank_buffer) {
|
||||
os_printf("blank node head malloc failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&uvc_device->free_uvc_tab);
|
||||
|
||||
UVC_BLANK *blank = uvc_device->blank_buffer;
|
||||
|
||||
for (int i = 0; i < uvc_device->blank_num; i++) {
|
||||
|
||||
// os_printf("blank[%d] : %x\n", i, blank);
|
||||
INIT_LIST_HEAD(&blank->list);
|
||||
|
||||
blank->blank_len = uvc_device->blank_len;
|
||||
blank->blank_loop = 0;
|
||||
blank->busy = UVC_DEVICE_BLANK_STATE_IDLE;
|
||||
blank->frame_counter = 0;
|
||||
blank->re_space = 0;
|
||||
blank->buf_ptr = UVC_BLANK_MALLOC(uvc_device->blank_len);
|
||||
if (!blank->buf_ptr) {
|
||||
os_printf("blank node[%d] buf malloc failed\n", i);
|
||||
return;
|
||||
}
|
||||
sys_dcache_invalid_range((uint32_t*)blank->buf_ptr, blank->blank_len);
|
||||
list_add_tail(&blank->list, &uvc_device->free_uvc_tab);
|
||||
os_printf("blank node[%d] :%x ptr:%x\n", i, blank, blank->buf_ptr);
|
||||
blank++;
|
||||
}
|
||||
}
|
||||
|
||||
static void uvc_device_blank_node_deinit(UVC_Device* uvc_device)
|
||||
{
|
||||
if (!uvc_device->blank_buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
uvc_device_wait_frame(uvc_device);
|
||||
|
||||
UVC_BLANK *blank = uvc_device->blank_buffer;
|
||||
os_printf("%s %d\n", __FUNCTION__, __LINE__);
|
||||
for (int i = 0; i < uvc_device->blank_num; i++) {
|
||||
if (blank->buf_ptr) {
|
||||
UVC_BLANK_FREE(blank->buf_ptr);
|
||||
os_printf("free blank node[%d] buf:%x\n", i, blank->buf_ptr);
|
||||
blank->buf_ptr = NULL;
|
||||
}
|
||||
blank++;
|
||||
}
|
||||
if(uvc_device->blank_buffer) {
|
||||
UVC_BLANK_FREE(uvc_device->blank_buffer);
|
||||
os_printf("free blank_buffer:%x\n", uvc_device->blank_buffer);
|
||||
uvc_device->blank_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct list_head *uvc_device_get_blank_node(struct list_head *head, struct list_head *del)
|
||||
{
|
||||
// os_printf("%s %d head:%x del:%x\n", __FUNCTION__, __LINE__,head,del);
|
||||
if(list_empty(del)) {
|
||||
return NULL;
|
||||
}
|
||||
list_move(del->prev, head);
|
||||
return head->next;
|
||||
}
|
||||
|
||||
static bool uvc_device_free_get_blank_node_list(struct list_head *head, struct list_head *free) {
|
||||
if (list_empty(head)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_splice_init(head, free);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------- 设备缓存帧接口 ------------------------------- */
|
||||
static void uvc_device_frame_init(UVC_Device* uvc_device)
|
||||
{
|
||||
os_printf("%s %d\n", __FUNCTION__, __LINE__);
|
||||
for (int i = 0; i < UVC_DEFAULT_FRAME_NUM; i++) {
|
||||
INIT_LIST_HEAD(&uvc_device->uvc_msg_frame[i].list);
|
||||
uvc_device->uvc_msg_frame[i].state = UVC_DEVICE_FRAME_STATE_IDLE;
|
||||
uvc_device->uvc_msg_frame[i].sta = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct list_head *uvc_device_get_new_frame(UVC_Device* uvc_device, int grab)
|
||||
{
|
||||
|
||||
uint8_t frame_num = 0;
|
||||
for (frame_num = 0; frame_num < UVC_DEFAULT_FRAME_NUM; frame_num++) {
|
||||
if (uvc_device->uvc_msg_frame[frame_num].state == UVC_DEVICE_FRAME_STATE_IDLE) {
|
||||
uvc_device->uvc_msg_frame[frame_num].state = UVC_DEVICE_FRAME_STATE_BUSY;
|
||||
uvc_device->uvc_msg_frame[frame_num].frame_end = UVC_DEIVCE_FRAME_NOT_END;
|
||||
uvc_device->frame_counter++;
|
||||
return &uvc_device->uvc_msg_frame[frame_num].list;
|
||||
}
|
||||
}
|
||||
|
||||
//是否开启抢占模式,开启抢占后,肯定有frame返回,上一帧没使用的frame肯定usable为2
|
||||
if (grab) {
|
||||
for (frame_num = 0; frame_num < UVC_DEFAULT_FRAME_NUM; frame_num++) {
|
||||
if (uvc_device->uvc_msg_frame[frame_num].state == UVC_DEVICE_FRAME_STATE_AVAILABLE) {
|
||||
uvc_device->uvc_msg_frame[frame_num].state = UVC_DEVICE_FRAME_STATE_BUSY;
|
||||
uvc_device->uvc_msg_frame[frame_num].frame_end = UVC_DEIVCE_FRAME_NOT_END;
|
||||
uvc_device_free_get_blank_node_list(&uvc_device->uvc_msg_frame[frame_num].list, &uvc_device->free_uvc_tab);
|
||||
uvc_device->frame_counter++;
|
||||
return &uvc_device->uvc_msg_frame[frame_num].list;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void uvc_device_end_frame(UVC_Device* uvc_device, UVC_MANAGE *frame)
|
||||
{
|
||||
if (uvc_device && frame) {
|
||||
if (frame->state != UVC_DEVICE_FRAME_STATE_USING) {
|
||||
frame->state = UVC_DEVICE_FRAME_STATE_AVAILABLE;
|
||||
}
|
||||
frame->frame_end = UVC_DEIVCE_FRAME_END;
|
||||
uvc_device->current_frame = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void uvc_device_free_err_frame(UVC_Device* uvc_device, UVC_MANAGE *frame)
|
||||
{
|
||||
if (uvc_device && frame) {
|
||||
// 重置帧状态
|
||||
if (frame->state != UVC_DEVICE_FRAME_STATE_USING) {
|
||||
uvc_device_free_get_blank_node_list(&frame->list, &uvc_device->free_uvc_tab);
|
||||
frame->state = UVC_DEVICE_FRAME_STATE_IDLE;
|
||||
}
|
||||
frame->frame_end = UVC_DEVICE_FRAME_ERROR;
|
||||
uvc_device->current_frame = NULL;
|
||||
// uvc_device->initial_fid_detected = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void uvc_device_wait_frame(UVC_Device* uvc_device)
|
||||
{
|
||||
uint32_t timeout = 0;
|
||||
os_printf("%s %d\n", __FUNCTION__, __LINE__);
|
||||
if (uvc_device){
|
||||
for(int j = 0; j < UVC_DEFAULT_FRAME_NUM; j++) {
|
||||
if (uvc_device->uvc_msg_frame[j].state == UVC_DEVICE_FRAME_STATE_USING) {
|
||||
os_sleep_ms(1);
|
||||
timeout++;
|
||||
if (timeout > 500) {
|
||||
timeout = 0;
|
||||
os_printf("%s %d\n", __FUNCTION__, __LINE__);
|
||||
//continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------- 设备池管理接口 ------------------------------- */
|
||||
bool uvc_device_pool_init() {
|
||||
if (uvc_devices[0]) {
|
||||
os_printf("uvc device pool already init\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int32 flags = disable_irq();
|
||||
for(int i = 0; i < MAX_DEVICES; i++) {
|
||||
uvc_devices[i] = (UVC_Device*)os_zalloc(sizeof(UVC_Device));
|
||||
if (!uvc_devices[i]) {
|
||||
os_printf("uvc device pool malloc failed\n");
|
||||
enable_irq(flags);
|
||||
return false;
|
||||
}
|
||||
uvc_devices[i]->is_register = UVC_DEVICE_REGISTER_IDLE;
|
||||
}
|
||||
enable_irq(flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
void uvc_device_pool_deinit() {
|
||||
|
||||
for (int i = 0; i < MAX_DEVICES; i++) {
|
||||
unregister_uvc_device(uvc_devices[i]);
|
||||
}
|
||||
|
||||
int32 flags = disable_irq();
|
||||
for(int i = 0; i < MAX_DEVICES; i++) {
|
||||
if (uvc_devices[i]) {
|
||||
os_free(uvc_devices[i]);
|
||||
uvc_devices[i] = NULL;
|
||||
}
|
||||
}
|
||||
enable_irq(flags);
|
||||
}
|
||||
|
||||
// 注册新设备(实际应用中需结合设备枚举过程)
|
||||
void* register_uvc_device(uint8_t dev_num, uint8_t blank_num, uint32_t blank_len, void* p_dev) {
|
||||
if (registered_devices >= MAX_DEVICES) return false;
|
||||
|
||||
UVC_Device *dev = NULL;
|
||||
int32 flags = disable_irq();
|
||||
for (int i = 0; i < MAX_DEVICES; i++) {
|
||||
os_printf("uvc_devices[%d] = %x is_register:%d\n", i, uvc_devices[i],uvc_devices[i]->is_register);
|
||||
if (uvc_devices[i]->is_register == UVC_DEVICE_REGISTER_IDLE) {
|
||||
dev = uvc_devices[i];
|
||||
registered_devices++;
|
||||
os_printf("%s %d\n", __FUNCTION__, __LINE__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enable_irq(flags);
|
||||
os_printf("%s %d\n", __FUNCTION__, __LINE__);
|
||||
if (dev == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
os_printf("%s %d\n", __FUNCTION__, __LINE__);
|
||||
|
||||
|
||||
dev->blank_num = blank_num;
|
||||
dev->blank_len = blank_len;
|
||||
dev->frame_counter = 0;
|
||||
dev->dev_num = dev_num + 1;
|
||||
dev->last_fid = 0xFF;
|
||||
dev->is_register = UVC_DEVICE_REGISTER_AVAILABLE;
|
||||
dev->current_frame = NULL;
|
||||
dev->filter_count = 10;
|
||||
dev->expected_fid = 0xFF;
|
||||
dev->initial_fid_detected = 0;
|
||||
dev->p_dev = (struct usb_device *)p_dev;
|
||||
uvc_device_frame_init(dev);
|
||||
uvc_device_blank_node_init(dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
bool unregister_uvc_device(void* device) {
|
||||
|
||||
UVC_Device* dev = (UVC_Device*)device;
|
||||
|
||||
os_printf("%s %d dev:0x%x dev->dev_num:%d\n", __FUNCTION__, __LINE__,dev,dev->dev_num);
|
||||
|
||||
if (!dev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dev->dev_num = 0;
|
||||
dev->is_register = UVC_DEVICE_REGISTER_BUSY;
|
||||
uvc_device_blank_node_deinit(dev);
|
||||
dev->is_register = UVC_DEVICE_REGISTER_IDLE;
|
||||
registered_devices--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 根据设备号查找设备(返回NULL表示未找到)
|
||||
static UVC_Device* find_uvc_device(uint8_t dev_num) {
|
||||
UVC_Device* ret = NULL;
|
||||
|
||||
for (int i = 0; i < MAX_DEVICES; i++) {
|
||||
if ((uvc_devices[i]->dev_num == (dev_num + 1)) && (uvc_devices[i]->is_register == UVC_DEVICE_REGISTER_AVAILABLE)) {
|
||||
ret = uvc_devices[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------- 上层应用调用接口 ------------------------------- */
|
||||
struct list_head *uvc_device_user_get_frame(void* device)
|
||||
{
|
||||
uint8_t frame_num = 0;
|
||||
struct list_head* list = NULL;
|
||||
UVC_Device* uvc_device = (UVC_Device*)device;
|
||||
|
||||
if (!uvc_device || uvc_device->is_register == UVC_DEVICE_REGISTER_IDLE || uvc_device->is_register == UVC_DEVICE_REGISTER_BUSY) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// os_printf("%s %d\n", __FUNCTION__, __LINE__);
|
||||
|
||||
uint32_t flags = disable_irq();
|
||||
|
||||
for (frame_num = 0; frame_num < UVC_DEFAULT_FRAME_NUM; frame_num++) {
|
||||
if (uvc_device->uvc_msg_frame[frame_num].state == UVC_DEVICE_FRAME_STATE_AVAILABLE) {
|
||||
uvc_device->uvc_msg_frame[frame_num].state = UVC_DEVICE_FRAME_STATE_BUSY;
|
||||
list = &uvc_device->uvc_msg_frame[frame_num].list;
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PSRAM_HEAP
|
||||
for (frame_num = 0; frame_num < UVC_DEFAULT_FRAME_NUM; frame_num++) {
|
||||
if (uvc_device->uvc_msg_frame[frame_num].state == UVC_DEVICE_FRAME_STATE_BUSY) {
|
||||
uvc_device->uvc_msg_frame[frame_num].state = UVC_DEVICE_FRAME_STATE_BUSY;
|
||||
list = &uvc_device->uvc_msg_frame[frame_num].list;
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
__exit:
|
||||
enable_irq(flags);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void uvc_device_user_set_frame_using(void *uvc_msg_frame)
|
||||
{
|
||||
UVC_MANAGE *frame = (UVC_MANAGE*)uvc_msg_frame;
|
||||
frame->state = UVC_DEVICE_FRAME_STATE_USING;
|
||||
}
|
||||
|
||||
void uvc_device_user_set_frame_idle(void *uvc_msg_frame)
|
||||
{
|
||||
UVC_MANAGE *frame = (UVC_MANAGE*)uvc_msg_frame;
|
||||
frame->frame_len = 0;
|
||||
frame->frame_end = 0;
|
||||
frame->state = UVC_DEVICE_FRAME_STATE_IDLE;
|
||||
}
|
||||
|
||||
int uvc_device_user_get_frame_blank_node_num(void* device, struct list_head *head)
|
||||
{
|
||||
int count = 0;
|
||||
UVC_Device* uvc_device = (UVC_Device*)device;
|
||||
struct list_head *first = (struct list_head *)head;
|
||||
|
||||
if (!uvc_device || uvc_device->is_register == UVC_DEVICE_REGISTER_BUSY || uvc_device->is_register == UVC_DEVICE_REGISTER_BUSY) {
|
||||
return count;
|
||||
}
|
||||
|
||||
irq_disable(usb_device_ioctl(uvc_device->p_dev, USB_HOST_GET_DMA_IRQ_VECTOR, (uint32)NULL, (uint32)NULL));
|
||||
while(head->next != first)
|
||||
{
|
||||
head = head->next;
|
||||
count++;
|
||||
}
|
||||
irq_enable(usb_device_ioctl(uvc_device->p_dev, USB_HOST_GET_DMA_IRQ_VECTOR, (uint32)NULL, (uint32)NULL));
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void uvc_device_user_free_blank_node(void* device, struct list_head *del)
|
||||
{
|
||||
UVC_Device* uvc_device = (UVC_Device*)device;
|
||||
UVC_BLANK *uvc_b = (UVC_BLANK *)del;
|
||||
|
||||
if (!uvc_device || uvc_device->is_register == UVC_DEVICE_REGISTER_BUSY || uvc_device->is_register == UVC_DEVICE_REGISTER_BUSY) {
|
||||
return ;
|
||||
}
|
||||
|
||||
// os_printf("%s %d\n", __FUNCTION__, __LINE__);
|
||||
|
||||
sys_dcache_invalid_range((uint32_t*)uvc_b->buf_ptr, uvc_b->blank_len);
|
||||
|
||||
uint32_t flags = disable_irq();
|
||||
|
||||
list_move(del, &uvc_device->free_uvc_tab);
|
||||
|
||||
enable_irq(flags);
|
||||
}
|
||||
|
||||
void uvc_device_user_del_frame(void* device, void *get_f)
|
||||
{
|
||||
UVC_Device* uvc_device = (UVC_Device*)device;
|
||||
|
||||
if (!uvc_device || uvc_device->is_register == UVC_DEVICE_REGISTER_BUSY || uvc_device->is_register == UVC_DEVICE_REGISTER_BUSY) {
|
||||
return;
|
||||
}
|
||||
|
||||
// os_printf("%s %d\n", __FUNCTION__, __LINE__);
|
||||
|
||||
|
||||
uvc_device_free_get_blank_node_list(get_f, &uvc_device->free_uvc_tab);
|
||||
|
||||
}
|
||||
|
||||
/* ------------------------------- UVC数据包解析状态机 ------------------------------- */
|
||||
#define UVC_DEVICE_CHECK_HEADER_EOH
|
||||
#define UVC_DEVICE_BULK_CHECK_MJPEG_HEADER
|
||||
// #define UVC_DEVICE_CHECK_PTS
|
||||
|
||||
void process_uvc_payload(uint8_t dev_num, uint8_t ep_type, uint8_t video_format, uint8_t *payload, uint32_t payload_len, bool drop) {
|
||||
UVC_Device* dev = find_uvc_device(dev_num);
|
||||
if (!dev || !payload || payload_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 强制丢帧处理
|
||||
if (drop) {
|
||||
//释放当前正在处理的帧(如果存在)
|
||||
UVC_MANAGE *frame = dev->current_frame;
|
||||
_os_printf("Drop frame %x\n", frame);
|
||||
if (frame) {
|
||||
// 重置帧状态
|
||||
uvc_device_free_err_frame(dev, frame);
|
||||
dev->current_frame = NULL;
|
||||
}
|
||||
goto _exit; // 直接返回,不处理后续数据
|
||||
}
|
||||
|
||||
if(dev->filter_count > 0) {
|
||||
dev->filter_count--;
|
||||
goto _exit; // 直接返回,不处理后续数据
|
||||
}
|
||||
|
||||
struct video_payload_header *header = NULL;
|
||||
uint8_t header_len = 0;
|
||||
uint8_t *data_ptr = NULL;
|
||||
uint32_t data_len = 0;
|
||||
uint8_t cur_fid = 0;
|
||||
bool valid_header = false;
|
||||
|
||||
// 包头有效性验证
|
||||
if (payload_len > payload[0]
|
||||
&& (payload[0] == 0x0C || (payload[0] == 0x02 && !(payload[1] & 0x0C)) || (payload[0] == 0x06 && !(payload[1] & 0x08)))
|
||||
&& !(payload[1] & 0x30)
|
||||
#ifdef UVC_DEVICE_CHECK_HEADER_EOH
|
||||
&& (payload[0] == 0x02 ? payload[1] & 0x80 : 1)
|
||||
#endif
|
||||
#ifdef UVC_DEVICE_BULK_CHECK_MJPEG_HEADER
|
||||
&& ((((ep_type & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_BULK) && (video_format == USBH_VIDEO_FORMAT_MJPEG)) ? (payload_len >= payload[0] + 2 && payload[payload[0]] == 0xFF && payload[payload[0] + 1] == 0xD8) : 1)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
//os_printf("UVC: Valid header detected\n");
|
||||
//os_printf("UVC: Payload [0]:%x [1]:%x [payload[0]]:%x [payload[0] + 1]:%x\n", payload[0], payload[1], payload[payload[0]], payload[payload[0] + 1]);
|
||||
valid_header = true;
|
||||
|
||||
switch(dev->initial_fid_detected)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
header = (struct video_payload_header *)payload;
|
||||
dev->expected_fid = header->headerInfoUnion.headerInfoBitmap.FID;
|
||||
// os_printf("UVC: Initial FID detected: %d\n", dev->expected_fid);
|
||||
dev->initial_fid_detected = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
header = (struct video_payload_header *)payload;
|
||||
cur_fid = header->headerInfoUnion.headerInfoBitmap.FID;
|
||||
// os_printf("UVC: Current FID detected: %d\n", cur_fid);
|
||||
if(cur_fid != dev->expected_fid){
|
||||
dev->initial_fid_detected = 2;
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
//os_printf("e UVC: Payload [0]:%x [1]:%x [payload[0]]:%x [payload[0] + 1]:%x\n", payload[0], payload[1], payload[payload[0]], payload[payload[0] + 1]);
|
||||
};
|
||||
|
||||
//初始化变量
|
||||
if (valid_header == true) {
|
||||
header = (struct video_payload_header *)payload;
|
||||
cur_fid = header->headerInfoUnion.headerInfoBitmap.FID;
|
||||
header_len = header->bHeaderLength;
|
||||
data_ptr = payload + header_len;
|
||||
data_len = payload_len - header_len;
|
||||
// os_printf("UVC: Header length: %d, Data: %x Data length: %d\n", header_len, data_ptr, data_len);
|
||||
} else {
|
||||
if(payload_len == payload[0]
|
||||
&& (payload[0] == 0x0C || (payload[0] == 0x02 && !(payload[1] & 0x0C)) || (payload[0] == 0x06 && !(payload[1] & 0x08)))) {
|
||||
cur_fid = dev->last_fid;
|
||||
data_len = 0;
|
||||
valid_header = true;
|
||||
header = (struct video_payload_header *)payload;
|
||||
header_len = header->bHeaderLength;
|
||||
//os_printf("valid_header true\n");
|
||||
}else{
|
||||
cur_fid = dev->last_fid;
|
||||
data_ptr = payload;
|
||||
data_len = payload_len;
|
||||
// os_printf("UVC: Header length: %d, Data: %x Data length: %d\n", header_len, data_ptr, data_len);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取当前帧管理结构
|
||||
UVC_MANAGE *frame = dev->current_frame;
|
||||
//os_printf("UVC: Current frame: %x\n", frame);
|
||||
|
||||
// 检查是否为帧起始
|
||||
if (valid_header == true) {
|
||||
|
||||
// 处理错误标志
|
||||
if (header->headerInfoUnion.headerInfoBitmap.ERR) {
|
||||
uvc_device_free_err_frame(dev, frame); // 异常结束
|
||||
dev->current_blank = NULL;
|
||||
dev->current_frame = NULL;
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
// FID变化处理(仅当有有效包头时)
|
||||
if ((frame ? (dev->last_fid != cur_fid) : 0)) {
|
||||
if(((ep_type & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_ISOC))
|
||||
{
|
||||
//os_printf("[UVC] FID changed %d->%d payload[0]:0x%x payload[1]:0x%x\n", dev->last_fid, cur_fid, payload[0], payload[1]);
|
||||
uvc_device_free_err_frame(dev, frame);//结束
|
||||
dev->current_blank = NULL;
|
||||
dev->current_frame = NULL;
|
||||
frame = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UVC_DEVICE_CHECK_PTS
|
||||
if (header->headerInfoUnion.headerInfoBitmap.PTS) {
|
||||
if ((frame ? (dev->dwPresentationTime != header->dwPresentationTime) : 0)) {
|
||||
uvc_device_free_err_frame(dev, frame);//结束
|
||||
dev->current_blank = NULL;
|
||||
dev->current_frame = NULL;
|
||||
frame = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(frame == NULL && data_len > 0) {
|
||||
// 获取新帧
|
||||
struct list_head *new_frame_list = uvc_device_get_new_frame(dev, 1);
|
||||
if (!new_frame_list) {
|
||||
// 抢占模式获取可用帧
|
||||
_os_printf("_D1_");
|
||||
goto _exit; // 无法获取帧,丢弃数据
|
||||
}
|
||||
|
||||
frame = list_entry(new_frame_list, UVC_MANAGE, list);
|
||||
// os_printf("uvc_device_get_new_frame frame:%x\n", frame);
|
||||
|
||||
if (&dev->uvc_msg_frame[0] != frame && &dev->uvc_msg_frame[1] != frame) {
|
||||
os_printf("ERR UVC: Frame %x\n", frame);
|
||||
while(1);
|
||||
} else {
|
||||
|
||||
}
|
||||
if(video_format == USBH_VIDEO_FORMAT_MJPEG && (payload[payload[0]] != 0xFF || payload[payload[0] + 1] != 0xD8)){
|
||||
uvc_device_free_err_frame(dev, frame);//结束
|
||||
dev->current_blank = NULL;
|
||||
dev->current_frame = NULL;
|
||||
goto _exit;
|
||||
}
|
||||
dev->current_frame = frame;
|
||||
dev->current_blank = NULL;
|
||||
dev->last_fid = cur_fid;
|
||||
|
||||
#ifdef UVC_DEVICE_CHECK_PTS
|
||||
if (header->headerInfoUnion.headerInfoBitmap.PTS) {
|
||||
dev->dwPresentationTime = header->dwPresentationTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 初始化帧信息
|
||||
frame->frame_counter = dev->frame_counter;;
|
||||
frame->frame_len = 0;
|
||||
frame->data_len = 0;
|
||||
frame->cpbuff = NULL;
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
//由于存在有效包头的判断,假如一直没有识别到有效包头,则不会获取到帧,不执行拷贝动作
|
||||
if (frame) {
|
||||
// 处理数据填充
|
||||
uint32_t _data_len = data_len;
|
||||
while (_data_len > 0) {
|
||||
UVC_BLANK *blank = NULL;
|
||||
uint8_t blank_loop = 0;
|
||||
|
||||
if(dev->current_blank) {
|
||||
blank = dev->current_blank;
|
||||
if (blank->re_space == 0) {
|
||||
// 当前节点已满,强制分配新节点
|
||||
blank->busy = UVC_DEVICE_BLANK_STATE_AVAILABLE;
|
||||
struct list_head *new_node = uvc_device_get_blank_node(&frame->list, &dev->free_uvc_tab);
|
||||
if (!new_node) {
|
||||
_os_printf("_D2_");
|
||||
uvc_device_free_err_frame(dev, frame);
|
||||
dev->current_blank = NULL;
|
||||
dev->current_frame = NULL;
|
||||
// os_printf("Error: Failed to allocate new blank node!\n");
|
||||
goto _exit;
|
||||
}
|
||||
blank_loop = blank->blank_loop;
|
||||
blank = list_entry(new_node, UVC_BLANK, list);
|
||||
dev->current_blank = blank;
|
||||
blank->busy = UVC_DEVICE_BLANK_STATE_BUSY;
|
||||
blank->blank_loop = blank_loop + 1;
|
||||
blank->frame_counter = frame->frame_counter;
|
||||
blank->re_space = blank->blank_len;
|
||||
frame->cpbuff = blank->buf_ptr; // 重置写入指针到新节点
|
||||
// os_printf("new blank:%x %x blank->blank_loop:%d\r\n", blank, blank->buf_ptr, blank->blank_loop);
|
||||
}
|
||||
} else {
|
||||
struct list_head *blank_node = uvc_device_get_blank_node(&frame->list, &dev->free_uvc_tab);
|
||||
if (!blank_node) {
|
||||
_os_printf("_D3_");
|
||||
uvc_device_free_err_frame(dev, frame);// 异常结束
|
||||
dev->current_blank = NULL;
|
||||
dev->current_frame = NULL;
|
||||
// os_printf("Error: No free blank nodes available!\n");
|
||||
goto _exit;
|
||||
}
|
||||
blank = list_entry(blank_node, UVC_BLANK, list);
|
||||
dev->current_blank = blank;
|
||||
blank->busy = UVC_DEVICE_BLANK_STATE_BUSY;
|
||||
blank->blank_loop = blank_loop;
|
||||
blank->frame_counter = frame->frame_counter;
|
||||
blank->re_space = blank->blank_len;
|
||||
frame->cpbuff = blank->buf_ptr; // 初始化写入指针
|
||||
// os_printf("blank:%x %x blank->blank_loop:%d\r\n", blank, blank->buf_ptr, blank->blank_loop);
|
||||
}
|
||||
|
||||
if(frame->cpbuff == NULL) {
|
||||
os_printf("Error: cpbuff is NULL!\n");
|
||||
while(1);
|
||||
}
|
||||
|
||||
if(blank) {
|
||||
// 计算实际可拷贝长度
|
||||
uint32_t copy_len = MIN(_data_len, blank->re_space);
|
||||
if (copy_len > 0) {
|
||||
// os_printf("copy_len:%d %x %x\r\n", copy_len, data_ptr, frame->cpbuff);
|
||||
hw_memcpy(frame->cpbuff, data_ptr, copy_len);
|
||||
data_ptr += copy_len;
|
||||
_data_len -= copy_len;
|
||||
frame->cpbuff += copy_len; // 更新当前写入位置
|
||||
frame->frame_len += copy_len;
|
||||
blank->re_space -= copy_len;
|
||||
// 标记节点为可用(若已填满)
|
||||
blank->busy = (blank->re_space > 0) ? UVC_DEVICE_BLANK_STATE_BUSY : UVC_DEVICE_BLANK_STATE_AVAILABLE;
|
||||
} else {
|
||||
// 数据长度为0或异常情况,退出循环
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
os_printf("Error: blank is NULL!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
//未能获取到frame
|
||||
}
|
||||
#ifdef UVC_DEVICE_BULK_CHECK_MJPEG_HEADER
|
||||
if(((ep_type & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_BULK) && (video_format == USBH_VIDEO_FORMAT_MJPEG))
|
||||
{
|
||||
if ((data_len >= 2) && (payload[data_len - 2] == 0xFF && payload[data_len - 1] == 0xD9) && dev->current_frame)
|
||||
{
|
||||
// os_printf("[UVC] MJPEG Frame end\n");
|
||||
uvc_device_end_frame(dev, frame);
|
||||
if (dev->current_blank) {
|
||||
dev->current_blank->busy = UVC_DEVICE_BLANK_STATE_AVAILABLE;
|
||||
}
|
||||
dev->current_blank = NULL; // 重置当前节点
|
||||
dev->current_frame = NULL; // 重置当前帧
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
{
|
||||
// 检查帧结束标志
|
||||
if (valid_header == true && header->headerInfoUnion.headerInfoBitmap.EOI && dev->current_frame) {
|
||||
// os_printf("[UVC] Frame end\n");
|
||||
uvc_device_end_frame(dev, frame);
|
||||
if (dev->current_blank) {
|
||||
dev->current_blank->busy = UVC_DEVICE_BLANK_STATE_AVAILABLE;
|
||||
}
|
||||
dev->current_blank = NULL; // 重置当前节点
|
||||
dev->current_frame = NULL; // 重置当前帧
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user