#include "osd_encode_stream.h" #include "osal/work.h" #include "custom_mem/custom_mem.h" //data申请空间函数 #define STREAM_MALLOC custom_malloc_psram #define STREAM_FREE custom_free_psram #define STREAM_ZALLOC custom_zalloc_psram //结构体申请空间函数 #define STREAM_LIBC_MALLOC custom_malloc #define STREAM_LIBC_FREE custom_free #define STREAM_LIBC_ZALLOC custom_zalloc struct lvgl_osd_encode_s { struct os_work work; struct lcdc_device *lcd_dev; stream *s; uint8_t *osd_tmp_buf; uint32_t osd_tmp_buf_size; //如果data_send有,并且useful可用,代表data_send需要发送出去 struct data_structure *parent_data_s; uint32_t parent_type; //osd压缩后的数据长度 uint32_t data_len; //解码模块是否可用 uint8_t hardware_ready; }; static int32 osd_encode_work(struct os_work *work) { struct lvgl_osd_encode_s *osd_encode = (struct lvgl_osd_encode_s*)work; struct data_structure *data_s = NULL; //static int osd_encode_count = 0; static uint32_t osd_send_times = 0; //先检测一下解码模块是否可用 if(osd_encode->hardware_ready) { //os_printf("osd_encode work!!!!!!!!!!!!!!!!\n"); //检测一下是否有data_s需要先发送出去 if(osd_encode->parent_data_s) { //获取data_s,申请空间,发送数据 data_s = get_src_data_f(osd_encode->s); if(data_s) { data_s->type = osd_encode->parent_data_s->type; free_data(osd_encode->parent_data_s); osd_encode->parent_data_s = NULL; //为data_s申请空间 data_s->data = (void*)STREAM_MALLOC(osd_encode->data_len); if(data_s->data) { //os_printf("memcpy buf:%X\n",stream_self_cmd_func(osd_encode->s,OSD_HARDWARE_ENCODE_BUF,0)); //拷贝数据 hw_memcpy(data_s->data,(void*)stream_self_cmd_func(osd_encode->s,OSD_HARDWARE_ENCODE_BUF,0),(uint32)osd_encode->data_len); sys_dcache_clean_range(data_s->data, osd_encode->data_len); //数据类型保持一致 set_stream_real_data_len(data_s,osd_encode->data_len); //os_printf("%s:%d\tdata_s:%X\tosd_encode->data_len:%d\n",__FUNCTION__,__LINE__,data_s,osd_encode->data_len); send_data_to_stream(data_s); osd_send_times++; } //没有发送成功,则释放data_s先吧,下一次再发送 else { force_del_data(data_s); _os_printf("**********************"); } } } //重新检测一下,parent_data_s是否还存在,不存在就去看看是否有需要压缩的osd //会进入中断 if(!osd_encode->parent_data_s) { osd_encode->parent_data_s = recv_real_data(osd_encode->s); if(osd_encode->parent_data_s) { //判断一下osd_tmp_buf_size是否足够,如果足够就不需要重新申请空间,否则重新申请一下空间 if(osd_encode->osd_tmp_buf_size < get_stream_real_data_len(osd_encode->parent_data_s)) { //释放原来空间 if(osd_encode->osd_tmp_buf) { STREAM_FREE(osd_encode->osd_tmp_buf); } //重新申请一下空间 osd_encode->osd_tmp_buf = (uint8_t*)STREAM_MALLOC(get_stream_real_data_len(osd_encode->parent_data_s)); //申请失败,不压缩了,丢弃 if(!osd_encode->osd_tmp_buf) { osd_encode->osd_tmp_buf_size = 0; free_data(osd_encode->parent_data_s); osd_encode->parent_data_s = NULL; goto osd_encode_work_end; } osd_encode->osd_tmp_buf_size = get_stream_real_data_len(osd_encode->parent_data_s); } //硬件模块开始被使用,标志置一下 stream_self_cmd_func(osd_encode->s,OSD_HARDWARE_REAY_CMD,0); //去压缩 //先清除cache sys_dcache_clean_invalid_range((uint32_t *)stream_self_cmd_func(osd_encode->s,OSD_HARDWARE_ENCODE_BUF,0), osd_encode->osd_tmp_buf_size); lcdc_set_osd_enc_src_addr(osd_encode->lcd_dev,(uint32)get_stream_real_data(osd_encode->parent_data_s)); lcdc_set_osd_enc_dst_addr(osd_encode->lcd_dev,(uint32)stream_self_cmd_func(osd_encode->s,OSD_HARDWARE_ENCODE_BUF,0)); lcdc_set_osd_enc_src_len(osd_encode->lcd_dev,get_stream_real_data_len(osd_encode->parent_data_s)); //gpio_set_val(PA_15,1); lcdc_osd_enc_start_run(osd_encode->lcd_dev,1); } } } osd_encode_work_end: os_run_work_delay(work, 1); return 0; } static uint32_t osd_stream_cmd_func(stream *s,int opcode,uint32_t arg) { uint32_t res = 0; struct lvgl_osd_encode_s *osd_encode = (struct lvgl_osd_encode_s*)s->priv; // uint32_t flags; switch(opcode) { //设置硬件是否准备好 case OSD_HARDWARE_REAY_CMD: osd_encode->hardware_ready = arg; break; //设置压缩后的数据长度 case OSD_HARDWARE_ENCODE_SET_LEN: osd_encode->data_len = arg; break; case OSD_HARDWARE_ENCODE_GET_LEN: res = osd_encode->data_len; break; //返回压缩的buf case OSD_HARDWARE_ENCODE_BUF: res = (uint32_t)osd_encode->osd_tmp_buf; break; case OSD_HARDWARE_DEV: res = (uint32_t)osd_encode->lcd_dev; break; case OSD_HARDWARE_STREAM_RESET: { #if 0 os_printf("%s:%d\n",__FUNCTION__,__LINE__); if(osd_encode->parent_data_s) { free_data(osd_encode->parent_data_s); osd_encode->parent_data_s = NULL; } #endif //硬件模块可用 osd_encode->hardware_ready = 1; OS_WORK_REINIT(&osd_encode->work); os_run_work(&osd_encode->work); } break; //硬件模块停止,workqueue停止 case OSD_HARDWARE_STREAM_STOP: //停止硬件模块 lcdc_osd_enc_start_run(osd_encode->lcd_dev,0); //workqueue停止 os_work_cancle2(&osd_encode->work,1); break; default: break; } return res; } static int opcode_func_r_osd(stream *s,void *priv,int opcode) { int res = 0; switch(opcode) { case STREAM_OPEN_ENTER: break; case STREAM_OPEN_EXIT: { struct lvgl_osd_encode_s *osd_encode = (struct lvgl_osd_encode_s*)STREAM_LIBC_ZALLOC(sizeof(struct lvgl_osd_encode_s)); if(osd_encode) { osd_encode->lcd_dev = (struct lcdc_device *)dev_get(HG_LCDC_DEVID); osd_encode->hardware_ready = 1; osd_encode->osd_tmp_buf_size = 0; osd_encode->osd_tmp_buf = NULL; s->priv = (void*)osd_encode; streamSrc_bind_streamDest(s,R_OSD_SHOW); register_stream_self_cmd_func(s,osd_stream_cmd_func); osd_encode->s = s; OS_WORK_INIT(&osd_encode->work, osd_encode_work, 0); os_run_work_delay(&osd_encode->work, 1); //启动一个任务去管理?或者workqueue都是可行的,就是实时性的问题 //先用workqueue实现,如果性能不行再换成任务的形式吧 enable_stream(s,1); } } break; case STREAM_OPEN_FAIL: break; case STREAM_DATA_DIS: { } break; case STREAM_DATA_FREE: { struct data_structure *data = (struct data_structure *)priv; if(data->data) { STREAM_FREE(data->data); data->data = NULL; } } break; case STREAM_DATA_FREE_END: break; //数据发送完成,可以选择唤醒对应的任务 case STREAM_SEND_DATA_FINISH: break; //音频发送之前先拷贝到psram case STREAM_SEND_DATA_START: { } break; case STREAM_CLOSE_EXIT: { struct lvgl_osd_encode_s *osd_encode = (struct lvgl_osd_encode_s *)s->priv; os_work_cancle2(&osd_encode->work,1); //关闭硬件 lcdc_osd_enc_start_run(osd_encode->lcd_dev,0); //释放资源 free_data(osd_encode->parent_data_s); osd_encode->parent_data_s = NULL; //释放原来空间 if(osd_encode->osd_tmp_buf) { STREAM_FREE(osd_encode->osd_tmp_buf); osd_encode->osd_tmp_buf_size = 0; osd_encode->osd_tmp_buf = NULL; } } break; case STREAM_MARK_GC_END: { if(s->priv) { STREAM_FREE(s->priv); } } break; default: //默认都返回成功 break; } return res; } //osd压缩是一个模块,所以在这里统一管理自己的模块,所有需要压缩的数据都到这里,然后再发出去 //然后类型可以跟着父流一致 //要预先申请一个空间给到osd压缩,最后再读取寄存器看看要拷贝多少压缩的数据 //所以空间是:w*h*2+压缩的size,压缩的size根据不同ui去压缩的,一般不会超过原来的size stream *lvgl_R_osd_stream(const char *name) { stream *s = open_stream_available(name,8,8,opcode_func_r_osd,NULL); return s; }