#include "basic_include.h" #include "lib/multimedia/msi.h" #include "stream_define.h" #include "lib/video/dvp/jpeg/jpg.h" #include "dev/jpg/hgjpg.h" #include "lib/heap/av_heap.h" #include "lib/heap/av_psram_heap.h" /*********************************************************** * 可以存放mjpg的公用函数组件 **********************************************************/ #define HARDWARE_JPG_NUM 2 // data申请空间函数 #define STREAM_MALLOC av_psram_malloc #define STREAM_FREE av_psram_free #define STREAM_ZALLOC av_psram_zalloc // 结构体申请空间函数 #define STREAM_LIBC_MALLOC av_malloc #define STREAM_LIBC_FREE av_free #define STREAM_LIBC_ZALLOC av_zalloc /***************************************************************** * 增加mjpg模块锁,主要用于复用的时候需要对mjeg模块锁 ****************************************************************/ typedef struct { os_event_t jpg_event; uint8_t init; uint8_t lock_value; uint8_t last_lock_value; } jpg_mutex; enum { JPG_LOCK = BIT(0), }; static jpg_mutex *jpg_mutex_table[HARDWARE_JPG_NUM]; int32 jpg_mutex_init() { int32_t ret = 0; int32_t res = 0; jpg_mutex *mutex = (jpg_mutex *) STREAM_LIBC_ZALLOC(sizeof(jpg_mutex) * 2); jpg_mutex_table[0] = &mutex[0]; jpg_mutex_table[1] = &mutex[1]; res = os_event_init(&jpg_mutex_table[0]->jpg_event); ret |= res; if (!res) { jpg_mutex_table[0]->init = 1; os_event_set(&jpg_mutex_table[0]->jpg_event, JPG_LOCK, NULL); } res = os_event_init(&jpg_mutex_table[1]->jpg_event); ret |= res; if (!res) { jpg_mutex_table[1]->init = 1; os_event_set(&jpg_mutex_table[1]->jpg_event, JPG_LOCK, NULL); } os_printf("%s:%d\tret:%d\n", __FUNCTION__, __LINE__, ret); return ret; } /************************************************************************ * jpgid: 硬件jpg模块ID,0:jpg0 1:jpg1 * value: 设置lock的值,只有一致才能释放 * last_value: 如果不为NULL,则返回上一次的锁值 ***********************************************************************/ int32_t jpg_mutex_lock(uint32_t jpgid, uint8_t value, uint8_t *last_value) { ASSERT(jpgid < HARDWARE_JPG_NUM); jpg_mutex *mutex = jpg_mutex_table[jpgid]; ASSERT(mutex && mutex->init == 1); uint32_t rflags; if (mutex->lock_value || value == 0) { if (last_value) { *last_value = mutex->last_lock_value; } return 1; } // 如果获取到锁,就将lock_value设置value int32_t ret = os_event_wait(&mutex->jpg_event, JPG_LOCK, &rflags, OS_EVENT_WMODE_CLEAR, 0); if (ret == 0) { if (last_value) { *last_value = mutex->last_lock_value; } mutex->lock_value = value; } return ret; } /******************************************************** * jpgid: 硬件jpg模块ID,0:jpg0 1:jpg1 * value: 设置lock的值,只有一致才能释放 ******************************************************/ int32_t jpg_mutex_unlock(uint32_t jpgid, int32_t value) { ASSERT(jpgid < HARDWARE_JPG_NUM); jpg_mutex *mutex = jpg_mutex_table[jpgid]; ASSERT(mutex && mutex->init == 1); int32_t ret = 1; // 只有相同的值才支持解锁 if (mutex->lock_value == value) { ret = os_event_set(&mutex->jpg_event, JPG_LOCK, NULL); if (ret == 0) { mutex->last_lock_value = mutex->lock_value; mutex->lock_value = 0; } } return ret; } int32_t jpg_mutex_unlock_check(uint32_t jpgid, int32_t value) { ASSERT(jpgid < HARDWARE_JPG_NUM); jpg_mutex *mutex = jpg_mutex_table[jpgid]; ASSERT(mutex && mutex->init == 1); int32_t ret = 1; // 只有相同的值才支持解锁 if (mutex->lock_value == value) { ret = os_event_set(&mutex->jpg_event, JPG_LOCK, NULL); if (ret == 0) { mutex->lock_value = 0; } } return ret; } struct jpg_mem_list_s; #define JPG_MEM_LIST_COUNT (4) struct jpg_mem_chunk { struct jpg_mem_chunk *next; uint8_t del : 1, jpg_mem_map : 5, rev : 2; uint8_t count; uint16_t len; struct jpg_mem_list_s *jpg_mem_list; uint32_t t_bitmap; // 当前chunk的内存位图 uint32_t bitmap; // 内存位图 struct jpg_mem *mem[32]; }; // 内存池列表,最多N个内存池 struct jpg_mem_list_s { uint32_t bitmap; // 1代表有空间,0代表没有空间 uint32_t total_count; // 记录当前内存池最大的空间数量,动态增加以及动态释放 // 剩余总共内存块数量,如果有,就判断bitmap,从最低位开始寻找,释放空间优先释放高位的内存块,低位内存块尽量在完全没用的时候才释放(防止频繁申请),可以通过一个超时机制去释放(影响立刻申请空间的模块,也可以实现一个立刻释放的命令) uint32_t remain_block_count; struct jpg_mem_chunk *last_chunk; // 记录上一次申请空间的chunk,如果释放,还需要检查是否是最低位的,尽量从最低位的chunk申请(利于释放空间) struct jpg_mem_chunk *chunk[JPG_MEM_LIST_COUNT]; }; // 32byte对齐,所以前面留32byte作为其他数据保存作用 struct jpg_mem { struct jpg_mem_chunk *chunk; // chunk的地址,相当于申请空间的chunk struct jpg_mem *next; uint32_t bitmap; // 固定只有一个bit被置位(代表内存块的位置) uint32_t rev[5]; }; static struct jpg_mem_list_s jpg_mem_list; // mjpg的内存管理,暂时不支持动态扩展,相当于预先分配 // 正常应该是可以后面动态添加以及删除 struct jpg_mem_chunk *jpg_mem_manage_init(uint8_t chunk_block) { if (chunk_block > 32) { chunk_block = 32; } if (!chunk_block) { return NULL; } uint8_t ret = 1; // 先去申请空间,清除cache问题,然后再挂接到链表中 uint32_t malloc_count = 0; struct jpg_mem_chunk *chunk = NULL; chunk = (struct jpg_mem_chunk *) STREAM_ZALLOC(sizeof(struct jpg_mem_chunk)); if (!chunk) { goto jpg_mem_manage_init_end; } chunk->len = 16 * 1024; for (malloc_count = 0; malloc_count < chunk_block; malloc_count++) { chunk->mem[malloc_count] = (struct jpg_mem *) STREAM_MALLOC(16 * 1024 + sizeof(struct jpg_mem)); if (chunk->mem[malloc_count]) { sys_dcache_invalid_range((uint32_t *) chunk->mem[malloc_count], 16 * 1024 + sizeof(struct jpg_mem)); chunk->t_bitmap |= BIT(malloc_count); chunk->mem[malloc_count]->bitmap = BIT(malloc_count); chunk->mem[malloc_count]->chunk = chunk; } } chunk->bitmap = chunk->t_bitmap; chunk->count = malloc_count + 1; // 没有申请到空间,返回错误 if (!chunk->bitmap) { goto jpg_mem_manage_init_end; } ret = 0; jpg_mem_manage_init_end: if (ret) { if (chunk) { STREAM_FREE(chunk); chunk = NULL; } } return chunk; } // 释放一个chunk static void free_jpg_chunk(struct jpg_mem_chunk *chunk) { if (chunk) { // 不一致,不能释放,报错 ASSERT(chunk->t_bitmap == chunk->bitmap); for (int i = 0; i < chunk->count; i++) { ASSERT(chunk->mem[i]); STREAM_FREE(chunk->mem[i]); chunk->mem[i] = NULL; } STREAM_FREE(chunk); } } // 增加一个内存块到列表 uint8_t add_jpg_block(uint8_t chunk_block) { uint8_t ret = 1; uint8_t map = 0; struct jpg_mem_chunk *chunk = jpg_mem_manage_init(chunk_block); if (chunk) { // 检查最低位是否有0,代表空闲 if (jpg_mem_list.bitmap) { map = __builtin_ctz(~jpg_mem_list.bitmap); } os_printf("jpg_block map:%d\n", map); // list没有满,则可以添加 if (map < JPG_MEM_LIST_COUNT) { uint32_t flags = disable_irq(); jpg_mem_list.chunk[map] = chunk; jpg_mem_list.bitmap |= BIT(map); jpg_mem_list.total_count = chunk->count; jpg_mem_list.remain_block_count += chunk->count; chunk->jpg_mem_list = &jpg_mem_list; chunk->jpg_mem_map = map; enable_irq(flags); ret = 0; } // 释放chunk else { free_jpg_chunk(chunk); } } return ret; } // 获取一个有内存块的chunk static struct jpg_mem_chunk *get_free_chunk() { struct jpg_mem_chunk *chunk; uint8_t map; // os_printf("jpg_mem_list.last_chunk:%X\n", jpg_mem_list.last_chunk); if (jpg_mem_list.last_chunk) { chunk = jpg_mem_list.last_chunk; } else { if (jpg_mem_list.bitmap) { map = __builtin_ctz(jpg_mem_list.bitmap); chunk = jpg_mem_list.chunk[map]; } else { chunk = NULL; } } return chunk; } void *get_jpg_node(uint16_t *len) { struct jpg_mem *buf = NULL; uint32_t flags = disable_irq(); struct jpg_mem_chunk *next_chunk = get_free_chunk(); uint8_t map; uint8_t change = 1; if (next_chunk && next_chunk->bitmap) { map = __builtin_ctz(next_chunk->bitmap); buf = next_chunk->mem[map]; buf->next = NULL; buf += 1; next_chunk->bitmap &= (~BIT(map)); // os_printf("next_chunk->bitmap:%X\n", next_chunk->bitmap); if (!next_chunk->bitmap) { next_chunk->jpg_mem_list->bitmap &= (~BIT(next_chunk->jpg_mem_map)); next_chunk->jpg_mem_list->last_chunk = NULL; } else { if (next_chunk->jpg_mem_list->last_chunk) { if (next_chunk->jpg_mem_list->last_chunk->jpg_mem_map < next_chunk->jpg_mem_map) { change = 0; } } if (change) { next_chunk->jpg_mem_list->last_chunk = next_chunk; } } if (len) { *len = next_chunk->len; } } else { if (len) { *len = 0; } } enable_irq(flags); if (buf) { // os_printf("malloc map:%X\tbuf:%X\taddr:%X\n",BIT(map),buf,RETURN_ADDR()); } else { os_printf("%s:%d err\n", __FUNCTION__, __LINE__); } return (void *) buf; } uint16_t get_node_len(void *buf) { struct jpg_mem *node = (struct jpg_mem *) buf; if (node) { node -= 1; return node->chunk->len; } else { return 0; } } // 获取node是否有足够的保留空间来填充额外的数据 void *get_node_rev(void *buf, uint32_t rev_len) { struct jpg_mem *node = (struct jpg_mem *) buf; if (node) { node -= 1; if (sizeof(node->rev) > rev_len) { return node->rev; } } return NULL; } void free_jpg_node(void *buf) { // os_printf("buf:%X\n",buf); struct jpg_mem *free_buf = (struct jpg_mem *) buf; struct jpg_mem_chunk *chunk; free_buf -= 1; chunk = free_buf->chunk; uint8_t change = 1; // 正常应该要检查是否符合,这里默认传入的地址是正确的 uint32_t flags = disable_irq(); // uint32_t map = free_buf->bitmap; chunk->bitmap |= free_buf->bitmap; chunk->jpg_mem_list->bitmap |= BIT(chunk->jpg_mem_map); // os_printf("chunk->bitmap:%X\n", chunk->bitmap); if (chunk->jpg_mem_list->last_chunk) { if (chunk->jpg_mem_list->last_chunk->jpg_mem_map < chunk->jpg_mem_map) { change = 0; } } if (change) { chunk->jpg_mem_list->last_chunk = chunk; } enable_irq(flags); // os_printf("free map:%X\tbuf:%X\n",map,buf); // 正常应该要检查当前chunk是否要被释放,如果需要被释放,是要考虑释放空间 } // 将一个节点放到另一个节点 void *push_node(void *head, void *next) { struct jpg_mem *h = (struct jpg_mem *) head; struct jpg_mem *n = (struct jpg_mem *) next; if (head) { h -= 1; n -= 1; h->next = n; } // os_printf("head:%X\tnext:%X\n",head,next); return next; } // pop一个节点头出去 void *pop_node(void *head) { if (!head) { return NULL; } struct jpg_mem *h = (struct jpg_mem *) head; h -= 1; if (!h->next) { return NULL; } return h->next + 1; }