Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources

This commit is contained in:
2026-07-06 11:30:13 +08:00
commit e76462eeb7
3451 changed files with 1415300 additions and 0 deletions

626
sdk/app/app_lcd/app_lcd.c Normal file
View File

@@ -0,0 +1,626 @@
#include "basic_include.h"
#include "hal/lcdc.h"
#include "hal/spi.h"
#include "hal/dsi.h"
#include "dev/lcdc/hglcdc.h"
#include "lib/lcd/lcd.h"
#include "lib/multimedia/msi.h"
#include "stream_frame.h"
#include "app_lcd.h"
#include "user_work/user_work.h"
#ifdef PIN_FROM_PARAM
#include "pin_param.h"
#endif
#ifdef LCD_EN
#define LCD_ROTATE_LINE 64
#define OSD_EN 1
#define LCD_SCREEN_RECORD_EN 0 // 录屏功能
struct app_lcd_s lcd_msg_s;
void lcd_hardware_init565();
void lcd_hardware_init666();
extern void lcd_register_read_3line(struct spi_device *spi_dev, uint32 code, uint8 *buf, uint32 len);
extern void lcd_table_init(struct spi_device *spi_dev, uint8_t *lcd_table);
extern void lcd_table_init_MCU(struct lcdc_device *lcd_dev, uint8_t (*lcd_table)[2]);
extern void lcd_reg_table_init(struct lcdc_device *lcd_dev, uint8 lcd_bus_type, uint8_t *lcd_table);
// 暂时没有作处理
static void lcd_timeout1(uint32 irq_flag, uint32 irq_data, uint32 param1)
{
struct app_lcd_s *lcd_s = (struct app_lcd_s *) irq_data;
struct lcdc_device *lcd_dev = lcd_s->lcd_dev;
lcdc_set_timeout_info(lcd_dev, 0, 3);
os_printf("lcd_timeout\r\n");
// 出现timeout,说明可能哪里卡住了,让应用层重新启动
lcd_s->hardware_ready = 1;
lcd_s->rekick_lcd = 1;
}
// 暂时没有作处理
static void lcd_te_isr1(uint32 irq_flag, uint32 irq_data, uint32 param1)
{
os_printf("%s:%d\n", __FUNCTION__, __LINE__);
struct app_lcd_s *lcd_s = (struct app_lcd_s *) irq_data;
struct lcdc_device *lcd_dev;
lcd_dev = lcd_s->lcd_dev;
os_printf("--------------------------------------------te------------------"
"---------------\r\n");
}
static void lcd_squralbuf_done1(uint32 irq_flag, uint32 irq_data, uint32 param1)
{
struct app_lcd_s *lcd_s = (struct app_lcd_s *) irq_data;
// 理论这里只是唤醒信号量之类,由线程来决定是否继续显示
// os_printf("%s:%d\n",__FUNCTION__,__LINE__);
#if LCD_SCREEN_RECORD_EN
static uint32 lcd_num = 0;
static uint32 dither = 0;
if ((lcd_num % 200) == 0)
{
os_printf("---------------------------------------------------------\r\n");
if (dither == 1)
{
lcdc_dither_en(lcd_s->lcd_dev, 0);
lcdc_screen_start(lcd_s->lcd_dev, 1);
dither = 0;
}
else
{
lcdc_dither_en(lcd_s->lcd_dev, 1);
lcdc_screen_start(lcd_s->lcd_dev, 1);
dither = 1;
}
}
#endif
lcd_s->end_time = os_jiffies();
lcd_s->refresh_time = lcd_s->end_time - lcd_s->start_time;
if (lcd_s->hardware_auto_ks)
{
lcd_s->hardware_ready = 0;
// 判断是否启动了硬件自动kick
if (!lcd_s->get_auto_ks)
{
// 启动自动kick
lcd_s->get_auto_ks = 1;
lcdc_video_enable_auto_ks(lcd_s->lcd_dev, 1);
}
}
else
{
if (lcd_s->get_auto_ks)
{
lcd_s->get_auto_ks = 0;
lcdc_video_enable_auto_ks(lcd_s->lcd_dev, 0);
}
else
{
lcd_s->hardware_ready = 1;
}
}
lcd_s->app_lcd_cb(lcd_s);
#if 1
uint32_t st0, st1;
struct dsi_device *dsi_dev;
dsi_dev = lcd_s->lcd_dsi_dev; //(struct dsi_device *)dev_get(HG_DSI_DEVID);
st0 = mipi_dsi_get_sta0(dsi_dev);
st1 = mipi_dsi_get_sta1(dsi_dev);
if ((st0 != 0) || (st1 != 0))
{
os_printf("L(%08x %08x)\r\n", st0, st1);
mipi_dsi_reset_module(dsi_dev);
}
#endif
}
#if LCD_SCREEN_RECORD_EN
static void lcd_screen_finish(uint32 irq_flag, uint32 irq_data, uint32 param1)
{
os_printf("%s %d\r\n", __func__, __LINE__);
}
#endif
uint8_t g_read_hardware_auto_ks()
{
// os_printf("%s:%d\n",__FUNCTION__,__LINE__);
return lcd_msg_s.get_auto_ks;
}
uint8_t g_set_hardware_auto_ks(uint8_t en)
{
uint32_t flags;
uint32_t timeout = 0;
if (en)
{
lcd_msg_s.hardware_auto_ks = en;
while (!lcd_msg_s.get_auto_ks && (timeout < 100))
{
timeout++;
os_sleep_ms(1);
}
}
else
{
flags = disable_irq();
lcd_msg_s.hardware_auto_ks = en;
enable_irq(flags);
}
return lcd_msg_s.get_auto_ks;
}
// 返回的是osd旋转和w h
static void get_osd_w_h(uint16_t *w, uint16_t *h, uint8_t *rotate)
{
*w = lcdstruct.osd_w;
*h = lcdstruct.osd_h;
*rotate = lcdstruct.osd_scan_mode;
}
static void get_video_w_h(uint16_t *video_w, uint16_t *video_h)
{
*video_w = lcdstruct.video_w;
*video_h = lcdstruct.video_h;
}
// 返回屏幕的size和旋转角度
static void get_screen_w_h(uint16_t *screen_w, uint16_t *screen_h, uint8_t *video_rotate)
{
*screen_w = lcdstruct.screen_w;
*screen_h = lcdstruct.screen_h;
*video_rotate = lcdstruct.scan_mode;
}
// 注意,这部分不同屏以及硬件设计不一样,需要修改
void lcd_hardware_init(uint16_t *w, uint16_t *h, uint8_t *rotate, uint16_t *screen_w, uint16_t *screen_h, uint16_t *video_w, uint16_t *video_h, uint8_t *video_rotate)
{
if (lcdstruct.lcd_bus_type == LCD_BUS_I80)
{
if (lcdstruct.color_mode == LCD_MODE_666)
{
lcd_hardware_init666();
}
else if (lcdstruct.color_mode == LCD_MODE_565)
{
lcd_hardware_init565();
}
else
{
lcd_hardware_init565();
}
}
else if ((lcdstruct.lcd_bus_type == LCD_BUS_RGB) || (lcdstruct.lcd_bus_type == LCD_BUS_SPI4))
{
lcd_hardware_init565();
}
else if (lcdstruct.lcd_bus_type == LCD_BUS_MIPI)
{
lcd_hardware_init565();
}
// 返回osd的w和h
get_osd_w_h(w, h, rotate);
get_screen_w_h(screen_w, screen_h, video_rotate);
get_video_w_h(video_w, video_h);
}
// 主要硬件初始化,但由于存在rgb屏,还是会有部分寄存器需要配置
void lcd_hardware_init565()
{
uint8 pixel_dot_num = 1;
struct lcdc_device *lcd_dev;
struct spi_device *spi_dev;
// uint32_t rbuf[4];
// uint8_t *pt8;
lcd_dev = (struct lcdc_device *) dev_get(HG_LCDC_DEVID);
spi_dev = (struct spi_device *) dev_get(HG_SPI0_DEVID);
uint8_t rst = MACRO_PIN(PIN_LCD_RESET);
if (rst != 255)
{
gpio_iomap_output(rst, GPIO_IOMAP_OUTPUT);
gpio_set_val(rst, 0);
os_sleep_ms(100);
gpio_set_val(rst, 1);
os_sleep_ms(100);
}
if (lcdstruct.lcd_bus_type == LCD_BUS_RGB)
{
uint8 spi_buf[10];
if (lcdstruct.init_table != NULL)
{
spi_open(spi_dev, 1000000, SPI_MASTER_MODE, SPI_WIRE_SINGLE_MODE, SPI_CPOL_1_CPHA_1);
spi_ioctl(spi_dev, SPI_SET_FRAME_SIZE, 9, 0);
// lcd spi_cfg
_os_printf("read lcd id(%x)\r\n", (unsigned int) spi_dev);
lcd_register_read_3line(spi_dev, 0xda, spi_buf, 4);
_os_printf("***ID:%02x %02x %02x %02x\r\n", spi_buf[0], spi_buf[1], spi_buf[2], spi_buf[3]);
lcd_table_init(spi_dev, (uint8_t *) lcdstruct.init_table);
gpio_set_val(PIN_SPI0_CS, 1);
gpio_iomap_output(PIN_SPI0_CS, GPIO_IOMAP_OUTPUT);
}
}
// scale_to_lcd_config();
lcdc_init(lcd_dev);
if ((lcdstruct.lcd_bus_type == LCD_BUS_I80) || (lcdstruct.lcd_bus_type == LCD_BUS_SPI4))
{
lcdc_open(lcd_dev);
}
lcdc_set_color_mode(lcd_dev, lcdstruct.color_mode);
lcdc_set_bus_width(lcd_dev, lcdstruct.bus_width);
lcdc_set_interface(lcd_dev, lcdstruct.lcd_bus_type);
lcdc_set_colrarray(lcd_dev, lcdstruct.colrarray);
pixel_dot_num = lcdstruct.color_mode / lcdstruct.bus_width;
lcdc_set_lcd_vaild_size(lcd_dev, lcdstruct.screen_w + lcdstruct.hlw + lcdstruct.hbp + lcdstruct.hfp, lcdstruct.screen_h + lcdstruct.vlw + lcdstruct.vbp + lcdstruct.vfp, pixel_dot_num);
lcdc_set_lcd_visible_size(lcd_dev, lcdstruct.screen_w, lcdstruct.screen_h, pixel_dot_num);
if (lcdstruct.lcd_bus_type == LCD_BUS_I80)
{
lcdc_mcu_signal_config(lcd_dev, lcdstruct.signal_config.value);
}
else if ((lcdstruct.lcd_bus_type == LCD_BUS_RGB) || (lcdstruct.lcd_bus_type == LCD_BUS_MIPI) || (lcdstruct.lcd_bus_type == LCD_BUS_QSPI))
{
lcdc_signal_config(lcd_dev, lcdstruct.vs_en, lcdstruct.hs_en, lcdstruct.de_en, lcdstruct.vs_inv, lcdstruct.hs_inv, lcdstruct.de_inv, lcdstruct.pclk_inv);
lcdc_set_invalid_line(lcd_dev, lcdstruct.vlw);
lcdc_set_valid_dot(lcd_dev, lcdstruct.hlw + lcdstruct.hbp, lcdstruct.vlw + lcdstruct.vbp);
lcdc_set_hlw_vlw(lcd_dev, lcdstruct.hlw, 0);
}
lcdc_set_baudrate(lcd_dev, lcdstruct.pclk);
lcdc_set_bigendian(lcd_dev, 1);
if (lcdstruct.lcd_bus_type == LCD_BUS_I80)
{
// lcd_table_init_MCU(lcd_dev, lcdstruct.init_table);
lcd_reg_table_init(lcd_dev, lcdstruct.lcd_bus_type, (uint8_t *) (lcdstruct.init_table));
}
else if (lcdstruct.lcd_bus_type == LCD_BUS_MIPI)
{
mipi_dsi_init(lcdstruct.screen_w, lcdstruct.screen_h, lcdstruct.pclk, lcdstruct.vlw, lcdstruct.vbp, lcdstruct.vfp, lcdstruct.hlw, lcdstruct.hbp, lcdstruct.hfp, lcdstruct.lane_num,
lcdstruct.color_mode);
}
else if (lcdstruct.lcd_bus_type == LCD_BUS_SPI4)
{
lcdc_spi_cs_lock_time(lcd_dev, 0x20, 0x20, 0x20);
lcdc_cmd_auto_send(lcd_dev, 0, 0);
// pt8 = (uint8_t *)rbuf;
// pt8[0] = 1;
// pt8[1] = 4;
// pt8[2] = 0x04;
// lcdc_reg_read_data(lcd_dev,1,4,rbuf);
// os_printf("ID:%02x %02x %02x %02x %02x %02x %02x\r\n",pt8[0],pt8[1],pt8[2],pt8[3],pt8[4],pt8[5],pt8[6]);
lcd_reg_table_init(lcd_dev, lcdstruct.lcd_bus_type, (uint8_t *) (lcdstruct.init_table));
}
}
void lcd_hardware_init666()
{
uint8 pixel_dot_num = 1;
struct lcdc_device *lcd_dev;
struct spi_device *spi_dev;
lcd_dev = (struct lcdc_device *) dev_get(HG_LCDC_DEVID);
spi_dev = (struct spi_device *) dev_get(HG_SPI0_DEVID);
uint8_t rst = MACRO_PIN(PIN_LCD_RESET);
if (rst != 255)
{
gpio_iomap_output(rst, GPIO_IOMAP_OUTPUT);
gpio_set_val(rst, 0);
os_sleep_ms(100);
gpio_set_val(rst, 1);
os_sleep_ms(100);
}
if (lcdstruct.lcd_bus_type == LCD_BUS_RGB)
{
uint8 spi_buf[10];
if (lcdstruct.init_table != NULL)
{
spi_open(spi_dev, 1000000, SPI_MASTER_MODE, SPI_WIRE_SINGLE_MODE, SPI_CPOL_1_CPHA_1);
spi_ioctl(spi_dev, SPI_SET_FRAME_SIZE, 9, 0);
// lcd spi_cfg
_os_printf("read lcd id(%x)\r\n", (unsigned int) spi_dev);
lcd_register_read_3line(spi_dev, 0xda, spi_buf, 4);
_os_printf("***ID:%02x %02x %02x %02x\r\n", spi_buf[0], spi_buf[1], spi_buf[2], spi_buf[3]);
lcd_table_init(spi_dev, (uint8_t *) lcdstruct.init_table);
gpio_set_val(PIN_SPI0_CS, 1);
gpio_iomap_output(PIN_SPI0_CS, GPIO_IOMAP_OUTPUT);
}
}
// scale_to_lcd_config();
lcdc_init(lcd_dev);
if (lcdstruct.lcd_bus_type == LCD_BUS_I80)
{
lcdc_open(lcd_dev);
}
lcdc_set_color_mode(lcd_dev, lcdstruct.color_mode);
lcdc_set_bus_width(lcd_dev, lcdstruct.bus_width);
lcdc_set_interface(lcd_dev, lcdstruct.lcd_bus_type);
lcdc_set_colrarray(lcd_dev, lcdstruct.colrarray);
pixel_dot_num = lcdstruct.color_mode / lcdstruct.bus_width;
lcdc_set_lcd_vaild_size(lcd_dev, lcdstruct.screen_w + lcdstruct.hlw + lcdstruct.hbp + lcdstruct.hfp, lcdstruct.screen_h + lcdstruct.vlw + lcdstruct.vbp + lcdstruct.vfp, pixel_dot_num);
lcdc_set_lcd_visible_size(lcd_dev, lcdstruct.screen_w, lcdstruct.screen_h, 3);
if (lcdstruct.lcd_bus_type == LCD_BUS_I80)
{
lcdc_mcu_signal_config(lcd_dev, lcdstruct.signal_config.value);
}
else if (lcdstruct.lcd_bus_type == LCD_BUS_RGB)
{
lcdc_signal_config(lcd_dev, lcdstruct.vs_en, lcdstruct.hs_en, lcdstruct.de_en, lcdstruct.vs_inv, lcdstruct.hs_inv, lcdstruct.de_inv, lcdstruct.pclk_inv);
lcdc_set_invalid_line(lcd_dev, lcdstruct.vlw);
lcdc_set_valid_dot(lcd_dev, lcdstruct.hlw + lcdstruct.hbp, lcdstruct.vlw + lcdstruct.vbp);
lcdc_set_hlw_vlw(lcd_dev, lcdstruct.hlw, 0);
}
lcdc_set_baudrate(lcd_dev, lcdstruct.pclk);
lcdc_set_bigendian(lcd_dev, 1);
if (lcdstruct.lcd_bus_type == LCD_BUS_I80)
{
lcd_table_init_MCU(lcd_dev, lcdstruct.init_table);
}
// gamma表之类没有配置,这个考虑是放在其他地方,这个函数专注硬件的初始化好了
#if 0
lcdc_video_enable_gamma(lcd_dev, 1);
lcdc_video_enable_ccm(lcd_dev, 1);
lcdc_video_enable_constarast(lcd_dev, 1);
lcdc_video_set_CCM_COEF0(lcd_dev, 0x00df0100);
lcdc_video_set_CCM_COEF1(lcd_dev, 0x0003b3f3);
lcdc_video_set_CCM_COEF2(lcd_dev, 0x0df0000d);
lcdc_video_set_CCM_COEF3(lcd_dev, 0x00000000);
lcdc_video_set_constarast_val(lcd_dev, 0x12);
lcdc_video_set_gamma_R(lcd_dev, (uint32_t)rgb_gamma_table);
lcdc_video_set_gamma_G(lcd_dev, (uint32_t)rgb_gamma_table);
lcdc_video_set_gamma_B(lcd_dev, (uint32_t)rgb_gamma_table);
#endif
lcdc_set_bus_width(lcd_dev, LCD_BUS_WIDTH_6);
}
// lcd相关参数配置,w、h、rotate
void lcd_arg_setting(uint16_t w, uint16_t h, uint8_t rotate, uint16_t screen_w, uint16_t screen_h, uint16_t video_w, uint16_t video_h, uint8_t video_rotate)
{
struct app_lcd_s *lcd_s = &lcd_msg_s;
lcd_s->w = w;
lcd_s->h = h;
lcd_s->rotate = rotate;
lcd_s->screen_w = screen_w;
lcd_s->screen_h = screen_h;
lcd_s->video_w = video_w;
lcd_s->video_h = video_h;
lcd_s->video_rotate = video_rotate;
}
// 芯片lcd的驱动初始化
void lcd_driver_init(const char *osd_encode_name, const char *lcd_osd_name, const char *lcd_video_p0, const char *lcd_video_p1)
{
struct app_lcd_s *lcd_s = &lcd_msg_s;
struct dsi_device *dsi_dev;
dsi_dev = (struct dsi_device *) dev_get(HG_DSI_DEVID);
dev_put((struct dev_obj *) dsi_dev);
lcd_s->osd_enc_msi = osd_encode_msi_init(osd_encode_name);
// 对应的rb初始化
RB_INIT(&lcd_s->osd_rb, LCD_RB_COUNT);
RB_INIT(&lcd_s->p0_rb, LCD_RB_COUNT);
RB_INIT(&lcd_s->p1_rb, LCD_RB_COUNT);
RB_INIT(&lcd_s->p2_rb, LCD_RB_COUNT);
RB_INIT(&lcd_s->delete_rb, LCD_DELETE_RB_COUNT);
#if 1
lcd_s->lcd_osd_msi = lcd_osd_msi(lcd_osd_name);
lcd_s->video_p0_msi = lcd_video_msi_init(lcd_video_p0, FSTYPE_YUV_P0);
lcd_s->video_p1_msi = lcd_video_msi_init(lcd_video_p1, FSTYPE_YUV_P1);
lcd_s->csc_video_p2_msi = lcd_video_msi_init(R_CSC_VIDEO_P2, FSTYPE_YUV_P0);
#endif
lcd_s->hardware_ready = 1;
lcd_s->thread_exit = 0;
lcd_s->hardware_auto_ks = 0;
lcd_s->get_auto_ks = 0;
struct lcdc_device *lcd_dev;
lcd_dev = (struct lcdc_device *) dev_get(HG_LCDC_DEVID);
dev_put((struct dev_obj *) lcd_dev);
lcd_s->lcd_dev = lcd_dev;
lcd_s->lcd_dsi_dev = dsi_dev;
lcdc_set_video_size(lcd_dev, lcdstruct.video_w, lcdstruct.video_h);
lcdc_set_rotate_p0_up(lcd_dev, 0);
lcdc_set_rotate_p0p1_start_location(lcd_dev, 0, 0, 0, 0);
lcdc_set_rotate_linebuf_num(lcd_dev, LCD_ROTATE_LINE);
lcd_s->line_buf_num = LCD_ROTATE_LINE;
lcdc_set_video_data_from(lcd_dev, VIDEO_FROM_MEMORY_ROTATE);
lcdc_set_video_start_location(lcd_dev, lcdstruct.video_x, lcdstruct.video_y);
lcdc_set_video_en(lcd_dev, 0);
// 设置默认值,因为这个一定要配置,并且地址与p1的地址范围要一样(就是全部是psram或者全部是sram,所以这里最好都是设置psram)
lcdc_set_p0_rotate_y_src_addr(lcd_dev, (uint32) 0x28000000);
lcdc_set_p0_rotate_u_src_addr(lcd_dev, (uint32) 0x28000000);
lcdc_set_p0_rotate_v_src_addr(lcd_dev, (uint32) 0x28000000);
lcdc_set_osd_start_location(lcd_dev, lcdstruct.osd_x, lcdstruct.osd_y);
lcdc_set_osd_size(lcd_dev, lcdstruct.osd_w, lcdstruct.osd_h);
lcdc_set_osd_format(lcd_dev, OSD_RGB_565);
// 仅仅测试新框架
// lcdc_set_osd_dma_addr(lcd_dev,(uint32)osd565_encode_test);
lcdc_set_osd_alpha(lcd_dev, 0x100);
lcdc_set_osd_enc_cfg(lcd_dev, 0xFFFFFF, 0x000000);
lcdc_osd_spec_color_alpha(lcd_dev, 0, 0xffffff, 0x00);
lcdc_osd_enc_en(lcd_dev, 1);
lcdc_set_osd_en(lcd_dev, 0);
lcdc_osd_trans_en(lcd_dev, 1);
lcdc_video_enable_auto_ks(lcd_dev, 0);
lcdc_set_timeout_info(lcd_dev, 1, 3);
lcdc_request_irq(lcd_dev, LCD_DONE_IRQ, (lcdc_irq_hdl) &lcd_squralbuf_done1, (uint32) lcd_s);
#if LCD_SCREEN_RECORD_EN
uint8_t *video_psram_screen = (uint8_t *) av_psram_zalloc(SCALE_CONFIG_W * SCALE_HIGH + SCALE_CONFIG_W * SCALE_HIGH / 2);
os_printf("LCD_SCREEN_RECORD_EN psram addr:%x\n", video_psram_screen);
lcdc_screen_yuv_addr(lcd_dev, video_psram_screen, video_psram_screen + SCALE_CONFIG_W * SCALE_HIGH, video_psram_screen + SCALE_CONFIG_W * SCALE_HIGH + SCALE_CONFIG_W * SCALE_HIGH / 4);
lcdc_request_irq(lcd_dev, SCREEN_DONE_IRQ, (lcdc_irq_hdl) &lcd_screen_finish, (uint32) lcd_s);
#endif
// lcdc_request_irq(lcd_dev, OSD_EN_IRQ, (lcdc_irq_hdl)&lcd_osd_isr1_msi, (uint32)lcd_s);
lcdc_request_irq(lcd_dev, TIMEOUT_IRQ, (lcdc_irq_hdl) &lcd_timeout1, (uint32) lcd_s);
if (MACRO_PIN(LCD_TE) != 255)
{
lcdc_te_edge_cfg(lcd_dev, 1);
lcdc_request_irq(lcd_dev, LCD_TE_IRQ, (lcdc_irq_hdl) &lcd_te_isr1, (uint32) lcd_s);
}
lcdc_open(lcd_dev);
#if 0
//extern void lcd_thread(void *d);
//lcd_s->thread_hdl = os_task_create("lcd_thread", lcd_thread2, lcd_s, OS_TASK_PRIORITY_NORMAL, 0, NULL, 1024);
#else
extern int32 lcd_msi_work(struct os_work * work);
extern void lcd_msi_irq_callback(void *data);
lcd_s->app_lcd_cb = lcd_msi_irq_callback;
OS_WORK_INIT(&lcd_s->work, lcd_msi_work, 0);
os_run_work_delay(&lcd_s->work, 1);
#endif
}
void wait_lcd_exit()
{
struct app_lcd_s *lcd_s = &lcd_msg_s;
lcd_s->thread_exit = 1;
while (lcd_s->thread_hdl)
{
os_sleep_ms(1);
}
}
// 重复初始化,一般用于意外断电或者说休眠起来后使用
void lcd_driver_reinit()
{
#if 0
struct app_lcd_s *lcd_s = &lcd_msg_s;
lcd_s->hardware_ready = 1;
lcd_s->thread_exit = 0;
lcd_s->hardware_auto_ks = 0;
lcd_s->get_auto_ks = 0;
struct lcdc_device *lcd_dev;
lcd_dev = (struct lcdc_device *)dev_get(HG_LCDC_DEVID);
lcd_s->lcd_dev = lcd_dev;
lcdc_set_video_size(lcd_dev, lcdstruct.video_w, lcdstruct.video_h);
// VIDEO
lcdc_set_rotate_p0_up(lcd_dev, 0);
lcdc_set_rotate_p0p1_start_location(lcd_dev, 0, 0, 0, 0);
// line_buf后续再分配
lcdc_set_rotate_linebuf_num(lcd_dev, LCD_ROTATE_LINE);
lcdc_set_video_data_from(lcd_dev, VIDEO_FROM_MEMORY_ROTATE);
lcdc_set_video_start_location(lcd_dev, lcdstruct.video_x, lcdstruct.video_y);
lcdc_set_video_en(lcd_dev, 0);
// 设置默认值,因为这个一定要配置,并且地址与p1的地址范围要一样(就是全部是psram或者全部是sram,所以这里最好都是设置psram)
lcdc_set_p0_rotate_y_src_addr(lcd_dev, (uint32)0x38000000);
lcdc_set_p0_rotate_u_src_addr(lcd_dev, (uint32)0x38000000);
lcdc_set_p0_rotate_v_src_addr(lcd_dev, (uint32)0x38000000);
// OSD
lcdc_set_osd_start_location(lcd_dev, lcdstruct.osd_x, lcdstruct.osd_y);
lcdc_set_osd_size(lcd_dev, lcdstruct.osd_w, lcdstruct.osd_h);
lcdc_set_osd_format(lcd_dev, OSD_RGB_565);
lcdc_set_osd_alpha(lcd_dev, 0x100);
lcdc_set_osd_enc_head(lcd_dev, 0xFFFFFF, 0xFFFBFF);
lcdc_set_osd_enc_diap(lcd_dev, 0x000000, 0x000000);
lcdc_set_osd_en(lcd_dev, 0);
lcdc_video_enable_auto_ks(lcd_dev, 0);
lcdc_set_timeout_info(lcd_dev, 1, 3);
lcdc_request_irq(lcd_dev, LCD_DONE_IRQ, (lcdc_irq_hdl)&lcd_squralbuf_done1, (uint32)lcd_s);
lcdc_request_irq(lcd_dev, OSD_EN_IRQ, (lcdc_irq_hdl)&lcd_osd_isr1_msi, (uint32)lcd_s);
lcdc_request_irq(lcd_dev, TIMEOUT_IRQ, (lcdc_irq_hdl)&lcd_timeout1, (uint32)lcd_s);
if (MACRO_PIN(LCD_TE) != 255) {
lcdc_set_te_edge(lcd_dev, 1);
lcdc_request_irq(lcd_dev, LCD_TE_IRQ, (lcdc_irq_hdl)&lcd_te_isr1, (uint32)lcd_s);
}
lcdc_open(lcd_dev);
// lcdc_set_start_run(lcd_dev);
extern void lcd_thread(void *d);
lcd_s->thread_hdl = os_task_create("lcd_thread", lcd_thread, (void *)lcd_s, OS_TASK_PRIORITY_NORMAL, 0, NULL, 1024);
#endif
}
#if 0
void lcd_module_run2(){
uint32_t rbuf[4];
uint8_t *pt8;
uint8 pixel_dot_num = 1;
uint32_t *osd_sram_fifo;
struct lcdc_device *lcd_dev;
struct spi_device *spi_dev;
struct scale_device *scale_dev;
struct vpp_device *vpp_dev;
struct jpg_device *jpg_dev;
jpg_dev = (struct jpg_device *)dev_get(HG_JPG1_DEVID);
vpp_dev = (struct vpp_device *)dev_get(HG_VPP_DEVID);
scale_dev = (struct scale_device *)dev_get(HG_SCALE2_DEVID);
lcd_dev = (struct lcdc_device *)dev_get(HG_LCDC_DEVID);
spi_dev = (struct spi_device * )dev_get(HG_SPI0_DEVID);
lcdc_set_video_size(lcd_dev,lcdstruct.video_w,lcdstruct.video_h);
lcdc_set_osd_start_location(lcd_dev,lcdstruct.osd_x,lcdstruct.osd_y);
lcdc_set_osd_size(lcd_dev,lcdstruct.osd_w,lcdstruct.osd_h);
lcdc_set_osd_dma_addr(lcd_dev,(uint32)osd565_encode_test);
lcdc_set_osd_format(lcd_dev,OSD_RGB_565);
lcdc_set_osd_alpha(lcd_dev,0x100);
lcdc_set_osd_enc_cfg(lcd_dev,0xFFFFFF,0x000000);
lcdc_osd_spec_color_alpha(lcd_dev,0,0xffffff,0x00);
lcdc_osd_enc_en(lcd_dev,1);
lcdc_set_osd_en(lcd_dev,1);
lcdc_osd_trans_en(lcd_dev,1);
if((lcdstruct.lcd_bus_type == LCD_BUS_RGB)||(lcdstruct.lcd_bus_type == LCD_BUS_MIPI)||(lcdstruct.lcd_bus_type == LCD_BUS_QSPI)){
lcdc_clock_alway_on(lcd_dev,1);
}
lcdc_rot_burst_dw16(lcd_dev,0);
lcdc_video_enable_auto_ks(lcd_dev,0);
lcdc_set_timeout_info(lcd_dev,1,3);
lcdc_request_irq(lcd_dev,LCD_DONE_IRQ,(lcdc_irq_hdl )&lcd_squralbuf_done1,(uint32)lcd_dev);
lcdc_open(lcd_dev);
os_sleep_ms(10);
lcdc_set_start_run(lcd_dev);
}
#endif
#endif

117
sdk/app/app_lcd/app_lcd.h Normal file
View File

@@ -0,0 +1,117 @@
#ifndef __APP_LCD_H
#define __APP_LCD_H
#include "sys_config.h"
#include "typesdef.h"
#include "stream_frame.h"
#include "basic_include.h"
#include "lib/multimedia/msi.h"
typedef void (*app_lcd_callback)(void *lcd_s);
#define LCD_RB_COUNT 4
#define LCD_DELETE_RB_COUNT 8
struct app_lcd_s
{
struct os_work work;
struct msi *osd_enc_msi;
struct msi *lcd_osd_msi;
struct msi *video_p0_msi;
struct msi *video_p1_msi;
struct msi *csc_video_p2_msi;
//创建多个队列,分别是osd、p0、p1以及csc_p2(将收到的fb放到队列,然后中断去获取队列,这里采用ringbuf的形式)
RBUFFER_DEF(osd_rb, struct framebuff *, LCD_RB_COUNT);
RBUFFER_DEF(p0_rb, struct framebuff *, LCD_RB_COUNT);
RBUFFER_DEF(p1_rb, struct framebuff *, LCD_RB_COUNT);
RBUFFER_DEF(p2_rb, struct framebuff *, LCD_RB_COUNT);
RBUFFER_DEF(delete_rb, struct framebuff *, LCD_DELETE_RB_COUNT);
struct framebuff * p0_fb;
struct framebuff * p1_fb;
struct framebuff * p2_fb;
struct framebuff * osd_fb;
app_lcd_callback app_lcd_cb;
struct lcdc_device *lcd_dev;
struct dsi_device *lcd_dsi_dev;
// 只有thread_hdl退出后,才可以休眠
void *thread_hdl;
void *line_buf;
void *free_line_buf;
uint32_t start_time;
uint32_t end_time;
uint32_t last_start_time;
uint16_t refresh_time;
uint16_t w, h;
uint16_t screen_w, screen_h;
uint16_t video_w, video_h;
uint16_t x0,y0,x1,y1;
uint8_t line_buf_num;
uint8_t rotate;
uint8_t video_rotate;
uint8_t hardware_auto_ks : 1, // 由应用层写入,由lcd模块读取
get_auto_ks : 1, // 由应用层去读取,由lcd的模块去设置
hardware_ready : 1,
thread_exit : 1,
rekick_lcd : 1;
};
extern struct app_lcd_s lcd_msg_s;
void lcd_arg_setting(uint16_t w, uint16_t h, uint8_t rotate, uint16_t screen_w, uint16_t screen_h,uint16_t video_w, uint16_t video_h, uint8_t video_rotate);
void lcd_driver_init(const char *osd_encode_name, const char *lcd_osd_name, const char *lcd_video_p0, const char *lcd_video_p1);
void wait_lcd_exit();
void lcd_driver_reinit();
void lcd_hardware_init(uint16_t *w, uint16_t *h, uint8_t *rotate, uint16_t *screen_w, uint16_t *screen_h,uint16_t *video_w, uint16_t *video_h, uint8_t *video_rotate);
uint8_t g_read_hardware_auto_ks();
uint8_t g_set_hardware_auto_ks(uint8_t en);
/*****************************osd_encode_msi******************************************/
extern struct msi *osd_encode_msi_init(const char *name);
/*************************************************************************************/
/*****************************lcd_osd_msi******************************************/
struct msi *lcd_osd_msi(const char *name);
struct lcd_osd_msi_s
{
struct lcdc_device *lcd_dev;
struct msi *msi;
struct framebuff *cur_show_data_s;
struct framebuff *last_show_data_s;
struct framebuff *delete_show_data_s;
};
/*************************************************************************************/
/*****************************lcd_video_msi******************************************/
struct msi *lcd_video_msi_init(const char *name, uint16_t filter);
struct lcd_video_msi_s
{
struct msi *msi;
uint16_t filter;
struct framebuff *cur_fb;
struct framebuff *last_fb;
struct framebuff *delete_fb;
};
/*************************************************************************************/
/*****************************lvgl_osd_msi******************************************/
struct msi *lvgl_osd_msi(const char *name);
struct framebuff *lvgl_osd_msi_get_fb(struct msi *msi);
typedef void (*osd_finish_cb)(void *self);
typedef void (*osd_free_cb)(void *self, void *data);
struct encode_data_s_callback
{
osd_finish_cb finish_cb;
osd_free_cb free_cb;
void * user_data;
uint8_t rot_flag : 1,
res : 7;
};
/*************************************************************************************/
#endif

632
sdk/app/app_lcd/lcd_msi.c Normal file
View File

@@ -0,0 +1,632 @@
#include "basic_include.h"
#include "stream_frame.h"
#include "utlist.h"
#include "lib/lcd/lcd.h"
#include "app_lcd.h"
#include "lib/multimedia/msi.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#include "user_work/user_work.h"
enum LCD_SHOW_MAP
{
LCD_OSD = BIT(0),
LCD_P0 = BIT(1),
LCD_P1 = BIT(2),
LCD_P2 = BIT(3),
};
// 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 LCD_MSI_DEBUG(fmt, ...) // os_printf(fmt, ##__VA_ARGS__)
/* 中断 kick lcd 模式 */
typedef int32 (*lcdc_set_rotate_y_src_addr)(struct lcdc_device *p_lcdc, uint32 yaddr);
typedef int32 (*lcdc_set_rotate_u_src_addr)(struct lcdc_device *p_lcdc, uint32 uaddr);
typedef int32 (*lcdc_set_rotate_v_src_addr)(struct lcdc_device *p_lcdc, uint32 vaddr);
static void lcd_msi_irq_video_show(struct app_lcd_s *lcd_s, uint8_t which_video, uint8_t *p0_p1_enable, uint32_t *p_w, uint32_t *p_h)
{
struct msi *v_msi = NULL;
struct lcd_video_msi_s *video = NULL;
struct framebuff *last_fb = NULL;
uint8_t ret;
uint32_t temp_w, temp_h;
uint16_t *x = NULL;
uint16_t *y = NULL;
lcdc_set_rotate_y_src_addr p_lcdc_set_rotate_y_src_addr = NULL;
lcdc_set_rotate_u_src_addr p_lcdc_set_rotate_u_src_addr = NULL;
lcdc_set_rotate_v_src_addr p_lcdc_set_rotate_v_src_addr = NULL;
/*****************************************************************************************************
* 要切换fb的条件分别是:
* 1、检查delete的队列是否满了并且已经有显示过的fb,如果delete队列满了,那不能切换fb,需要保持原样,等待删除队列有空闲位置才能去切换
* 2、需要检查当前是否有需要显示的,如果没有显示的,可以去从对应的队列获取fb去显示
*****************************************************************************************************/
if (which_video == 0)
{
video = (struct lcd_video_msi_s *) lcd_s->video_p0_msi->priv;
v_msi = lcd_s->video_p0_msi;
last_fb = lcd_s->p0_fb;
if (v_msi->enable)
{
x = &lcd_s->x0;
y = &lcd_s->y0;
p_lcdc_set_rotate_y_src_addr = lcdc_set_p0_rotate_y_src_addr;
p_lcdc_set_rotate_u_src_addr = lcdc_set_p0_rotate_u_src_addr;
p_lcdc_set_rotate_v_src_addr = lcdc_set_p0_rotate_v_src_addr;
// 如果上一次没有显示,则尝试从队列获取fb去显示
if (!last_fb)
{
RB_GET(&lcd_s->p0_rb, lcd_s->p0_fb);
last_fb = lcd_s->p0_fb;
}
// 曾经显示过,就要检查一下delete rb是否还有空位,有空位才能切换fb
else if (!RB_FULL(&lcd_s->delete_rb))
{
// 检查是否有需要切换的fb
ret = RB_GET(&lcd_s->p0_rb, lcd_s->p0_fb);
// 更新切换的fb
if (ret)
{
// 把需要删除的last fb放到delete rb的队列
RB_SET(&lcd_s->delete_rb, last_fb);
last_fb = lcd_s->p0_fb;
}
}
// last fb存在和delete rb队列满了,则不需要切换,等待下次切换
else
{
}
}
// 使能被关闭,则需要清除显示的fb,那么要检查delete rb的队列是否为空
else
{
if (last_fb && !RB_FULL(&lcd_s->delete_rb))
{
RB_SET(&lcd_s->delete_rb, last_fb);
last_fb = NULL;
lcd_s->p0_fb = NULL;
}
}
}
else if (which_video == 1)
{
v_msi = lcd_s->video_p1_msi;
video = (struct lcd_video_msi_s *) lcd_s->video_p1_msi->priv;
last_fb = lcd_s->p1_fb;
if (v_msi->enable)
{
x = &lcd_s->x1;
y = &lcd_s->y1;
p_lcdc_set_rotate_y_src_addr = lcdc_set_p1_rotate_y_src_addr;
p_lcdc_set_rotate_u_src_addr = lcdc_set_p1_rotate_u_src_addr;
p_lcdc_set_rotate_v_src_addr = lcdc_set_p1_rotate_v_src_addr;
// 如果上一次没有显示,则尝试从队列获取fb去显示
if (!last_fb)
{
RB_GET(&lcd_s->p1_rb, lcd_s->p1_fb);
last_fb = lcd_s->p1_fb;
}
// 曾经显示过,就要检查一下delete rb是否还有空位,有空位才能切换fb
else if (!RB_FULL(&lcd_s->delete_rb))
{
// 检查是否有需要切换的fb
ret = RB_GET(&lcd_s->p1_rb, lcd_s->p1_fb);
// 更新切换的fb
if (ret)
{
// 把需要删除的last fb放到delete rb的队列
RB_SET(&lcd_s->delete_rb, last_fb);
last_fb = lcd_s->p1_fb;
}
}
// last fb存在和delete rb队列满了,则不需要切换,等待下次切换
else
{
}
}
// 使能被关闭,则需要清除显示的fb,那么要检查delete rb的队列是否为空
else
{
if (last_fb && !RB_FULL(&lcd_s->delete_rb))
{
RB_SET(&lcd_s->delete_rb, last_fb);
last_fb = NULL;
lcd_s->p1_fb = NULL;
}
}
}
else if (which_video == 2)
{
v_msi = lcd_s->csc_video_p2_msi;
video = (struct lcd_video_msi_s *) lcd_s->csc_video_p2_msi->priv;
last_fb = lcd_s->p2_fb;
if (v_msi->enable)
{
x = &lcd_s->x0;
y = &lcd_s->y0;
p_lcdc_set_rotate_y_src_addr = lcdc_set_p0_rotate_y_src_addr;
p_lcdc_set_rotate_u_src_addr = lcdc_set_p0_rotate_u_src_addr;
p_lcdc_set_rotate_v_src_addr = lcdc_set_p0_rotate_v_src_addr;
// 如果上一次没有显示,则尝试从队列获取fb去显示
if (!last_fb)
{
RB_GET(&lcd_s->p2_rb, lcd_s->p2_fb);
last_fb = lcd_s->p2_fb;
}
// 曾经显示过,就要检查一下delete rb是否还有空位,有空位才能切换fb
else if (!RB_FULL(&lcd_s->delete_rb))
{
// 检查是否有需要切换的fb
ret = RB_GET(&lcd_s->p2_rb, lcd_s->p2_fb);
// 更新切换的fb
if (ret)
{
// 把需要删除的last fb放到delete rb的队列
RB_SET(&lcd_s->delete_rb, last_fb);
last_fb = lcd_s->p2_fb;
}
}
// last fb存在和delete rb队列满了,则不需要切换,等待下次切换
else
{
}
}
// 使能被关闭,则需要清除显示的fb,那么要检查delete rb的队列是否为空
else
{
if (last_fb && !RB_FULL(&lcd_s->delete_rb))
{
RB_SET(&lcd_s->delete_rb, last_fb);
last_fb = NULL;
lcd_s->p2_fb = NULL;
}
}
}
// 需要将队列的数据清除
if (!v_msi->enable)
{
return;
}
struct framebuff *fb = last_fb;
// 这里再次判断p_fb,保证非空才打开使能,有可能此时外部选择关闭
if (fb)
{
*p0_p1_enable |= BIT(which_video);
struct yuv_arg_s *yuv_msg = (struct yuv_arg_s *) fb->priv;
uint32_t y_off = 0, uv_off = 0;
uint8_t *p_buf = (uint8_t *) fb->data;
temp_w = yuv_msg->out_w;
temp_h = yuv_msg->out_h;
*p_w = temp_w;
*p_h = temp_h;
*x = yuv_msg->x;
*y = yuv_msg->y;
if (lcd_s->video_rotate == LCD_ROTATE_180)
{
y_off = temp_w * (temp_h - 1);
uv_off = ((temp_w / 2 + 3) / 4) * 4 * (temp_h / 2 - 1);
}
LCD_MSI_DEBUG("p%d yuv_msg->y_size:%d \n", which_video, yuv_msg->y_size);
p_lcdc_set_rotate_y_src_addr(lcd_s->lcd_dev, (uint32) p_buf + y_off);
p_lcdc_set_rotate_u_src_addr(lcd_s->lcd_dev, (uint32) p_buf + yuv_msg->y_size + uv_off);
p_lcdc_set_rotate_v_src_addr(lcd_s->lcd_dev, (uint32) p_buf + yuv_msg->y_size + yuv_msg->y_size / 4 + uv_off);
}
}
static void lcd_msi_irq_osd_show(struct app_lcd_s *lcd_s, uint8_t *osd_en)
{
struct msi *v_msi = lcd_s->lcd_osd_msi;
int32_t ret;
struct framebuff *last_fb = lcd_s->osd_fb;
if (v_msi->enable)
{
// 如果上一次没有显示,则尝试从队列获取fb去显示
if (!last_fb)
{
RB_GET(&lcd_s->osd_rb, lcd_s->osd_fb);
last_fb = lcd_s->osd_fb;
}
// 曾经显示过,就要检查一下delete rb是否还有空位,有空位才能切换fb
else if (!RB_FULL(&lcd_s->delete_rb))
{
// 检查是否有需要切换的fb
ret = RB_GET(&lcd_s->osd_rb, lcd_s->osd_fb);
// 更新切换的fb
if (ret)
{
// 把需要删除的last fb放到delete rb的队列
RB_SET(&lcd_s->delete_rb, last_fb);
last_fb = lcd_s->osd_fb;
}
}
// last fb存在和delete rb队列满了,则不需要切换,等待下次切换
else
{
}
}
else
{
if (last_fb && !RB_FULL(&lcd_s->delete_rb))
{
RB_SET(&lcd_s->delete_rb, last_fb);
last_fb = NULL;
lcd_s->osd_fb = NULL;
}
}
// 这里再次判断osd_fb,保证非空才打开使能,有可能此时外部选择关闭
if (last_fb)
{
*osd_en = 1;
lcdc_set_osd_dma_addr(lcd_s->lcd_dev, (uint32_t) last_fb->data);
}
}
int g_osd_en = 1;
void lcd_msi_irq_callback(void *data)
{
struct app_lcd_s *lcd_s = (struct app_lcd_s *) data;
uint8_t p0_p1_enable = 0;
uint8_t osd_en = 0;
uint32_t p0_w = 0, p0_h = 0, p1_w = 0, p1_h = 0;
// 设置 OSD 的 DMA 地址
lcd_msi_irq_osd_show(lcd_s, &osd_en);
// 设置视频 P0 的地址
lcd_msi_irq_video_show(lcd_s, 0, &p0_p1_enable, &p0_w, &p0_h);
// 设置视频 P1 的地址
lcd_msi_irq_video_show(lcd_s, 1, &p0_p1_enable, &p1_w, &p1_h);
// 设置 CSC P2 的地址
lcd_msi_irq_video_show(lcd_s, 2, &p0_p1_enable, &p0_w, &p0_h);
if (lcd_s->p2_fb && lcd_s->osd_fb)
{
uint32_t osd_fb_time = lcd_s->osd_fb->time;
uint32_t p2_fb_time = lcd_s->p2_fb->time;
int32_t diff = osd_fb_time - p2_fb_time;
struct framebuff *del_fb = NULL;
uint8_t del_flag = 0;
// 因为在中断,delete rb有空位,代表可以删除
if (!RB_FULL(&lcd_s->delete_rb))
{
del_flag = 1;
}
// 需要移除一个fb,这里需要保证delete rb有空位,没有空位,则报一下错误(某些情况应该是异常显示,需要优化)
if (diff > 0)
{
del_fb = lcd_s->p2_fb;
p0_p1_enable &= ~BIT(2);
if (del_flag)
{
lcd_s->p2_fb = NULL;
}
}
else if (diff < 0)
{
del_fb = lcd_s->osd_fb;
osd_en = 0;
if (del_flag)
{
lcd_s->osd_fb = NULL;
}
}
else
{
}
// 删除对应的fb
if (del_flag)
{
RB_SET(&lcd_s->delete_rb, del_fb);
}
}
if (osd_en == 0 && p0_p1_enable == 0)
{
os_printf("(@@@@@@@@@@@)\n");
}
// 打开video
if (p0_p1_enable)
{
// 检查一下line_buf是否已经申请了,申请空间就是w*line_num的空间(w应该是和屏旋转有关)
uint16_t rotate_w;
rotate_w = (lcd_s->video_w+15)/16*16;
if (lcd_s->line_buf)
{
lcdc_set_rotate_linebuf_y_addr(lcd_s->lcd_dev, (uint32) lcd_s->line_buf);
lcdc_set_rotate_linebuf_u_addr(lcd_s->lcd_dev, (uint32) lcd_s->line_buf + rotate_w * lcd_s->line_buf_num);
lcdc_set_rotate_linebuf_v_addr(lcd_s->lcd_dev, (uint32) lcd_s->line_buf + rotate_w * lcd_s->line_buf_num + (rotate_w / 2) * lcd_s->line_buf_num);
LCD_MSI_DEBUG("p0_w:%d p0_h:%d p1_w:%d p1_h:%d\n", p0_w, p0_h, p1_w, p1_h);
lcdc_set_rotate_p0p1_size(lcd_s->lcd_dev, p0_w, p0_h, p1_w, p1_h);
lcdc_set_rotate_mirror(lcd_s->lcd_dev, 0, lcd_s->video_rotate);
if (lcd_s->video_rotate == LCD_ROTATE_180)
{
lcdc_set_video_start_location(lcd_s->lcd_dev, 0, 0);
lcdc_set_rotate_p0p1_start_location(lcd_s->lcd_dev, lcd_s->x0, 0, lcd_s->x1, lcd_s->y1);
}
else
{
lcdc_set_video_start_location(lcd_s->lcd_dev, 0, 0);
lcdc_set_rotate_p0p1_start_location(lcd_s->lcd_dev, lcd_s->x0, lcd_s->y0, lcd_s->x1, lcd_s->y1);
}
lcdc_set_p0p1_enable(lcd_s->lcd_dev, (p0_p1_enable & BIT(0)) ? 1 : (p0_p1_enable & BIT(2)), p0_p1_enable & BIT(1));
lcdc_set_video_en(lcd_s->lcd_dev, 1);
}
else
{
lcdc_set_video_en(lcd_s->lcd_dev, 0);
}
}
else
{
if (lcd_s->free_line_buf && lcd_s->line_buf)
{
LCD_MSI_DEBUG("-----------force free video line buff:0x%x-----------\n", lcd_s->free_line_buf);
STREAM_LIBC_FREE(lcd_s->free_line_buf);
lcd_s->free_line_buf = NULL;
}
if (lcd_s->line_buf)
{
lcd_s->free_line_buf = lcd_s->line_buf;
lcd_s->line_buf = NULL;
}
lcdc_set_video_en(lcd_s->lcd_dev, 0);
}
lcdc_set_osd_en(lcd_s->lcd_dev, osd_en);
lcdc_set_timeout_info(lcd_s->lcd_dev, 1, 3);
lcdc_set_start_run(lcd_s->lcd_dev);
lcd_s->start_time = os_jiffies();
}
// 检查如果被关闭了,则清空队列,这里有个问题,如果使能被关闭后立刻打开,是不会清空队列的,这个要考虑后续如何去处理
void clear_msi_fb(struct msi *v_msi)
{
struct framebuff *fb;
while (v_msi)
{
fb = msi_get_fb(v_msi, 0);
if (fb)
{
os_printf("msi name:%s\tfb:%X\n", v_msi->name, fb);
msi_delete_fb(NULL, fb);
}
else
{
break;
}
}
}
int32 lcd_msi_work(struct os_work *work)
{
struct app_lcd_s *lcd_s = (struct app_lcd_s *) work;
struct lcd_video_msi_s *video_p0 = NULL;
struct lcd_video_msi_s *video_p1 = NULL;
struct lcd_video_msi_s *csc_video_p2 = NULL;
struct lcd_osd_msi_s *osd_show = NULL;
struct framebuff *fb;
uint32_t lcd_show_map = 0;
uint32_t temp = 0;
static int count = 0;
osd_show = (struct lcd_osd_msi_s *) lcd_s->lcd_osd_msi->priv;
video_p0 = (struct lcd_video_msi_s *) lcd_s->video_p0_msi->priv;
video_p1 = (struct lcd_video_msi_s *) lcd_s->video_p1_msi->priv;
csc_video_p2 = (struct lcd_video_msi_s *) lcd_s->csc_video_p2_msi->priv;
// 如果不需要显示video,则空间释放吧
if (lcd_s->free_line_buf)
{
LCD_MSI_DEBUG("-----------free video line buff:0x%x-----------\n", lcd_s->free_line_buf);
irq_disable(LCD_IRQn);
temp = (uint32_t) lcd_s->free_line_buf;
lcd_s->free_line_buf = NULL;
irq_enable(LCD_IRQn);
STREAM_LIBC_FREE((void *) temp);
}
// 检查一下是否有fb需要删除,从delete rb里面查找
while (!RB_EMPTY(&lcd_s->delete_rb))
{
RB_GET(&lcd_s->delete_rb, fb);
msi_delete_fb(NULL, fb);
}
// 检查是否需要清空队列,一个一个清空(通过使能位来判断,如果使能被关闭,则清空对应的队列)
// 这里没有考虑正在显示的情况,正在显示的由中断去放到delete rb的队列
// 将对应rb队列清空(由于ringbuf结构体原因,暂时没有通用函数,先在这里清空)
if (!lcd_s->lcd_osd_msi->enable)
{
clear_msi_fb(lcd_s->lcd_osd_msi);
while (!RB_EMPTY(&lcd_s->osd_rb))
{
// 因为get会在中断使用,所以这里采用安全方式去读取,防止异步问题
if (RB_INT_GET(&lcd_s->osd_rb, fb))
{
msi_delete_fb(NULL, fb);
}
}
}
if (!lcd_s->video_p0_msi->enable)
{
clear_msi_fb(lcd_s->video_p0_msi);
while (!RB_EMPTY(&lcd_s->p0_rb))
{
// 因为get会在中断使用,所以这里采用安全方式去读取,防止异步问题
if (RB_INT_GET(&lcd_s->p0_rb, fb))
{
msi_delete_fb(NULL, fb);
}
}
}
if (!lcd_s->video_p1_msi->enable)
{
clear_msi_fb(lcd_s->video_p1_msi);
while (!RB_EMPTY(&lcd_s->p1_rb))
{
// 因为get会在中断使用,所以这里采用安全方式去读取,防止异步问题
if (RB_INT_GET(&lcd_s->p1_rb, fb))
{
msi_delete_fb(NULL, fb);
}
}
}
if (!lcd_s->csc_video_p2_msi->enable)
{
clear_msi_fb(lcd_s->csc_video_p2_msi);
while (!RB_EMPTY(&lcd_s->p2_rb))
{
// 因为get会在中断使用,所以这里采用安全方式去读取,防止异步问题
if (RB_INT_GET(&lcd_s->p2_rb, fb))
{
msi_delete_fb(NULL, fb);
}
}
}
// 将获取到对应的fb放到队列里面,如果被disable,需要将队列清空
if (!RB_FULL(&lcd_s->osd_rb))
{
fb = msi_get_fb(lcd_s->lcd_osd_msi, 0);
if (fb)
{
RB_SET(&lcd_s->osd_rb, fb);
}
}
if (!RB_FULL(&lcd_s->p0_rb))
{
fb = msi_get_fb(lcd_s->video_p0_msi, 0);
if (fb)
{
RB_SET(&lcd_s->p0_rb, fb);
}
}
if (!RB_FULL(&lcd_s->p1_rb))
{
fb = msi_get_fb(lcd_s->video_p1_msi, 0);
if (fb)
{
RB_SET(&lcd_s->p1_rb, fb);
}
}
if (!RB_FULL(&lcd_s->p2_rb))
{
fb = msi_get_fb(lcd_s->csc_video_p2_msi, 0);
if (fb)
{
RB_SET(&lcd_s->p2_rb, fb);
}
}
// 检查队列是否为空
if (lcd_s->osd_fb || !RB_EMPTY(&lcd_s->osd_rb))
{
lcd_show_map |= LCD_OSD;
}
if (lcd_s->p0_fb || !RB_EMPTY(&lcd_s->p0_rb))
{
lcd_show_map |= LCD_P0;
}
if (lcd_s->p1_fb || !RB_EMPTY(&lcd_s->p1_rb))
{
lcd_show_map |= LCD_P1;
}
if (lcd_s->p2_fb || !RB_EMPTY(&lcd_s->p2_rb))
{
lcd_show_map |= LCD_P2;
}
// 如果p0和p1、p2的队列不为空,则要尝试申请空间
if (lcd_show_map & (LCD_P0 | LCD_P1 | LCD_P2))
{
uint16_t rotate_w;
rotate_w = (lcd_s->video_w+15)/16*16;
// 这里理论要申请到空间,如果申请失败,重新申请一下(否则要就额外处理资源数据)
if (!lcd_s->line_buf)
{
lcd_s->line_buf = (void *) STREAM_LIBC_MALLOC(lcd_s->line_buf_num * rotate_w * 2);
LCD_MSI_DEBUG("-----------alloc video line buff:0x%x-----------\n", lcd_s->line_buf);
}
// 空间申请失败,是尝试等待申请空间还是清空队列?这里就是等待下次申请空间去尝试吧
if (!lcd_s->line_buf)
{
}
}
if (lcd_show_map)
{
lcd_s->hardware_ready = 0; // 标记fb已准备好等待刷新
}
else
{
goto __lcd_msi_work_end;
}
if ((!count && !lcd_s->hardware_ready) || lcd_s->rekick_lcd)
{
count++;
lcd_s->rekick_lcd = 0;
LCD_MSI_DEBUG("=========first kick lcd=========\n");
lcd_s->app_lcd_cb(lcd_s);
}
__lcd_msi_work_end:
os_run_work_delay(&lcd_s->work, 1);
return 0;
}

View File

@@ -0,0 +1,86 @@
#include "app_lcd.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
// 这里只是为了给osd创建流,实际内部没有做什么,这个流取到的数据应该是已经压缩过的
// 接收到就可以配置硬件寄存器了
// 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_OSD_SHOW_RX 8
static int lcd_osd_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
{
int ret = RET_OK;
struct lcd_osd_msi_s *show = (struct lcd_osd_msi_s *)msi->priv;
switch (cmd_id)
{
// 暂时没有考虑释放
case MSI_CMD_POST_DESTROY:
{
STREAM_LIBC_FREE(show);
}
break;
// 接收,判断是否已经压缩了
case MSI_CMD_TRANS_FB:
{
struct framebuff *fb = (struct framebuff *)param1;
if(fb->mtype != F_ERGB)
{
ret = RET_ERR;
}
}
break;
case MSI_CMD_FREE_FB:
{
}
break;
case MSI_CMD_LCD_OSD:
{
uint32_t cmd_self = (uint32_t)param1;
uint32_t arg = param2;
switch (cmd_self)
{
case MSI_OSD_ENABLE:
{
msi->enable = arg;
os_printf("---MSI_OSD_ENABLE :%d----\n",msi->enable);
}
break;
}
}
break;
default:
break;
}
return ret;
}
struct msi *lcd_osd_msi(const char *name)
{
struct msi *msi = msi_new(name, MAX_OSD_SHOW_RX, NULL);
struct lcd_osd_msi_s *show = (struct lcd_osd_msi_s *)msi->priv;
struct lcdc_device *lcd_dev;
if (!show)
{
show = (struct lcd_osd_msi_s *)STREAM_LIBC_ZALLOC(sizeof(struct lcd_osd_msi_s));
lcd_dev = (struct lcdc_device *)dev_get(HG_LCDC_DEVID);
show->lcd_dev = lcd_dev;
msi->action = lcd_osd_msi_action;
show->msi = msi;
msi->priv = (void *)show;
msi->enable = 1;
}
return msi;
}

View File

@@ -0,0 +1,88 @@
#include "app_lcd.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
// 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_LCD_VIDEO 8
static int lcd_video_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
{
int ret = RET_OK;
struct lcd_video_msi_s *lcd_video = (struct lcd_video_msi_s *)msi->priv;
switch (cmd_id)
{
// 暂时没有考虑释放
case MSI_CMD_POST_DESTROY:
{
STREAM_LIBC_FREE(lcd_video);
}
break;
// 类型不匹配,就不需要接收
case MSI_CMD_TRANS_FB:
{
struct framebuff *fb = (struct framebuff *)param1;
if((fb->mtype != F_YUV) || (fb->stype != lcd_video->filter))
{
ret = RET_ERR;
}
}
break;
case MSI_CMD_FREE_FB:
{
}
break;
case MSI_CMD_LCD_VIDEO:
{
uint32_t cmd_self = (uint32_t)param1;
uint32_t arg = param2;
switch (cmd_self)
{
case MSI_VIDEO_ENABLE:
{
msi->enable = arg;
os_printf("---%s MSI_VIDEO_ENABLE :%d----\n",msi->name, msi->enable);
}
break;
case MSI_VIDEO_GET_ENABLE:
{
uint32_t *val = (uint32_t *)param2;
// os_printf("---%s get enable:%d-----\n",msi->name, msi->enable);
*val = msi->enable;
}
break;
}
}
break;
default:
break;
}
return ret;
}
struct msi *lcd_video_msi_init(const char *name, uint16_t filter)
{
struct msi *msi = msi_new(name, MAX_LCD_VIDEO, NULL);
struct lcd_video_msi_s *lcd_video = (struct lcd_video_msi_s *)msi->priv;
if (!lcd_video)
{
lcd_video = (struct lcd_video_msi_s *)STREAM_LIBC_ZALLOC(sizeof(struct lcd_video_msi_s));
lcd_video->msi = msi;
lcd_video->filter = filter;
msi->priv = (void *)lcd_video;
msi->enable = 1;
msi->action = lcd_video_msi_action;
}
return msi;
}

View File

@@ -0,0 +1,132 @@
#include "app_lcd.h"
#include "basic_include.h"
#include "lib/multimedia/msi.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
// 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_LVGL_OSD_TX 2
struct lvgl_osd_msi_s
{
struct msi *msi;
struct fbpool tx_pool;
};
static int lvgl_osd_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
{
int ret = RET_OK;
struct lvgl_osd_msi_s *lvgl_osd = (struct lvgl_osd_msi_s *)msi->priv;
switch (cmd_id)
{
// 暂时没有考虑释放
case MSI_CMD_POST_DESTROY:
{
struct framebuff *fb;
// 释放资源fb资源文件,priv是独立申请的
while (1)
{
fb = fbpool_get(&lvgl_osd->tx_pool, 0, NULL);
if (!fb)
{
break;
}
// 预分配空间释放
if (fb->priv)
{
STREAM_LIBC_FREE(fb->priv);
}
}
fbpool_destroy(&lvgl_osd->tx_pool);
STREAM_LIBC_FREE(lvgl_osd);
}
break;
// 接收,判断是类型是否可以支持压缩
case MSI_CMD_TRANS_FB:
{
}
break;
case MSI_CMD_FREE_FB:
{
struct framebuff *fb = (struct framebuff *)param1;
struct encode_data_s_callback *callback = (struct encode_data_s_callback *)fb->priv;
if (callback->finish_cb)
{
callback->finish_cb(callback->user_data);
}
if (callback->free_cb)
{
callback->free_cb(callback->user_data, fb->data);
}
// 这个data可能是lvgl那边的,暂时不需要释放
fb->data = NULL;
callback->finish_cb = NULL;
callback->free_cb = NULL;
callback->user_data = NULL;
// msi_get_fb(NULL,fb);
fbpool_put(&lvgl_osd->tx_pool, fb);
ret = RET_OK + 1;
}
break;
default:
break;
}
return ret;
}
struct framebuff *lvgl_osd_msi_get_fb(struct msi *msi)
{
struct lvgl_osd_msi_s *lvgl_osd = (struct lvgl_osd_msi_s *)msi->priv;
struct framebuff *fb = fbpool_get(&lvgl_osd->tx_pool, 0, lvgl_osd->msi);
if(fb)
{
fb->mtype = F_RGB;
fb->stype = LVGL_RGB;
}
return fb;
}
// 拷贝osd到内存,然后发送出去,使用workqueue去作为任务吧
struct msi *lvgl_osd_msi(const char *name)
{
struct msi *msi = msi_new(name, 0, NULL);
struct lvgl_osd_msi_s *lvgl_osd = (struct lvgl_osd_msi_s *)msi->priv;
if (!lvgl_osd)
{
lvgl_osd = (struct lvgl_osd_msi_s *)STREAM_LIBC_ZALLOC(sizeof(struct lvgl_osd_msi_s));
lvgl_osd->msi = msi;
fbpool_init(&lvgl_osd->tx_pool, MAX_LVGL_OSD_TX);
int init_count = 0;
void *priv;
// 初始化framebuffer节点数量空间?最后由workqueue去从ringbuf去获取一个节点
while (init_count < MAX_LVGL_OSD_TX)
{
priv = (void *)STREAM_LIBC_ZALLOC(sizeof(struct encode_data_s_callback));
FBPOOL_SET_INFO(&lvgl_osd->tx_pool, init_count, NULL, 0, priv);
init_count++;
}
msi->priv = (void *)lvgl_osd;
msi->action = lvgl_osd_msi_action;
msi->enable = 1;
msi_add_output(lvgl_osd->msi, NULL, R_OSD_ENCODE);
msi_add_output(lvgl_osd->msi, NULL, R_CSC_MSI);
}
return msi;
}

View File

@@ -0,0 +1,314 @@
#include "stream_frame.h"
#include "osal/work.h"
#include "basic_include.h"
#include "lib/multimedia/msi.h"
#include "hal/osd_enc.h"
#include "dev/osd_enc/hgosd_enc.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
// 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_OSD_ENCODE_RX 8
#define MAX_OSD_ENCODE_TX 8
struct osd_encode_msi_s
{
struct os_work work;
struct osdenc_device *osd_enc_dev;
struct msi *msi;
uint8_t *osd_tmp_buf;
uint32_t osd_tmp_buf_size;
struct fbpool tx_pool;
struct framebuff *parent_data_s;
// osd压缩后的数据长度
uint32_t data_len;
uint32_t start_time;
// 解码模块是否可用
uint8_t hardware_ready;
};
static int32 osd_enc_isr_msi(uint32 irq_flag, uint32 irq_data, uint32 param1)
{
struct osd_encode_msi_s *osd_enc = (struct osd_encode_msi_s *)irq_data;
struct osdenc_device *osd_enc_dev;
struct msi *osd_enc_msi = (struct msi *)osd_enc->msi;
osd_enc_dev = osd_enc->osd_enc_dev;
// _os_printf("=");
msi_do_cmd(osd_enc_msi, MSI_CMD_OSD_ENCODE, MSI_OSD_HARDWARE_ENCODE_SET_LEN, osd_enc_dlen(osd_enc_dev));
msi_do_cmd(osd_enc_msi, MSI_CMD_OSD_ENCODE, MSI_OSD_HARDWARE_REAY_CMD, 1);
return 0;
}
static int32 osd_encode_work(struct os_work *work)
{
struct osd_encode_msi_s *osd_encode = (struct osd_encode_msi_s *)work;
struct framebuff *data_s = NULL;
// static int osd_encode_count = 0;
static uint32_t osd_send_times = 0;
// 先检测一下解码模块是否可用
if (osd_encode->hardware_ready)
{
// 检测一下是否有data_s需要先发送出去
if (osd_encode->parent_data_s)
{
// 获取data_s,申请空间,发送数据
data_s = fbpool_get(&osd_encode->tx_pool, 0, osd_encode->msi);
if (data_s)
{
data_s->mtype = F_ERGB; //设置为已经压缩的RGB
data_s->stype = osd_encode->parent_data_s->stype; //子类保持与接收一致
msi_delete_fb(NULL, 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)
{
// 先清除cache
sys_dcache_invalid_range((uint32_t *)data_s->data, osd_encode->data_len);
// 拷贝数据
hw_memcpy_no_cache(data_s->data, (const void *)msi_do_cmd(osd_encode->msi, MSI_CMD_OSD_ENCODE, MSI_OSD_HARDWARE_ENCODE_BUF, 0), (uint32_t)osd_encode->data_len);
//sys_dcache_clean_range((uint32_t *)data_s->data, osd_encode->data_len);
// 数据类型保持一致
data_s->len = osd_encode->data_len;
data_s->time = os_jiffies();
// os_printf("osd encode after len:%d\n",data_s->len);
// os_printf("encode spend time:%d\n",(uint32_t)os_jiffies()-osd_encode->start_time);
msi_output_fb(osd_encode->msi, data_s);
//os_printf("success:%d\n",success);
osd_send_times++;
}
// 没有发送成功,则释放data_s先吧,下一次再发送
else
{
msi_delete_fb(osd_encode->msi, data_s);
_os_printf("**********************");
}
data_s = NULL;
}
}
// 重新检测一下,parent_data_s是否还存在,不存在就去看看是否有需要压缩的osd
// 会进入中断
if (!osd_encode->parent_data_s)
{
osd_encode->parent_data_s = msi_get_fb(osd_encode->msi, 0);
if (osd_encode->parent_data_s)
{
// 判断一下osd_tmp_buf_size是否足够,如果足够就不需要重新申请空间,否则重新申请一下空间
if (osd_encode->osd_tmp_buf_size < osd_encode->parent_data_s->len)
{
// 释放原来空间
if (osd_encode->osd_tmp_buf)
{
STREAM_FREE(osd_encode->osd_tmp_buf);
}
// 重新申请一下空间
osd_encode->osd_tmp_buf = (uint8_t *)STREAM_MALLOC(osd_encode->parent_data_s->len);
// 申请失败,不压缩了,丢弃
if (!osd_encode->osd_tmp_buf)
{
osd_encode->osd_tmp_buf_size = 0;
msi_delete_fb(NULL, osd_encode->parent_data_s);
osd_encode->parent_data_s = NULL;
goto osd_encode_work_end;
}
osd_encode->osd_tmp_buf_size = osd_encode->parent_data_s->len;
// 先清除cache
sys_dcache_invalid_range((uint32_t *)osd_encode->osd_tmp_buf, osd_encode->osd_tmp_buf_size);
}
// 硬件模块开始被使用,标志置一下
msi_do_cmd(osd_encode->msi, MSI_CMD_OSD_ENCODE, MSI_OSD_HARDWARE_REAY_CMD, 0);
// 去压缩
osd_enc_addr(osd_encode->osd_enc_dev, (uint32)osd_encode->parent_data_s->data, (uint32)msi_do_cmd(osd_encode->msi, MSI_CMD_OSD_ENCODE, MSI_OSD_HARDWARE_ENCODE_BUF, 0));
osd_enc_src_len(osd_encode->osd_enc_dev, osd_encode->osd_tmp_buf_size);
osd_encode->start_time = os_jiffies();
osd_enc_run(osd_encode->osd_enc_dev);
}
}
}
osd_encode_work_end:
os_run_work_delay(work, 1);
return 0;
}
static int32 osd_encode_msi_action(struct msi *msi, uint32 cmd_id, uint32 param1, uint32 param2)
{
int32_t ret = RET_OK;
struct osd_encode_msi_s *osd_encode = (struct osd_encode_msi_s *)msi->priv;
uint32_t arg = param2;
switch (cmd_id)
{
case MSI_CMD_PRE_DESTROY:
{
os_work_cancle2(&osd_encode->work, 1);
// lcdc_osd_enc_start_run(osd_encode->osd_enc_dev, 0);
// 释放资源空间
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;
}
// 将缓冲区的fb释放
struct framebuff *fb;
while (1)
{
fb = msi_get_fb(osd_encode->msi, 0);
if (fb)
{
msi_delete_fb(NULL, fb);
}
else
{
break;
}
}
if (osd_encode->parent_data_s)
{
msi_delete_fb(NULL, osd_encode->parent_data_s);
osd_encode->parent_data_s = NULL;
}
// 由于tx_pool的fb没有特殊空间,直接释放就好了
fbpool_destroy(&osd_encode->tx_pool);
break;
}
// 暂时没有考虑释放
case MSI_CMD_POST_DESTROY:
{
STREAM_LIBC_FREE(osd_encode);
}
break;
// 接收,判断是类型是否可以支持压缩,暂时默认全部接收
case MSI_CMD_TRANS_FB:
{
struct framebuff *fb = (struct framebuff *)param1;
if(fb->mtype != F_RGB || fb->srcID != FRAMEBUFF_SOURCE_OSD_ENC)
{
ret = RET_ERR;
}
}
break;
case MSI_CMD_FREE_FB:
{
struct framebuff *fb = (struct framebuff *)param1;
if (fb->data)
{
STREAM_FREE(fb->data);
fb->data = NULL;
}
fbpool_put(&osd_encode->tx_pool, fb);
ret = RET_OK + 1;
}
break;
case MSI_CMD_OSD_ENCODE:
{
uint32_t cmd_self = (uint32_t)param1;
switch (cmd_self)
{
case MSI_OSD_HARDWARE_REAY_CMD:
osd_encode->hardware_ready = arg;
break;
case MSI_OSD_HARDWARE_ENCODE_SET_LEN:
osd_encode->data_len = arg;
break;
case MSI_OSD_HARDWARE_ENCODE_GET_LEN:
ret = osd_encode->data_len;
break;
case MSI_OSD_HARDWARE_ENCODE_BUF:
ret = (uint32_t)osd_encode->osd_tmp_buf;
break;
case MSI_OSD_HARDWARE_DEV:
ret = (uint32_t)osd_encode->osd_enc_dev;
break;
case MSI_OSD_HARDWARE_STREAM_RESET:
{
// 硬件模块可用
osd_encode->hardware_ready = 1;
OS_WORK_REINIT(&osd_encode->work);
os_run_work(&osd_encode->work);
}
break;
case MSI_OSD_HARDWARE_STREAM_STOP:
// 停止硬件模块
// lcdc_osd_enc_start_run(osd_encode->osd_enc_dev, 0);
// workqueue停止
os_work_cancle2(&osd_encode->work, 1);
break;
case MSI_OSD_ENC_MSI_ENABLE:
osd_encode->msi->enable = arg;
break;
}
}
break;
default:
break;
}
return ret;
}
// osd压缩是一个模块,所以在这里统一管理自己的模块,所有需要压缩的数据都到这里,然后再发出去
// 然后类型可以跟着父流一致
// 要预先申请一个空间给到osd压缩,最后再读取寄存器看看要拷贝多少压缩的数据
// 所以空间是:w*h*2+压缩的size,压缩的size根据不同ui去压缩的,一般不会超过原来的size
struct msi *osd_encode_msi_init(const char *name)
{
struct msi *msi = msi_new(name, MAX_OSD_ENCODE_RX, NULL); //R_OSD_ENCODE
struct osd_encode_msi_s *osd_encode = (struct osd_encode_msi_s *)msi->priv;
if (!osd_encode)
{
osd_encode = (struct osd_encode_msi_s *)STREAM_LIBC_ZALLOC(sizeof(struct osd_encode_msi_s));
msi->priv = (void *)osd_encode;
osd_encode->msi = msi;
fbpool_init(&osd_encode->tx_pool, MAX_OSD_ENCODE_TX);
osd_encode->osd_enc_dev = (struct osdenc_device *)dev_get(HG_OSD_ENC_DEVID);
osd_encode->hardware_ready = 1;
osd_encode->osd_tmp_buf_size = 0;
osd_encode->osd_tmp_buf = NULL;
msi->action = osd_encode_msi_action;
msi->enable = 1;
msi_add_output(osd_encode->msi, NULL, R_LCD_OSD);
osd_enc_open(osd_encode->osd_enc_dev);
osd_enc_tran_config(osd_encode->osd_enc_dev, 0xFFFFFF, 0xFFFFFF, 0x000000, 0x000000);
osd_enc_set_format(osd_encode->osd_enc_dev, 1);
osd_enc_request_irq(osd_encode->osd_enc_dev, ENC_DONE_IRQ, osd_enc_isr_msi, (uint32)osd_encode);
OS_WORK_INIT(&osd_encode->work, osd_encode_work, 0);
os_run_work_delay(&osd_encode->work, 1);
}
return msi;
}

View File

@@ -0,0 +1,553 @@
/**********************************************************************************************************
* 虚拟屏幕,支持更多的屏,顶层序号大,底层序号低
* ********************************************************************************************************/
#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"
#include "app_lcd/app_lcd.h"
#include "user_work/user_work.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);
extern void yuv_blk_reduce(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
#define MAX_TX 2
struct window_msg{
uint16_t w;
uint16_t h;
uint16_t x;
uint16_t y;
};
struct sim_video_more_msi_s
{
struct os_work work;
struct msi *msi;
struct fbpool tx_pool;
uint16_t w, h;
uint16_t *filter; // 数组去进行过滤,0为结束
struct framebuff **screen; // 不同屏幕的framebuff,屏幕数量与filter数量一致
uint16_t screen_num;
uint32_t bufadr[MAX_TX];
struct framebuff *last_fb;
struct framebuff *last_input_fb;
uint32_t subwindow_cnt[10]; //本地buf所记录的cnt
uint32_t dispwindow_cnt[10]; //显示的buf所记录的cnt
struct window_msg dsp_window_msg[10];
uint8_t video_display_mask[10]; //记录哪个界面打开了独显,正常只可能有一个设备配置上,或者没人配置上
uint8_t lcd_fb_updata;
};
//只做双层
static int32 sim_video_more_work(struct os_work *work)
{
struct sim_video_more_msi_s *sim_video = (struct sim_video_more_msi_s *)work;
struct framebuff *fb;
struct framebuff *output_fb;
uint32_t dispbuf;
fb = msi_get_fb(sim_video->msi, 0);
// 接收到一个fb,就需要判断类型(p0,p1),然后申请空间去进行叠层
if (fb)
{
// 查看类型是否匹配(正常到这里一定匹配,因为接收的时候就进行过滤了)
uint16_t match_count = 0;
uint8_t match_flag = 0;
while (match_count < sim_video->screen_num)
{
if (fb->stype == sim_video->filter[match_count]) //类型检查看一下当前的fb类型是否存在于过滤网内
{
if (sim_video->screen[match_count]) //检查当前的screen是否存在如果存在则删除更新新的fb到screen
{
msi_delete_fb(NULL, sim_video->screen[match_count]);
}
sim_video->screen[match_count] = fb;
match_flag = 1;
break;
}
match_count++;
}
// 没有匹配,删除,并且不需要刷新
if (!match_flag)
{
msi_delete_fb(NULL, fb);
fb = NULL;
goto sim_video_work_end;
}
output_fb = fbpool_get(&sim_video->tx_pool, 0, sim_video->msi); //从sim_video的发送池里找到对应的fb
if (!output_fb)
{
goto sim_video_work_end;
}
if((uint32_t)output_fb->data == sim_video->bufadr[0]){
dispbuf = sim_video->bufadr[1]; //提取当前正在显示的buf地址,用来拷数据
}else{
dispbuf = sim_video->bufadr[0];
}
// 这个模式是默认都是叠层,不再判断有某些情况不需要叠层的情况(效率低,但是既然应用设定多个屏幕,就应该去实现吧)
// 叠层
{
// 开始尝试叠层
uint16_t tmp = 0;
uint16_t p_w, p_h;
struct yuv_arg_s *yuv_msg = NULL;
while (tmp < sim_video->screen_num)
{
if (sim_video->screen[tmp])
{
yuv_msg = (struct yuv_arg_s *)sim_video->screen[tmp]->priv;
p_w = yuv_msg->out_w;
p_h = yuv_msg->out_h;
yuv_blk_cpy((uint8_t*)output_fb->data, sim_video->screen[tmp]->data, sim_video->w, sim_video->h, p_w, p_h, yuv_msg->x, yuv_msg->y);
}
tmp++;
}
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 int32 sim_video_more_work_more(struct os_work *work)
{
#define REFRESH_LCD_INTERNAL_TIME 10
struct sim_video_more_msi_s *sim_video = (struct sim_video_more_msi_s *)work;
struct framebuff *fb;
struct framebuff *output_fb;
static uint16_t oldbigx,oldbigy;
uint32_t dispbuf;
uint32_t *cache_buf[10];
uint8_t push_lcd_updata=0;
uint8_t display_only = 0;
uint16_t p_w, p_h;
uint16_t max_w;
uint16_t tmp = 0;
struct yuv_arg_s *yuv_msg = NULL;
struct app_lcd_s *lcd_s = &lcd_msg_s;
output_fb = NULL;
if(sim_video->last_input_fb != NULL){
fb = sim_video->last_input_fb;
}else{
fb = msi_get_fb(sim_video->msi, 0);
}
// 接收到一个fb,就需要判断类型(p0,p1),然后申请空间去进行叠层
if (fb)
{
// 查看类型是否匹配(正常到这里一定匹配,因为接收的时候就进行过滤了)
uint16_t match_count = 0;
uint8_t match_flag = 0;
while (match_count < sim_video->screen_num)
{
if (fb->stype == sim_video->filter[match_count]) //类型检查看一下当前的fb类型是否存在于过滤网内
{
yuv_msg = (struct yuv_arg_s *)fb->priv;
if(sim_video->subwindow_cnt[match_count] != sim_video->dispwindow_cnt[match_count]){ //重复更新,当前要刷的叠层已在备刷区,但又来了新的数据,那要把备刷区推出去
push_lcd_updata = 1;
sim_video->last_input_fb = fb;
output_fb = sim_video->last_fb;
goto sim_video_push_lcd;
}
match_flag = 1;
break;
}
match_count++;
}
// 没有匹配,删除,并且不需要刷新
if (!match_flag)
{
msi_delete_fb(NULL, fb);
if(fb == sim_video->last_input_fb) {
sim_video->last_input_fb = NULL;
}
fb = NULL;
goto sim_video_work_end;
}
if(sim_video->lcd_fb_updata){
sim_video->lcd_fb_updata = 0;
sim_video->last_input_fb = fb;
output_fb = fbpool_get(&sim_video->tx_pool, 0, sim_video->msi); //从sim_video的发送池里找到对应的fb
if(!output_fb){ //需要更新时无法申请到fb,则下次重新申请,直到能申请为止
sim_video->lcd_fb_updata = 1;
goto sim_video_work_end;
}else{ //申请到了表示当前input_fb可被处理掉指针清空一下
if((uint32_t)output_fb->data == sim_video->bufadr[0]){
dispbuf = sim_video->bufadr[1]; //提取当前正在显示的buf地址,用来拷数据
}else{
dispbuf = sim_video->bufadr[0];
}
//hw_memcpy(output_fb->data,dispbuf,output_fb->len);
yuv_blk_cpy((uint8_t*)output_fb->data, (uint8_t*)dispbuf, sim_video->w, sim_video->h, sim_video->w,sim_video->h, 0,0);
sim_video->last_input_fb = NULL;
}
}
if (!output_fb)
{
output_fb = sim_video->last_fb;
}else{
sim_video->last_fb = output_fb; //记录当前要修改的fb
}
sim_video->subwindow_cnt[match_count] = yuv_msg->dispcnt;
sim_video->dsp_window_msg[match_count].w = yuv_msg->out_w;
sim_video->dsp_window_msg[match_count].h = yuv_msg->out_h;
sim_video->dsp_window_msg[match_count].x = yuv_msg->x;
sim_video->dsp_window_msg[match_count].y = yuv_msg->y;
sim_video->video_display_mask[match_count] = yuv_msg->video_only;
if((uint32_t)output_fb->data == sim_video->bufadr[0]){
dispbuf = sim_video->bufadr[1]; //提取当前正在显示的buf地址,用来拷数据
}else{
dispbuf = sim_video->bufadr[0];
}
display_only = 0;
tmp = 0;
while (tmp < sim_video->screen_num) { //选出是否配置独显了
if(sim_video->video_display_mask[tmp] != 0){
if(yuv_msg->video_only){ //当前数据流是否就是要显示的数据流
display_only |= BIT(7);
}
display_only++;
}
tmp++;
}
if((display_only&0x7f) > 1){
_os_printf("too much stream set display only mode\r\n");
}
max_w = 0;
tmp = 0;
while (tmp < sim_video->screen_num) { //选出最大的图片
if(sim_video->dsp_window_msg[tmp].w > max_w){
max_w = sim_video->dsp_window_msg[tmp].w;
}
tmp++;
}
yuv_msg = (struct yuv_arg_s *)fb->priv;
p_w = yuv_msg->out_w;
p_h = yuv_msg->out_h;
if(display_only){ //有设备打开了独显
if((display_only&BIT(7)) == BIT(7)){
hw_memset((uint8_t*)output_fb->data, 0, sim_video->w * sim_video->h); //清黑屏
hw_memset((uint8_t*)output_fb->data + sim_video->w * sim_video->h, 0x80, sim_video->w * sim_video->h / 2);
yuv_blk_cpy((uint8_t*)output_fb->data, fb->data, sim_video->w, sim_video->h, p_w, p_h, yuv_msg->x, yuv_msg->y); //把大图拷好
}
}
else
{
if(max_w != yuv_msg->out_w){ //如果并非大图
yuv_blk_cpy((uint8_t*)output_fb->data, fb->data, sim_video->w, sim_video->h, p_w, p_h, yuv_msg->x, yuv_msg->y); //拷到对应的位置上
}else{ //如果是大图
tmp = 0;
while(tmp < sim_video->screen_num){
cache_buf[tmp] = NULL;
if( (match_count != tmp) && (sim_video->dsp_window_msg[tmp].w != 0)){
if(sim_video->subwindow_cnt[tmp] > sim_video->dispwindow_cnt[tmp]){ //如果备用区数值是更新的,那就拷出来
cache_buf[tmp] = (uint32_t *)STREAM_MALLOC(sim_video->dsp_window_msg[tmp].w * sim_video->dsp_window_msg[tmp].h * 3 / 2); //申请小图空间
sys_dcache_invalid_range(cache_buf[tmp], sim_video->dsp_window_msg[tmp].w * sim_video->dsp_window_msg[tmp].h * 3 / 2);
if(cache_buf[tmp] != NULL){
yuv_blk_reduce((uint8_t*)cache_buf[tmp],(uint8_t*)output_fb->data,sim_video->dsp_window_msg[tmp].w,sim_video->dsp_window_msg[tmp].h,sim_video->w,sim_video->h,sim_video->dsp_window_msg[tmp].x,sim_video->dsp_window_msg[tmp].y);
}else{
_os_printf("malloc psram for sim video error1\r\n");
}
}
}
tmp++;
}
if((oldbigx != yuv_msg->x) || (oldbigy != yuv_msg->y)){
hw_memset((uint8_t*)output_fb->data, 0, sim_video->w * sim_video->h); //大图产生偏移,清黑屏
hw_memset((uint8_t*)output_fb->data + sim_video->w * sim_video->h, 0x80, sim_video->w * sim_video->h / 2);
}
yuv_blk_cpy((uint8_t*)output_fb->data, fb->data, sim_video->w, sim_video->h, p_w, p_h, yuv_msg->x, yuv_msg->y); //把大图拷好
oldbigx = yuv_msg->x;
oldbigy = yuv_msg->y;
tmp = 0;
while(tmp < sim_video->screen_num){
if( (match_count != tmp) && (sim_video->dsp_window_msg[tmp].w != 0)){
if(cache_buf[tmp]){ //图片是从之前的备用区提取出来的,在缓存中
yuv_blk_cpy((uint8_t*)output_fb->data, (uint8_t*)cache_buf[tmp], sim_video->w, sim_video->h, sim_video->dsp_window_msg[tmp].w,sim_video->dsp_window_msg[tmp].h, sim_video->dsp_window_msg[tmp].x,sim_video->dsp_window_msg[tmp].y); //拷到对应的psram块中
STREAM_FREE((uint8_t*)cache_buf[tmp]);
}
else{ //图片得从刷新区那里提取
cache_buf[tmp] = (uint32_t *)STREAM_MALLOC(sim_video->dsp_window_msg[tmp].w * sim_video->dsp_window_msg[tmp].h * 3 / 2);
sys_dcache_invalid_range(cache_buf[tmp],sim_video->dsp_window_msg[tmp].w * sim_video->dsp_window_msg[tmp].h * 3 / 2);
if(cache_buf[tmp] != NULL){
yuv_blk_reduce((uint8_t*)cache_buf[tmp],(uint8_t*)dispbuf,sim_video->dsp_window_msg[tmp].w,sim_video->dsp_window_msg[tmp].h,sim_video->w,sim_video->h,sim_video->dsp_window_msg[tmp].x,sim_video->dsp_window_msg[tmp].y);
yuv_blk_cpy((uint8_t*)output_fb->data, (uint8_t*)cache_buf[tmp], sim_video->w, sim_video->h, sim_video->dsp_window_msg[tmp].w,sim_video->dsp_window_msg[tmp].h, sim_video->dsp_window_msg[tmp].x,sim_video->dsp_window_msg[tmp].y);
STREAM_FREE((uint8_t*)cache_buf[tmp]);
}else{
_os_printf("malloc psram for sim video error2\r\n");
}
}
}
tmp++;
}
}
}
sim_video_push_lcd:
if(push_lcd_updata == 1){
memcpy(sim_video->dispwindow_cnt,sim_video->subwindow_cnt,10*4);
output_fb->mtype = F_YUV;
output_fb->stype = FSTYPE_YUV_P0;
msi_output_fb(sim_video->msi, output_fb); //将当前推屏的fb推出去
sim_video->lcd_fb_updata = 1; //下次提取新的刷屏帧
sim_video->last_fb = NULL;
}else{
msi_delete_fb(NULL, fb); //删除对应的输入到msi video的fb
fb = NULL;
}
}
sim_video_work_end:
if((os_jiffies() - lcd_s->start_time) > (lcd_s->refresh_time - REFRESH_LCD_INTERNAL_TIME)){ //当距离结束刷屏时间为REFRESH_LCD_INTERNAL_TIME时检查是否需要更新需要的话就先更新
if(output_fb){ //先检查推屏的fb是否存在
tmp = 0;
while(tmp < sim_video->screen_num){ //检查各个叠层
if(sim_video->dispwindow_cnt[tmp] != sim_video->subwindow_cnt[tmp]){ //发现有叠层出现更新了
memcpy(sim_video->dispwindow_cnt,sim_video->subwindow_cnt,10*4);
output_fb->mtype = F_YUV;
output_fb->stype = FSTYPE_YUV_P0;
msi_output_fb(sim_video->msi, output_fb); //将当前推屏的fb推出去
sim_video->lcd_fb_updata = 1; //下次提取新的刷屏帧
sim_video->last_fb = NULL;
break;
}
tmp++;
}
}
}
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_more_msi_s *sim_video = (struct sim_video_more_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->data)
{
STREAM_FREE(fb->data);
fb->data = NULL;
}
// 预分配空间释放
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);
uint16_t tmp = 0;
while (tmp < sim_video->screen_num)
{
if (sim_video->screen[tmp])
{
msi_delete_fb(NULL, sim_video->screen[tmp]);
}
tmp++;
}
while (1)
{
struct framebuff *fb = msi_get_fb(msi, 0);
if (fb) {
msi_delete_fb(NULL, fb);
} else {
break;
}
}
if (sim_video->last_fb){
msi_delete_fb(NULL, sim_video->last_fb);
sim_video->last_fb = NULL;
}
if(sim_video->last_input_fb){
msi_delete_fb(NULL, sim_video->last_input_fb);
sim_video->last_input_fb = NULL;
}
}
break;
default:
{
}
break;
}
return ret;
}
struct msi *sim_video_more_msi(const char *name, uint16_t w, uint16_t h, uint16_t *sim_filter)
{
// 设置1个接收,只是为了可以output_fb给到这个msi
uint16_t count = 0;
uint32_t *buf;
struct msi *msi = msi_new(name, MAX_RX, NULL);
if (msi)
{
struct sim_video_more_msi_s *sim_video = (struct sim_video_more_msi_s *)msi->priv;
if (!sim_video)
{
// 统计sim_filter数量来决定screen的数量
while (*(sim_filter + count))
{
count++;
}
sim_video = (struct sim_video_more_msi_s *)STREAM_LIBC_ZALLOC(sizeof(struct sim_video_more_msi_s) + (sizeof(struct framebuff *) * count));
}
sim_video->w = w;
sim_video->h = h;
sim_video->msi = msi;
sim_video->filter = sim_filter;
sim_video->screen_num = count;
// 申请空间的时候就已经多申请了,所有screen放在末尾
sim_video->screen = (struct framebuff **)(sim_video + 1);
sim_video->lcd_fb_updata = 1;
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_TX);
while (init_count < MAX_TX)
{
priv = (void *)STREAM_LIBC_ZALLOC(sizeof(struct yuv_arg_s));
struct yuv_arg_s *yuv_msg = (struct yuv_arg_s *)priv;
buf = (uint32_t *)STREAM_MALLOC(sim_video->w * sim_video->h * 3 / 2);
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); //清cache
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;
sim_video->bufadr[init_count] = (uint32_t)buf;
FBPOOL_SET_INFO(&sim_video->tx_pool, init_count, (uint8_t*)buf, sim_video->w * sim_video->h * 3 / 2, priv);
init_count++;
}
msi->enable = 1;
// msi_add_output(sim_video->msi, NULL, R_VIDEO_P0);
OS_WORK_INIT(&sim_video->work, sim_video_more_work_more, 0);
os_run_work_delay(&sim_video->work, 1);
}
return msi;
}

View File

@@ -0,0 +1,316 @@
/**********************************************************************************************************
* 虚拟的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;
}