doubao_chat/apps/demo/demo_DevKitBoard/raw_stream_to_lcd.c

231 lines
7.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "app_config.h"
#if (defined CONFIG_UI_ENABLE) && (defined RAW_STREAM_ENABLE)
#include "storage_device.h"
#include "os/os_api.h"
#include "generic/lbuf.h"
#include "fs/fs.h"
#include "yuv_soft_scalling.h"
#include "yuv_to_rgb.h"
/* #include "video_rec.h" */
/****************************本文件使用lbuff的yuv接收队列实现提高显示帧率***********************************/
//本文件例子:函数根据LCD屏幕驱动的分辨率自动完成对应缩放推屏显示,不支持配合UI合成!!!
extern int lcd_get_color_format_rgb24(void);
extern void lcd_show_frame_to_dev(u8 *buf, u32 len);//该接口显示数据直接推送数据到LCD设备接口,不分数据格式,慎用!
extern void lcd_get_width_height(int *width, int *height);
extern void user_lcd_init(void);
extern void get_yuv_init(void (*cb)(u8 *data, u32 len, int width, int height));
#define YUV_BUFF_FPS 3 //yuv缓存区域帧数
#define YUV_FPS_DBG 1 //1:打开yuv到rgb到屏显帧率测试
#define USE_CUT_TO_LCD 0 //1:使用裁剪推数据到屏丢视角 0使用缩放不丢视角 裁剪要比缩放帧数高
#define YUV2RGB_TASK_NAME "yuv2rgb"
struct yuv_buffer {
u32 len;
u8 data[0];
};
struct yuv2rgb {
void *lbuf;
void *yuv_buf;
void *rgb_buf;
u16 width;
u16 height;
u32 yuv_buf_size;
u8 kill;
u8 init;
u8 index;
};
static struct yuv2rgb yuv2rgb_info = {0};
#define __this (&yuv2rgb_info)
//本函数根据LCD屏幕驱动的分辨率自动完成对应缩放推屏显示,不支持配合UI合成!!!
//使用本函数前,先移植LCD驱动才能显示!!!
static void camera_show_lcd(u8 *buf, u32 size, int width, int height)
{
int src_w = width;
int src_h = height;
int out_w;
int out_h;
int out_size;
char rgb24 = 0;
u32 msg[2];
struct yuv_buffer *yuv = NULL;
if (!__this->init || __this->kill) {
return ;
}
rgb24 = lcd_get_color_format_rgb24();
lcd_get_width_height(&out_w, &out_h);
if (out_w <= 0 || out_h <= 0) {
printf("lcd_get_width_height err \n");
return ;
}
if (!__this->yuv_buf) {
__this->width = out_w;
__this->height = out_h;
__this->yuv_buf_size = out_w * out_h * 3 / 2 * YUV_BUFF_FPS + 256;
__this->yuv_buf = malloc(__this->yuv_buf_size);
if (!__this->yuv_buf) {
printf("no mem size = %d \n", __this->yuv_buf_size);
return ;
}
__this->lbuf = lbuf_init(__this->yuv_buf, __this->yuv_buf_size, 4, sizeof(struct yuv_buffer));
yuv = lbuf_alloc(__this->lbuf, out_w * out_h * 3 / 2);
} else {
if ((out_w * out_h * 3 / 2) < lbuf_free_space(__this->lbuf)) {
yuv = lbuf_alloc(__this->lbuf, out_w * out_h * 3 / 2);
if (yuv) {
yuv->len = out_w * out_h * 3 / 2;
}
}
}
if (!yuv) {
return;
}
#if USE_CUT_TO_LCD
YUV420p_Cut(buf, src_w, src_h, yuv->data, yuv->len, (src_w - out_w) / 2, out_w, (src_h - out_h) / 2, out_h);//裁剪取屏大小数据
#else
YUV420p_Soft_Scaling(buf, yuv->data, src_w, src_h, out_w, out_h);//缩放到LCD指定的宽高
#endif
lbuf_push((void *)yuv, BIT(__this->index));
os_taskq_post_type(YUV2RGB_TASK_NAME, Q_MSG, 0, NULL);
}
static void yuv2rgb_task(void)
{
u32 time_1 = 0, time_2 = 0;
u32 cnt = 0;
u32 out_size;
char rgb24;
int res;
u32 msg[8];
__this->yuv_buf = NULL;
__this->rgb_buf = NULL;
__this->init = true;
__this->index = 0;
while (!__this->yuv_buf && !__this->kill) {
os_time_dly(1);
}
if (__this->kill) {
goto exit;
}
rgb24 = lcd_get_color_format_rgb24();
__this->rgb_buf = malloc(__this->width * __this->height * (rgb24 ? 3 : 2));
out_size = __this->width * __this->height * (rgb24 ? 3 : 2);
if (!__this->rgb_buf) {
printf("err no mem in %s \n", __func__);
goto exit;
}
printf("yuv2rgb_task init\n");
while (1) {
#if YUV_FPS_DBG
time_1 = timer_get_ms();
if (time_1 - time_2 > 1000) {
time_2 = timer_get_ms();
/* printf("lcd cnt = %d \n", cnt); */
cnt = 0;
}
#endif
res = os_task_pend("taskq", msg, ARRAY_SIZE(msg));
if (__this->kill) {
goto exit;
}
switch (res) {
case OS_TASKQ:
switch (msg[0]) {
case Q_MSG:
;
struct yuv_buffer *yuv = lbuf_pop(__this->lbuf, BIT(__this->index));
if (yuv) {
if (rgb24) {
yuv420p_quto_rgb24(yuv->data, __this->rgb_buf, __this->width, __this->height);//YUV转RGB
} else {
yuv420p_quto_rgb565(yuv->data, __this->rgb_buf, __this->width, __this->height, 1);//YUV转RGB
}
/**************推屏显示******************/
lcd_show_frame_to_dev(__this->rgb_buf, out_size);//显示一帧摄像头数据
/****************************************/
lbuf_free(yuv);
cnt++;
}
break;
default:
break;
}
break;
default:
break;
}
}
exit:
__this->init = 0;
if (__this->yuv_buf) {
free(__this->yuv_buf);
__this->yuv_buf = NULL;
}
if (__this->rgb_buf) {
free(__this->rgb_buf);
__this->rgb_buf = NULL;
}
__this->kill = 0;
}
void yuv2rgb_task_kill(void)
{
if (__this->init) {
__this->kill = true;
os_taskq_post_type(YUV2RGB_TASK_NAME, Q_MSG, 0, NULL);
while (__this->kill) {
os_time_dly(1);
}
printf("yuv2rgb_task kill ok\n");
}
}
extern int jpeg2yuv_open(void);
extern void jpeg2yuv_yuv_callback_register(void (*cb)(u8 *data, u32 len, int width, int height));
extern int jpeg2yuv_jpeg_frame_write(u8 *buf, u32 len);
extern void jpeg2yuv_close(void);
extern int user_net_video_rec_open(char forward);
extern int user_net_video_rec_close(char forward);
extern void set_video_rt_cb(u32(*cb)(void *, u8 *, u32), void *priv);
static void uvc_video_jpeg2yuv_task(void)
{
int ret;
//1.打开jpeg解码YUV
ret = jpeg2yuv_open();
if (ret) {
printf("err in jpeg2yuv_open \n");
return;
}
//2.注册YUV数据回调函数
jpeg2yuv_yuv_callback_register(camera_show_lcd);
/* while (1) { */
/* os_time_dly(200); */
/* } */
//8.删除任务
/* yuv2rgb_task_kill(); */
}
static void uvc_video_init(void)
{
int thread_fork(const char *thread_name, int prio, int stk_size, u32 qsize, int *pid, void (*func)(void *), void *parm);
thread_fork("uvc_video_jpeg2yuv_task", 15, 1024, 64, 0, uvc_video_jpeg2yuv_task, NULL);
}
//外部使用初始化lcd驱动,注册YUV回调,创建任务发送数据
void raw_stream_to_lcd(void)
{
user_lcd_init();
uvc_video_init();
thread_fork(YUV2RGB_TASK_NAME, 16, 1024 * 1, 128, 0, yuv2rgb_task, NULL);
}
#endif