功能: FB+视频共存 - bk背景+tag叠加+视频挖洞

This commit is contained in:
zzh 2026-02-12 14:34:25 +08:00
parent b4d8f49143
commit 65e29b91e4
6 changed files with 84 additions and 54 deletions

BIN
bk.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 KiB

View File

@ -71,8 +71,15 @@ void fbdev_exit(void)
void *fbdev_req_mem(int size)
{
(void)size;
return lvgl_surface.data;
void *buf = NULL;
int ret = posix_memalign(&buf, 64, size);
if (ret != 0 || buf == NULL)
{
printf("fbdev_req_mem malloc failed: ret=%d\n", ret);
return NULL;
}
memset(buf, 0, size);
return buf;
}
int fbdev_get_actual_height(void)
@ -133,6 +140,8 @@ static void fbdev_draw_hole()
void fbdev_flush(lv_display_t *drv, const lv_area_t *area, uint8_t *color_p)
{
static int flush_cnt = 0;
if (flush_cnt < 3) { printf("[fbdev_flush] #%d area=[%d,%d,%d,%d]\n", flush_cnt, area->x1, area->y1, area->x2, area->y2); fflush(stdout); flush_cnt++; }
if (fbp == NULL || finfo.line_length == 0)
{
lv_display_flush_ready(drv);
@ -148,38 +157,8 @@ void fbdev_flush(lv_display_t *drv, const lv_area_t *area, uint8_t *color_p)
return;
}
/* lvgl_surface == fb_surface (same mmap buffer), LVGL writes directly to it.
* qua_gl_transform with same src/dst triggers hardware compress pipeline. */
int32_t act_x1 = LV_MAX(area->x1, 0);
int32_t act_y1 = LV_MAX(area->y1, 0);
int32_t act_x2 = LV_MIN(area->x2, (int32_t)lvgl_surface.width - 1);
int32_t act_y2 = LV_MIN(area->y2, (int32_t)lvgl_surface.height - 1);
int32_t w = act_x2 - act_x1 + 1;
int32_t h = act_y2 - act_y1 + 1;
lvgl_surface.crop_x = act_x1;
lvgl_surface.crop_y = act_y1;
lvgl_surface.crop_w = w;
lvgl_surface.crop_h = h;
fb_surface.crop_x = act_x1;
fb_surface.crop_y = act_y1;
fb_surface.crop_w = w;
fb_surface.crop_h = h;
qua_gl_transform_t trans = {};
trans.conversion = 1;
qua_gl_transform(&trans, &lvgl_surface, &fb_surface);
lvgl_surface.crop_x = 0;
lvgl_surface.crop_y = 0;
lvgl_surface.crop_w = lvgl_surface.width;
lvgl_surface.crop_h = lvgl_surface.height;
fb_surface.crop_x = 0;
fb_surface.crop_y = 0;
fb_surface.crop_w = fb_surface.width;
fb_surface.crop_h = fb_surface.height;
/* Skip memcpy: FB buffer already has pre-loaded image (tag.rgba).
* Only do hole drawing + render on last flush. */
if (lv_display_flush_is_last(drv))
{
fbdev_draw_hole();

View File

@ -25,6 +25,9 @@
#include "bootanimation/qua_bootanimation.h"
#define DISPLAY_ID "id:display0"
#define BK_IMAGE_PATH "/usrdata/pic/bk.rgba"
#define TAG_IMAGE_PATH "/usrdata/pic/tag.rgba"
#define TAG_Y_OFFSET 640
static QUA_CHAR *pShowScreen;
static QUA_U32 u32PhyAddrScreen;
@ -160,6 +163,56 @@ static QUA_S32 init_fyfb()
goto map_failed;
}
memset(pShowScreen, 0x00, finfo.smem_len);
/* Step 1: load bk.rgba as full-screen background */
{
int fb_stride = finfo.line_length;
int row_bytes = vinfo.xres * 4;
FILE *fp = fopen(BK_IMAGE_PATH, "rb");
if (fp) {
for (unsigned int y = 0; y < vinfo.yres; y++) {
if (fread(pShowScreen + y * fb_stride, 1, row_bytes, fp) <= 0) break;
}
fclose(fp);
printf("[init_fyfb] loaded %s full screen\n", BK_IMAGE_PATH);
} else {
printf("[init_fyfb] %s not found\n", BK_IMAGE_PATH);
}
/* Step 2: overlay tag.rgba at bottom (y=TAG_Y_OFFSET ~ yres) with alpha blend */
fp = fopen(TAG_IMAGE_PATH, "rb");
if (fp) {
unsigned int tag_h = vinfo.yres - TAG_Y_OFFSET;
uint8_t *row_buf = (uint8_t *)malloc(row_bytes);
if (row_buf) {
/* skip top TAG_Y_OFFSET rows of tag image */
for (unsigned int y = 0; y < (unsigned int)TAG_Y_OFFSET; y++)
if (fread(row_buf, 1, row_bytes, fp) <= 0) break;
/* blend bottom rows */
for (unsigned int y = 0; y < tag_h; y++) {
if (fread(row_buf, 1, row_bytes, fp) <= 0) break;
uint8_t *dst = (uint8_t *)(pShowScreen + (TAG_Y_OFFSET + y) * fb_stride);
uint8_t *src = row_buf;
for (unsigned int x = 0; x < vinfo.xres; x++) {
uint8_t sb = src[0], sg = src[1], sr = src[2], sa = src[3];
if (sa == 255) {
dst[0] = sb; dst[1] = sg; dst[2] = sr; dst[3] = 255;
} else if (sa > 0) {
dst[0] = (sb * sa + dst[0] * (255 - sa)) / 255;
dst[1] = (sg * sa + dst[1] * (255 - sa)) / 255;
dst[2] = (sr * sa + dst[2] * (255 - sa)) / 255;
dst[3] = 255;
}
src += 4; dst += 4;
}
}
free(row_buf);
}
fclose(fp);
printf("[init_fyfb] overlaid %s at y=%d\n", TAG_IMAGE_PATH, TAG_Y_OFFSET);
} else {
printf("[init_fyfb] %s not found\n", TAG_IMAGE_PATH);
}
}
fb_device->compress(fb_device, QUA_TRUE);
return QUA_SUCCESS;
map_failed:
@ -230,6 +283,8 @@ int fbdev_pan_disp(void)
{
qua_mm_fb_device_t *fb_dev = (qua_mm_fb_device_t *)g_fb_device;
static int is_first_frame = 1;
static int pan_cnt = 0;
if (pan_cnt < 3) { printf("[fbdev_pan_disp] called #%d first=%d fb_dev=%p\n", pan_cnt, is_first_frame, fb_dev); fflush(stdout); pan_cnt++; }
if (fb_dev == NULL)
return -1;
@ -280,8 +335,9 @@ int fbdev_pan_disp(void)
if (fb_dev->render == NULL)
return -1;
return fb_dev->render(fb_dev, &vinfo);
QUA_S32 render_ret = fb_dev->render(fb_dev, &vinfo);
return render_ret;
}
#endif

View File

@ -160,10 +160,15 @@ void log_print(LogLevel level, const char *file, int line, const char *format, .
{
pthread_mutex_lock(&log_mutex);
// 初始化检查
// 初始化检查 (inline to avoid deadlock with log_init)
if (g_output == NULL)
{
log_init();
ensure_log_dir_exists();
snprintf(g_log_file_path, sizeof(g_log_file_path), "%s/%s", LOG_DIR, LOG_FILE_NAME);
g_output = fopen(g_log_file_path, "a");
if (!g_output)
g_output = stdout;
init_udp_socket();
}
// 检查日志级别是否足够

View File

@ -99,22 +99,15 @@ int main(int argc, char **argv)
disp_handle_t disp = get_front_display();
lv_obj_t *cont_col = lv_obj_create(disp.root_obj);
lv_obj_set_size(cont_col, LV_PCT(90), 640);
lv_obj_set_pos(cont_col, 0, 640);
lv_obj_center(cont_col);
// 设置方向为垂直排列
lv_obj_set_flex_flow(cont_col, LV_FLEX_FLOW_COLUMN);
// 对齐方式
lv_obj_set_flex_align(cont_col, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
lv_obj_set_style_bg_color(cont_col, lv_color_hex(0xffffff), LV_PART_MAIN);
/* make LVGL root transparent so FB image (tag.rgba) shows through */
lv_obj_set_style_bg_opa(disp.root_obj, LV_OPA_TRANSP, LV_PART_MAIN);
//创建视频播放器
VideoPlayer *video_player=video_player_init(0);
e_player_area area={0};
area.x = 0;
area.y = 640;
area.y = 0;
area.width = 800;
area.height = 640;
@ -128,12 +121,12 @@ int main(int argc, char **argv)
}
memset(media_path, 0, sizeof(MediaPath));
safe_strcpy(media_path->path, "/usrdata/downloads/xxx.mp4", MAX_URL_LEN);
safe_strcpy(media_path->path, "/usrdata/downloads/lemon.MOV", MAX_URL_LEN);
safe_strcpy(media_path->item_id, "", MAX_ID_LEN);
safe_strcpy(media_path->deviceId, "700000000010", MAX_DEVICE_ID);
safe_strcpy(media_path->downloadUrl, "", MAX_URL_LEN);
safe_strcpy(media_path->file_name, "/usrdata/downloads/xxx.mp4", MAX_NAME_LEN);
safe_strcpy(media_path->file_name, "/usrdata/downloads/lemon.MOV", MAX_NAME_LEN);
media_path->type = 1; // 视频
@ -141,13 +134,10 @@ int main(int argc, char **argv)
video_player_play(video_player);
printf("启动主循环\n");
printf("[MAIN] 启动主循环\n"); fflush(stdout);
// /* 主循环 */
while (running)
{
// LOGI("启动主循环---------》》》");
// pthread_mutex_lock(&lvgl_mutex);
uint32_t wait_ms = lv_timer_handler();
// pthread_mutex_unlock(&lvgl_mutex);
// LOGI("启动主循环---------<<<");

BIN
tag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB