Files
TAIXIN/sdk/lib/video/dvp/jpeg/jpg_common.c

460 lines
13 KiB
C

#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;
}