diff --git a/bk.jpg b/bk.jpg new file mode 100644 index 0000000..db4310c Binary files /dev/null and b/bk.jpg differ diff --git a/src/display/fbdev.c b/src/display/fbdev.c index 13f0cd7..6dad7b7 100644 --- a/src/display/fbdev.c +++ b/src/display/fbdev.c @@ -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(); diff --git a/src/display/fbdev_10xd.c b/src/display/fbdev_10xd.c index 9b1734a..924d35e 100644 --- a/src/display/fbdev_10xd.c +++ b/src/display/fbdev_10xd.c @@ -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 diff --git a/src/e_logger.c b/src/e_logger.c index edc1375..b9548af 100644 --- a/src/e_logger.c +++ b/src/e_logger.c @@ -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(); } // 检查日志级别是否足够 diff --git a/src/main.c b/src/main.c index f41df6a..5eac163 100755 --- a/src/main.c +++ b/src/main.c @@ -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("启动主循环---------<<<"); diff --git a/tag.png b/tag.png new file mode 100644 index 0000000..9f34c2b Binary files /dev/null and b/tag.png differ