323 lines
12 KiB
C
323 lines
12 KiB
C
#include "sys_config.h"
|
|
#include "typesdef.h"
|
|
#include "dev.h"
|
|
#include "devid.h"
|
|
#include "stream_frame.h"
|
|
#include "utlist.h"
|
|
#include "osal/work.h"
|
|
#include "lib/lcd/lcd.h"
|
|
#include "dev/scale/hgscale.h"
|
|
#include "dev/jpg/hgjpg.h"
|
|
#include "app_lcd.h"
|
|
#include "decode/recv_jpg_yuv_demo.h"
|
|
#include "yuv_stream.h"
|
|
#include "custom_mem/custom_mem.h"
|
|
|
|
//创建一个线程,专门是处理lcd显示
|
|
struct osd_show_s
|
|
{
|
|
struct lcdc_device *lcd_dev;
|
|
stream *s;
|
|
struct data_structure *last_show_data_s;
|
|
};
|
|
|
|
|
|
|
|
//如果说workqueue确定没有一些耗时的任务,这个也是可以放到workqueue去处理,节省线程的内存
|
|
void lcd_thread(void *d)
|
|
{
|
|
struct app_lcd_s *lcd_s = (struct app_lcd_s *)d;
|
|
struct lcdc_device *lcd_dev = lcd_s->lcd_dev;
|
|
stream *p1_s = lcd_s->video_p1_s;
|
|
stream *p0_s = lcd_s->video_p0_s;
|
|
stream *s = lcd_s->osd_show_s;
|
|
struct osd_show_s *osd_show = (struct osd_show_s *)s->priv;
|
|
struct recv_jpg_yuv_s *yuv_p1 = (struct recv_jpg_yuv_s *)p1_s->priv;
|
|
|
|
struct yuv_stream_s *yuv_p0 = (struct yuv_stream_s *)p0_s->priv;
|
|
|
|
struct data_structure *osd_data_s;
|
|
struct data_structure *video_p1_data_s;
|
|
struct data_structure *video_p0_data_s;
|
|
|
|
uint32_t p0_w=0,p0_h=0,p1_w=0,p1_h=0;
|
|
struct yuv_arg_s *yuv_msg;
|
|
uint32_t y_off = 0,uv_off = 0;
|
|
|
|
|
|
//是否要启动显示,只要有osd或者video显示,都要启动硬件模块
|
|
//如果是mcu屏,内部可以增加其他逻辑,判断显示是否有变化决定是否刷屏
|
|
//如果是rgb屏,无论内容是否发生变化,都要刷新,否则会有问题
|
|
uint8_t flag = 0;
|
|
uint8_t p0_p1_enable = 0;
|
|
while(!lcd_s->thread_exit)
|
|
{
|
|
//ready
|
|
p0_p1_enable = 0;
|
|
if(lcd_s->hardware_ready)
|
|
{
|
|
//显示osd
|
|
{
|
|
osd_data_s = recv_real_data(s);
|
|
if(osd_data_s)
|
|
{
|
|
//os_printf("%s:%d\tosd_data_s:%X\n",__FUNCTION__,__LINE__,osd_data_s);
|
|
if(osd_show->last_show_data_s)
|
|
{
|
|
free_data(osd_show->last_show_data_s);
|
|
osd_show->last_show_data_s = NULL;
|
|
}
|
|
osd_show->last_show_data_s = osd_data_s;
|
|
}
|
|
else
|
|
{
|
|
osd_data_s = osd_show->last_show_data_s;
|
|
}
|
|
//os_printf("data_s len:%d\t%X\n",get_stream_real_data_len(osd_data_s),osd_data_s);
|
|
if(osd_data_s)
|
|
{
|
|
lcdc_set_osd_dma_addr(lcd_dev,(uint32)get_stream_real_data(osd_data_s));
|
|
lcdc_set_osd_dma_len(lcd_dev,get_stream_real_data_len(osd_data_s));
|
|
lcdc_set_osd_en(lcd_dev,1);
|
|
//os_printf("encode osd len:%d\n",get_stream_real_data_len(osd_data_s));
|
|
flag++;
|
|
}
|
|
else
|
|
{
|
|
lcdc_set_osd_en(lcd_dev,0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//显示video p1
|
|
//这里是video_p1的显示
|
|
{
|
|
lcd_thread_get_video_p1_again:
|
|
video_p1_data_s = recv_real_data(p1_s);
|
|
|
|
//有新的yuv数据要显示
|
|
if(video_p1_data_s)
|
|
{
|
|
//os_printf("%s:%d\tvideo_p1_data_s:%X\n",__FUNCTION__,__LINE__,video_p1_data_s);
|
|
//移除原来的数据
|
|
if(yuv_p1->last_data_s)
|
|
{
|
|
free_data(yuv_p1->last_data_s);
|
|
}
|
|
yuv_p1->last_data_s = video_p1_data_s;
|
|
}
|
|
else if(yuv_p1->last_data_s)
|
|
{
|
|
video_p1_data_s = yuv_p1->last_data_s;
|
|
}
|
|
|
|
//判断一下显示时间,如果过时的,就不显示了
|
|
if(video_p1_data_s)
|
|
{
|
|
uint32_t show_time =stream_self_cmd_func(p1_s,GET_LVGL_YUV_UPDATE_TIME,(uint32_t)0);
|
|
if(show_time > get_stream_data_timestamp(video_p1_data_s))
|
|
{
|
|
free_data(yuv_p1->last_data_s);
|
|
yuv_p1->last_data_s = NULL;
|
|
goto lcd_thread_get_video_p1_again;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if(video_p1_data_s)
|
|
{
|
|
yuv_msg = (struct yuv_arg_s *)stream_self_cmd_func(video_p1_data_s->s,YUV_ARG,(uint32_t)video_p1_data_s);
|
|
|
|
//错误的图片,可能不需要显示或者发送错误
|
|
if(yuv_msg)
|
|
{
|
|
|
|
//需要删除
|
|
if(yuv_msg->del && *yuv_msg->del)
|
|
{
|
|
free_data(video_p1_data_s);
|
|
yuv_p1->last_data_s = NULL;
|
|
os_printf("%s:%d p1 del:%X\n",__FUNCTION__,__LINE__,video_p1_data_s);
|
|
goto lcd_thread_get_video_p1_again;
|
|
}
|
|
|
|
p1_w = yuv_msg->out_w;
|
|
p1_h = yuv_msg->out_h;
|
|
uint8_t *yuv_buf = get_stream_real_data(video_p1_data_s);
|
|
if(lcd_s->rotate == LCD_ROTATE_180)
|
|
{
|
|
y_off = p1_w*(p1_h-1);
|
|
uv_off= ((p1_w/2+3)/4)*4 * (p1_h/2-1);
|
|
}
|
|
lcdc_set_p1_rotate_y_src_addr(lcd_dev,(uint32)yuv_buf+y_off/**/);
|
|
lcdc_set_p1_rotate_u_src_addr(lcd_dev,(uint32)yuv_buf+yuv_msg->y_size+uv_off/**/);
|
|
lcdc_set_p1_rotate_v_src_addr(lcd_dev,(uint32)yuv_buf+yuv_msg->y_size+yuv_msg->y_size/4+uv_off/**/);
|
|
p0_p1_enable |= BIT(1);
|
|
}
|
|
else
|
|
{
|
|
os_printf("%s:%d\tlvgl video yuv err\n",__FUNCTION__,__LINE__);
|
|
os_printf("%s:%d\tvideo_p1_data_s:%X\tname:%s\n",__FUNCTION__,__LINE__,video_p1_data_s,video_p1_data_s->s->name);
|
|
free_data(yuv_p1->last_data_s);
|
|
yuv_p1->last_data_s = NULL;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//强行显示一下p0的数据
|
|
{
|
|
lcd_thread_get_video_p0_again:
|
|
video_p0_data_s = recv_real_data(p0_s);
|
|
//有新的yuv数据要显示
|
|
if(video_p0_data_s)
|
|
{
|
|
//os_printf("%s:%d\tvideo_p1_data_s:%X\n",__FUNCTION__,__LINE__,video_p1_data_s);
|
|
//移除原来的数据
|
|
if(yuv_p0->last_data_s)
|
|
{
|
|
free_data(yuv_p0->last_data_s);
|
|
}
|
|
yuv_p0->last_data_s = video_p0_data_s;
|
|
}
|
|
else if(yuv_p0->last_data_s)
|
|
{
|
|
video_p0_data_s = yuv_p0->last_data_s;
|
|
}
|
|
|
|
|
|
//判断一下显示时间,如果过时的,就不显示了
|
|
if(video_p0_data_s)
|
|
{
|
|
uint32_t show_time =stream_self_cmd_func(p0_s,GET_LVGL_YUV_UPDATE_TIME,(uint32_t)0);
|
|
if(show_time > get_stream_data_timestamp(video_p0_data_s))
|
|
{
|
|
free_data(video_p0_data_s);
|
|
yuv_p0->last_data_s = NULL;
|
|
goto lcd_thread_get_video_p0_again;
|
|
}
|
|
}
|
|
|
|
if(video_p0_data_s)
|
|
{
|
|
yuv_msg = (struct yuv_arg_s *)stream_self_cmd_func(video_p0_data_s->s,YUV_ARG,(uint32_t)video_p0_data_s);
|
|
if(yuv_msg)
|
|
{
|
|
//需要删除
|
|
if(yuv_msg->del && *yuv_msg->del)
|
|
{
|
|
free_data(video_p0_data_s);
|
|
yuv_p0->last_data_s = NULL;
|
|
os_printf("%s:%d p0 del:%X\n",__FUNCTION__,__LINE__,video_p0_data_s);
|
|
goto lcd_thread_get_video_p0_again;
|
|
}
|
|
uint8_t *p_buf = (uint8_t*)get_stream_real_data(video_p0_data_s);
|
|
p0_w = yuv_msg->out_w;
|
|
p0_h = yuv_msg->out_h;
|
|
if(lcd_s->rotate == LCD_ROTATE_180)
|
|
{
|
|
y_off = p0_w*(p0_h-1);
|
|
uv_off= ((p0_w/2+3)/4)*4 * (p0_h/2-1);
|
|
}
|
|
|
|
lcdc_set_p0_rotate_y_src_addr(lcd_dev,(uint32)p_buf+y_off);
|
|
lcdc_set_p0_rotate_u_src_addr(lcd_dev,(uint32)p_buf+yuv_msg->y_size+uv_off);
|
|
lcdc_set_p0_rotate_v_src_addr(lcd_dev,(uint32)p_buf+yuv_msg->y_size+yuv_msg->y_size/4+uv_off);
|
|
|
|
p0_p1_enable |= BIT(0);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//打开video
|
|
if(p0_p1_enable)
|
|
{
|
|
//检查一下line_buf是否已经申请了,申请空间就是w*line_num的空间(w应该是和屏旋转有关)
|
|
if(!lcd_s->line_buf)
|
|
{
|
|
uint16_t rotate_w;
|
|
rotate_w = lcd_s->screen_w;
|
|
lcd_s->line_buf = (void*)custom_malloc(lcd_s->line_buf_num*rotate_w*2);
|
|
//这里理论要申请到空间,如果申请失败,重新申请一下(否则要就额外处理资源数据)
|
|
while(!lcd_s->line_buf)
|
|
{
|
|
os_sleep_ms(1);
|
|
lcd_s->line_buf = (void*)custom_malloc(lcd_s->line_buf_num*rotate_w*2);
|
|
}
|
|
lcdc_set_rotate_linebuf_y_addr(lcd_dev,(uint32)lcd_s->line_buf );
|
|
lcdc_set_rotate_linebuf_u_addr(lcd_dev,(uint32)lcd_s->line_buf +rotate_w*lcd_s->line_buf_num);
|
|
lcdc_set_rotate_linebuf_v_addr(lcd_dev,(uint32)lcd_s->line_buf +rotate_w*lcd_s->line_buf_num+(rotate_w/2)*lcd_s->line_buf_num);
|
|
}
|
|
lcdc_set_rotate_p0p1_size(lcd_dev,p0_w,p0_h,p1_w,p1_h);
|
|
lcdc_set_rotate_mirror(lcd_dev,0,lcd_s->video_rotate);
|
|
lcdc_set_p0p1_enable(lcd_dev,p0_p1_enable&BIT(0),p0_p1_enable&BIT(1));
|
|
lcdc_set_video_en(lcd_dev,1);
|
|
flag++;
|
|
}
|
|
else
|
|
{
|
|
//如果不需要显示video,则空间释放吧
|
|
if(lcd_s->line_buf)
|
|
{
|
|
custom_free(lcd_s->line_buf);
|
|
lcd_s->line_buf = NULL;
|
|
|
|
}
|
|
lcdc_set_video_en(lcd_dev,0);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//lcd模块已经启动,hardware_ready清0
|
|
if(flag)
|
|
{
|
|
//os_printf("%s:%d\n",__FUNCTION__,__LINE__);
|
|
lcd_s->hardware_ready = 0;
|
|
|
|
lcdc_set_start_run(lcd_dev);
|
|
flag = 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
//不需要显示,则休眠1ms重新检查
|
|
//这里暂时没有用信号量唤醒,主要考虑到osd和video都有可能需要显示,要考虑如何监听osd和video的数据才可以用信号量
|
|
//这里用sleep,会占用一点点cpu
|
|
os_sleep_ms(1);
|
|
}
|
|
}
|
|
|
|
|
|
free_data(yuv_p0->last_data_s);
|
|
yuv_p0->last_data_s = NULL;
|
|
|
|
free_data(yuv_p1->last_data_s);
|
|
yuv_p1->last_data_s = NULL;
|
|
|
|
do
|
|
{
|
|
video_p0_data_s = recv_real_data(p0_s);
|
|
free_data(video_p0_data_s);
|
|
os_printf("video_p0_data_s:%X\n",video_p0_data_s);
|
|
|
|
}while(video_p0_data_s);
|
|
|
|
do
|
|
{
|
|
video_p1_data_s = recv_real_data(p1_s);
|
|
free_data(video_p1_data_s);
|
|
os_printf("video_p1_data_s:%X\n",video_p1_data_s);
|
|
|
|
}while(video_p1_data_s);
|
|
//相当于退出lcd的线程
|
|
lcd_s->thread_exit = 0;
|
|
lcd_s->thread_hdl = NULL;
|
|
return;
|
|
} |