317 lines
10 KiB
C
317 lines
10 KiB
C
|
|
/**********************************************************************************************************
|
||
|
|
* 虚拟的P0和P1,使用dma2d去实现p0和p1的叠层,最终目的是为了让lcd不旋转(省sram),直接预先旋转叠层给到video显示
|
||
|
|
* ********************************************************************************************************/
|
||
|
|
#include "basic_include.h"
|
||
|
|
|
||
|
|
#include "lib/multimedia/msi.h"
|
||
|
|
#include "osal/work.h"
|
||
|
|
#include "stream_define.h"
|
||
|
|
#include "lib/heap/av_heap.h"
|
||
|
|
#include "lib/heap/av_psram_heap.h"
|
||
|
|
|
||
|
|
|
||
|
|
extern void yuv_blk_cpy(uint8 *des, uint8* src,uint32 des_w,uint32 des_h, uint32 src_w, uint32_t src_h,uint32 x,uint32 y);
|
||
|
|
|
||
|
|
// 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
|
||
|
|
|
||
|
|
#define MAX_RX 8
|
||
|
|
|
||
|
|
struct sim_video_msi_s
|
||
|
|
{
|
||
|
|
struct os_work work;
|
||
|
|
struct msi *msi;
|
||
|
|
struct fbpool tx_pool;
|
||
|
|
struct framebuff *p0;
|
||
|
|
struct framebuff *p1;
|
||
|
|
uint16_t w, h;
|
||
|
|
uint16_t *filter; //数组去进行过滤,0为结束
|
||
|
|
// 设置哪个在顶层,这个模块只有P0和P1
|
||
|
|
uint8_t top;
|
||
|
|
};
|
||
|
|
|
||
|
|
static int32 sim_video_work(struct os_work *work)
|
||
|
|
{
|
||
|
|
struct sim_video_msi_s *sim_video = (struct sim_video_msi_s *)work;
|
||
|
|
struct framebuff *fb;
|
||
|
|
struct framebuff *output_fb;
|
||
|
|
uint32_t *buf;
|
||
|
|
fb = msi_get_fb(sim_video->msi, 0);
|
||
|
|
// 接收到一个fb,就需要判断类型(p0,p1),然后申请空间去进行叠层
|
||
|
|
if (fb)
|
||
|
|
{
|
||
|
|
if (fb->stype == FSTYPE_YUV_P0)
|
||
|
|
{
|
||
|
|
if (sim_video->p0)
|
||
|
|
{
|
||
|
|
msi_delete_fb(NULL, sim_video->p0);
|
||
|
|
}
|
||
|
|
sim_video->p0 = fb;
|
||
|
|
}
|
||
|
|
else if (fb->stype == FSTYPE_YUV_P1)
|
||
|
|
{
|
||
|
|
if (sim_video->p1)
|
||
|
|
{
|
||
|
|
msi_delete_fb(NULL, sim_video->p1);
|
||
|
|
}
|
||
|
|
sim_video->p1 = fb;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
msi_delete_fb(NULL, fb);
|
||
|
|
fb = NULL;
|
||
|
|
goto sim_video_work_end;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 不需要叠层,帮忙转发就好了,但是需要保留p0或者p1
|
||
|
|
// 因为output会发送完毕后会执行删除,所以要保留,不能被删除
|
||
|
|
if (fb && !(sim_video->p0 && sim_video->p1))
|
||
|
|
{
|
||
|
|
// 克隆一个fb发出去,但是因为这个sim_video是给到P0显示,所以需要将stype转换成FSTYPE_YUV_P0
|
||
|
|
output_fb = fb_clone(fb, fb->mtype<<8|FSTYPE_YUV_P0, sim_video->msi);
|
||
|
|
if (output_fb)
|
||
|
|
{
|
||
|
|
msi_output_fb(sim_video->msi, output_fb);
|
||
|
|
}
|
||
|
|
|
||
|
|
goto sim_video_work_end;
|
||
|
|
}
|
||
|
|
//os_printf("sim video p0:%X\tp1:%X\n",sim_video->p0,sim_video->p1);
|
||
|
|
// 开始申请空间
|
||
|
|
buf = (uint32_t *)STREAM_MALLOC(sim_video->w * sim_video->h * 3 / 2);
|
||
|
|
if (!buf)
|
||
|
|
{
|
||
|
|
goto sim_video_work_end;
|
||
|
|
}
|
||
|
|
|
||
|
|
output_fb = fbpool_get(&sim_video->tx_pool, 0, sim_video->msi);
|
||
|
|
if (!output_fb)
|
||
|
|
{
|
||
|
|
STREAM_FREE(buf);
|
||
|
|
goto sim_video_work_end;
|
||
|
|
}
|
||
|
|
output_fb->data = (uint8_t*)buf;
|
||
|
|
output_fb->len = sim_video->w * sim_video->h * 3 / 2;
|
||
|
|
|
||
|
|
// 叠层
|
||
|
|
{
|
||
|
|
uint16_t p0_w= 0, p0_h = 0, p1_w = 0, p1_h = 0;
|
||
|
|
struct yuv_arg_s *yuv_msg_p0 = NULL;
|
||
|
|
struct yuv_arg_s *yuv_msg_p1 = NULL;
|
||
|
|
if (sim_video->p0)
|
||
|
|
{
|
||
|
|
yuv_msg_p0 = (struct yuv_arg_s *)sim_video->p0->priv;
|
||
|
|
p0_w = yuv_msg_p0->out_w;
|
||
|
|
p0_h = yuv_msg_p0->out_h;
|
||
|
|
}
|
||
|
|
if (sim_video->p1)
|
||
|
|
{
|
||
|
|
yuv_msg_p1 = (struct yuv_arg_s *)sim_video->p1->priv;
|
||
|
|
p1_w = yuv_msg_p1->out_w;
|
||
|
|
p1_h = yuv_msg_p1->out_h;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 判断一下p0_w和p1_w是否和当前的w,h匹配,不匹配,可能底部需要配置颜色才可以
|
||
|
|
uint16_t p_w = p0_w > p1_w ? p0_w : p1_w;
|
||
|
|
uint16_t p_h = p0_h > p1_h ? p0_h : p1_h;
|
||
|
|
// 如果没有匹配,设置颜色
|
||
|
|
if (!(p_w >= sim_video->w && p_h >= sim_video->h))
|
||
|
|
{
|
||
|
|
hw_memset((uint8_t*)buf, 0, sim_video->w * sim_video->h);
|
||
|
|
hw_memset((uint8_t*)buf+sim_video->w * sim_video->h,0x80,sim_video->w * sim_video->h / 2);
|
||
|
|
sys_dcache_invalid_range(buf, sim_video->w * sim_video->h * 3 / 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
//os_printf("yuv_msg_p1->x:%d\ty:%d\n",yuv_msg_p1->x,yuv_msg_p1->y);
|
||
|
|
//os_printf("yuv_msg_p0->x:%d\ty:%d\n",yuv_msg_p0->x,yuv_msg_p0->y);
|
||
|
|
if (sim_video->top == 0)
|
||
|
|
{
|
||
|
|
|
||
|
|
if (yuv_msg_p1)
|
||
|
|
{
|
||
|
|
yuv_blk_cpy((uint8_t*)buf, sim_video->p1->data, sim_video->w, sim_video->h, p1_w, p1_h, yuv_msg_p1->x, yuv_msg_p1->y);
|
||
|
|
}
|
||
|
|
if (yuv_msg_p0)
|
||
|
|
{
|
||
|
|
yuv_blk_cpy((uint8_t*)buf, sim_video->p0->data, sim_video->w, sim_video->h, p0_w, p0_h, yuv_msg_p0->x, yuv_msg_p0->y);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (yuv_msg_p0)
|
||
|
|
{
|
||
|
|
yuv_blk_cpy((uint8_t*)buf, sim_video->p0->data, sim_video->w, sim_video->h, p0_w, p0_h, yuv_msg_p0->x, yuv_msg_p0->y);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (yuv_msg_p1)
|
||
|
|
{
|
||
|
|
yuv_blk_cpy((uint8_t*)buf, sim_video->p1->data, sim_video->w, sim_video->h, p1_w, p1_h, yuv_msg_p1->x, yuv_msg_p1->y);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
output_fb->mtype = F_YUV;
|
||
|
|
output_fb->stype = FSTYPE_YUV_P0;
|
||
|
|
msi_output_fb(sim_video->msi, output_fb);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
sim_video_work_end:
|
||
|
|
os_run_work_delay(work, 1);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
static int sim_video_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
|
||
|
|
{
|
||
|
|
struct sim_video_msi_s *sim_video = (struct sim_video_msi_s *)msi->priv;
|
||
|
|
int ret = RET_OK;
|
||
|
|
switch (cmd_id)
|
||
|
|
{
|
||
|
|
case MSI_CMD_POST_DESTROY:
|
||
|
|
{
|
||
|
|
struct framebuff *fb;
|
||
|
|
// 释放资源fb资源文件,priv是独立申请的
|
||
|
|
while (1)
|
||
|
|
{
|
||
|
|
fb = fbpool_get(&sim_video->tx_pool, 0, NULL);
|
||
|
|
if (!fb)
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
// 预分配空间释放
|
||
|
|
if (fb->priv)
|
||
|
|
{
|
||
|
|
STREAM_LIBC_FREE(fb->priv);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
fbpool_destroy(&sim_video->tx_pool);
|
||
|
|
STREAM_LIBC_FREE(sim_video);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case MSI_CMD_TRANS_FB:
|
||
|
|
{
|
||
|
|
struct framebuff *fb = (struct framebuff *)param1;
|
||
|
|
|
||
|
|
if (fb->mtype != F_YUV)
|
||
|
|
{
|
||
|
|
//os_printf("not recv fb:%X\tcount:%d\n",fb,fb->users.counter);
|
||
|
|
ret = RET_ERR;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if(sim_video->filter)
|
||
|
|
{
|
||
|
|
//轮询类型是否有一致
|
||
|
|
ret = RET_ERR;
|
||
|
|
uint16_t *each = sim_video->filter;
|
||
|
|
while(*each)
|
||
|
|
{
|
||
|
|
//如果一致,返回OK
|
||
|
|
if(*each == fb->stype)
|
||
|
|
{
|
||
|
|
ret = RET_OK;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
each++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
|
||
|
|
case MSI_CMD_FREE_FB:
|
||
|
|
{
|
||
|
|
struct framebuff *fb = (struct framebuff *)param1;
|
||
|
|
// 如果不是克隆的,就自己释放
|
||
|
|
if (!fb->clone)
|
||
|
|
{
|
||
|
|
if (fb->data)
|
||
|
|
{
|
||
|
|
STREAM_FREE(fb->data);
|
||
|
|
fb->data = NULL;
|
||
|
|
}
|
||
|
|
fbpool_put(&sim_video->tx_pool, fb);
|
||
|
|
// 不需要内核去释放fb
|
||
|
|
ret = RET_OK + 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case MSI_CMD_PRE_DESTROY:
|
||
|
|
{
|
||
|
|
os_work_cancle2(&sim_video->work, 1);
|
||
|
|
if (sim_video->p0)
|
||
|
|
{
|
||
|
|
msi_delete_fb(NULL, sim_video->p0);
|
||
|
|
sim_video->p0 = NULL;
|
||
|
|
}
|
||
|
|
if (sim_video->p1)
|
||
|
|
{
|
||
|
|
msi_delete_fb(NULL, sim_video->p1);
|
||
|
|
sim_video->p1 = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
{
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct msi *sim_video_msi(const char *name, uint16_t w, uint16_t h, uint8_t top)
|
||
|
|
{
|
||
|
|
static const uint16_t sim_filter[3] = {FSTYPE_YUV_P0,FSTYPE_YUV_P1,FSTYPE_NONE};
|
||
|
|
// 设置1个接收,只是为了可以output_fb给到这个msi
|
||
|
|
struct msi *msi = msi_new(name, MAX_RX, NULL);
|
||
|
|
if (msi)
|
||
|
|
{
|
||
|
|
struct sim_video_msi_s *sim_video = (struct sim_video_msi_s *)msi->priv;
|
||
|
|
if (!sim_video)
|
||
|
|
{
|
||
|
|
sim_video = (struct sim_video_msi_s *)STREAM_LIBC_ZALLOC(sizeof(struct sim_video_msi_s));
|
||
|
|
}
|
||
|
|
sim_video->p0 = NULL;
|
||
|
|
sim_video->p1 = NULL;
|
||
|
|
sim_video->w = w;
|
||
|
|
sim_video->h = h;
|
||
|
|
sim_video->msi = msi;
|
||
|
|
sim_video->filter = (uint16_t*)sim_filter;
|
||
|
|
sim_video->top = top;
|
||
|
|
msi->priv = (void *)sim_video;
|
||
|
|
msi->action = sim_video_msi_action;
|
||
|
|
|
||
|
|
// 预分配结构体空间
|
||
|
|
uint32_t init_count = 0;
|
||
|
|
void *priv;
|
||
|
|
fbpool_init(&sim_video->tx_pool, MAX_RX);
|
||
|
|
while (init_count < MAX_RX)
|
||
|
|
{
|
||
|
|
priv = (void *)STREAM_LIBC_ZALLOC(sizeof(struct yuv_arg_s));
|
||
|
|
struct yuv_arg_s *yuv_msg = (struct yuv_arg_s *)priv;
|
||
|
|
yuv_msg->out_w = w;
|
||
|
|
yuv_msg->out_h = h;
|
||
|
|
yuv_msg->y_size = w * h;
|
||
|
|
yuv_msg->y_off = 0;
|
||
|
|
yuv_msg->uv_off = 0;
|
||
|
|
yuv_msg->del = NULL;
|
||
|
|
FBPOOL_SET_INFO(&sim_video->tx_pool, init_count, NULL, 0, priv);
|
||
|
|
init_count++;
|
||
|
|
}
|
||
|
|
|
||
|
|
msi->enable = 1;
|
||
|
|
|
||
|
|
//msi_add_output(sim_video->msi, NULL, R_VIDEO_P0);
|
||
|
|
|
||
|
|
OS_WORK_INIT(&sim_video->work, sim_video_work, 0);
|
||
|
|
os_run_work_delay(&sim_video->work, 1);
|
||
|
|
}
|
||
|
|
return msi;
|
||
|
|
}
|