/********************************************************************************************************** * 虚拟的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; }