293 lines
7.9 KiB
C
293 lines
7.9 KiB
C
#include "app_config.h"
|
||
|
||
#if defined CONFIG_UI_ENABLE && defined CONFIG_VIDEO_ENABLE && !(defined RAW_STREAM_ENABLE)
|
||
#include "device/device.h"
|
||
#include "os/os_api.h"
|
||
#include "generic/lbuf.h"
|
||
#include "yuv_soft_scalling.h"
|
||
#include "yuv_to_rgb.h"
|
||
#include "system/sys_time.h"
|
||
#include "system/init.h"
|
||
|
||
#ifdef USE_LCD_DEMO
|
||
/****************************本文件使用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 1 //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;
|
||
int pid;
|
||
};
|
||
|
||
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(yuv, BIT(__this->index));
|
||
os_taskq_post_type(YUV2RGB_TASK_NAME, Q_MSG, 0, NULL);
|
||
}
|
||
|
||
static void yuv2rgb_task(void *priv)
|
||
{
|
||
u32 time_1 = 0, time_2 = 0;
|
||
u32 cnt = 0;
|
||
u32 out_size;
|
||
char rgb24;
|
||
int res;
|
||
int msg[4];
|
||
|
||
__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) {
|
||
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:
|
||
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->init = 0;
|
||
__this->kill = 0;
|
||
}
|
||
|
||
static void yuv2rgb_task_kill(void)
|
||
{
|
||
if (__this->init) {
|
||
__this->kill = true;
|
||
os_taskq_post_type(YUV2RGB_TASK_NAME, Q_MSG, 0, NULL);
|
||
thread_kill(&__this->pid, KILL_WAIT);
|
||
}
|
||
}
|
||
|
||
#ifdef CONFIG_UVC_VIDEO2_ENABLE
|
||
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_video_rec0_open(int dev);
|
||
extern int user_video_rec0_close(void);
|
||
extern void set_video_rt_cb(u32(*cb)(void *, u8 *, u32), void *priv);
|
||
extern int uvc_host_online(void);
|
||
|
||
static u32 jpeg_cb(void *hdr, u8 *data, u32 len)
|
||
{
|
||
#define JPEG_HEAD 0xE0FFD8FF
|
||
#define JPEG_HEAD1 0xC0FFD8FF
|
||
u32 *head = (u32 *)data;
|
||
if (*head == JPEG_HEAD || *head == JPEG_HEAD1) {
|
||
//video
|
||
jpeg2yuv_jpeg_frame_write(data, len);
|
||
} else {
|
||
//audio
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static void uvc_video_jpeg2yuv_task(void *priv)
|
||
{
|
||
int ret;
|
||
|
||
while (1) {
|
||
//0.等待UVC上线
|
||
while (!dev_online("uvc")) {
|
||
os_time_dly(5);
|
||
}
|
||
|
||
//1.打开jpeg解码YUV
|
||
ret = jpeg2yuv_open();
|
||
if (ret) {
|
||
break;
|
||
}
|
||
|
||
thread_fork(YUV2RGB_TASK_NAME, 6, 512, 128, &__this->pid, yuv2rgb_task, NULL);
|
||
|
||
//2.注册YUV数据回调函数
|
||
jpeg2yuv_yuv_callback_register(camera_show_lcd);
|
||
|
||
//3.打开UVC实时流
|
||
ret = user_video_rec0_open(uvc_host_online() ? 3 : 2);
|
||
if (ret) {
|
||
jpeg2yuv_close();
|
||
yuv2rgb_task_kill();
|
||
os_time_dly(100);
|
||
continue;
|
||
}
|
||
|
||
//4.注册jpeg数据回调函数
|
||
set_video_rt_cb(jpeg_cb, NULL);
|
||
|
||
//5.检查是否掉线
|
||
while (dev_online("uvc")) {
|
||
os_time_dly(5);
|
||
}
|
||
|
||
//6.关闭UVC实时流
|
||
user_video_rec0_close();
|
||
|
||
//7.关闭jpeg解码YUV
|
||
jpeg2yuv_close();
|
||
|
||
//8.删除任务
|
||
yuv2rgb_task_kill();
|
||
}
|
||
}
|
||
|
||
static int uvc_video_init(void)
|
||
{
|
||
return thread_fork("uvc_video_jpeg2yuv_task", 4, 512, 0, 0, uvc_video_jpeg2yuv_task, NULL);
|
||
}
|
||
#endif
|
||
|
||
static int camera_to_lcd_init(void)
|
||
{
|
||
user_lcd_init();
|
||
|
||
#ifdef CONFIG_UVC_VIDEO2_ENABLE
|
||
uvc_video_init();
|
||
#else
|
||
get_yuv_init(camera_show_lcd);
|
||
#endif
|
||
|
||
return 0;
|
||
}
|
||
late_initcall(camera_to_lcd_init);
|
||
|
||
#endif
|
||
#endif
|