This commit is contained in:
zzh 2026-05-12 10:05:01 +08:00
parent c4a6e42446
commit 58ff822a9d
9 changed files with 75 additions and 101 deletions

View File

@ -1,46 +0,0 @@
# eplayer demo - FB+视频共存问题
## 问题与根因
FB 和视频无法共存:`compress(TRUE)` 下 render 阻塞,`compress(FALSE)` 下视频返回 VO_BUSY。
根因: `rootfs_overlay/qua/ko/loadko.sh``insmod fhfb.ko fbc=0` 禁用了 FB 压缩,且 `fhfb.ko` 是旧版不支持 fbc。
## 修改点
### 内核层
1. 替换 fhfb.ko — 用 SDK 新版替换 `rootfs_overlay/qua/ko/fhfb.ko`(旧版 md5:`96d321` → 新版 md5:`58050d`
2. loadko.sh 启用 fbc — `fbc=0``fbc=3000``vram0_size=4000``fhfb0_fbc=1`
### 应用层
3. e_logger.c — 修复 `log_print` 死锁(持有 mutex 后调用 `log_init` 再次加锁)
4. fbdev_10xd.c — `compress(TRUE)` 前加载 `bk.rgba` 全屏铺底 + `tag.rgba` 底部 alpha 叠加
5. fbdev.c — 跳过 LVGL memcpy仅做挖洞 + render
6. main.c — 视频区域改为顶部LVGL root 设为透明
## 关键时序
mmap → 写入图片 → compress(TRUE) → VO enable → show(TRUE) → render → 挖洞 → 播视频
> 图片必须在 `compress(TRUE)` 之前写入 FB buffer。
## 素材
素材需预转换PNG/JPG → raw BGRA
python3 -c "
from PIL import Image
import struct
img = Image.open('/path/to/bk1.jpg').convert('RGBA')
print(f'Size: {img.size}')
with open('/path/to/bk1.rgba', 'wb') as f:
for y in range(img.height):
for x in range(img.width):
r, g, b, a = img.getpixel((x, y))
f.write(struct.pack('BBBB', b, g, r, a))
print('Done')
"
> 设备上 crc32 与 zlib 冲突,无法用 libpng需预转换 raw 格式。

Binary file not shown.

View File

@ -91,7 +91,7 @@
#endif
#endif /*LV_USE_STDLIB_MALLOC == LV_STDLIB_BUILTIN*/
#define LV_DEF_REFR_PERIOD 33 /**< [ms] 33ms (30fps),优化后支持 tag.gif + 02.gif + 03.gif + 视频长时间稳定运行 */
#define LV_DEF_REFR_PERIOD 150 /**< [ms] 33ms (30fps),优化后支持 tag.gif + 02.gif + 03.gif + 视频长时间稳定运行 */
#define LV_DPI_DEF 130 /**< [px/inch] */

View File

@ -1 +1 @@
d7d8bda7fec96e0cb0b071e56df40841 /home/hyx/work/0212/demo/release/e_player-single-00-70-1.0.84.tar
1191545f9e16f1a3cb238f5c529dc0a7 /home/hyx/work/MC3302_push/0212/demo/release/e_player-single-00-70-1.0.84.tar

View File

@ -504,7 +504,11 @@ static int play_video(VideoPlayer *video_player, const MediaPath *media_path)
{
qua_mm_player_set_parameter(player, KEY_PARAMETER_VO_DISPLAY_ID, (QUA_VOID_PTR)video_player->display);
qua_mm_player_set_parameter(player, KEY_PARAMETER_VO_ROTATE, (QUA_VOID_PTR)&g_screen_rotation);
xos_player_set_volume(player, 0);
// 设置音频轨道类型为音乐
qua_audio_track_type_t track_type = QUA_AUDIO_TRACK_TYPE_MUSIC;
qua_mm_player_set_parameter(player, KEY_PARAMETER_AO_TRACK_TYPE, (QUA_VOID_PTR)&track_type);
xos_player_set_volume(player, 80); // 设置音量为80 (范围通常是0-100)
qua_mm_player_set_loop(player, QUA_FALSE);
video_player->player = player;
}

View File

@ -30,7 +30,7 @@ static disp_handle_t front_disp;
static disp_handle_t back_disp;
// 屏幕旋转
int g_screen_rotation = 2;
int g_screen_rotation = 0;
qua_mm_system_ops_t *g_sys_ops = NULL;
qua_mm_tde_device_t *g_tde_device_for_hole = NULL;

View File

@ -7,6 +7,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
@ -101,56 +102,72 @@ int main(int argc, char **argv)
disp_handle_t disp = get_front_display();
/* 创建 tag.gif 全屏背景动画 */
lv_obj_t *tag_gif = lv_gif_create(disp.root_obj);
lv_gif_set_src(tag_gif, "A:usrdata/pic/tag.gif");
lv_obj_set_pos(tag_gif, 0, 0); /* 全屏 */
lv_obj_set_size(tag_gif, 800, 1280);
lv_obj_clear_flag(tag_gif, LV_OBJ_FLAG_HIDDEN);
lv_gif_restart(tag_gif);
/* 创建 02.gif 小动画 - 根据旋转调整位置 */
lv_obj_t *small_gif = lv_gif_create(disp.root_obj);
lv_gif_set_src(small_gif, "A:usrdata/pic/02.gif");
// 根据屏幕旋转调整小动画位置
extern int g_screen_rotation;
int small_x, small_y;
if (g_screen_rotation == 2) {
// 180度旋转显示系统已旋转逻辑坐标需要反向
// 要显示在左上角,逻辑坐标应该是右下角
small_x = 800 - 280; // 520为280宽度留出空间
small_y = 1280 - 280; // 1000为280高度留出空间
printf("[DEBUG] Rotation 2: position (%d, %d) will display at top-left\n", small_x, small_y);
} else {
// 不旋转:右下角位置
small_x = 800 - 280 - 20; // 500右下角留20像素边距
small_y = 1280 - 280 - 20; // 980右下角留20像素边距
printf("[DEBUG] No rotation: position (%d, %d) at bottom-right\n", small_x, small_y);
}
lv_obj_set_pos(small_gif, small_x, small_y);
lv_obj_set_size(small_gif, 280, 280); // 增加尺寸到280x280
lv_obj_clear_flag(small_gif, LV_OBJ_FLAG_HIDDEN);
lv_gif_restart(small_gif);
printf("[DEBUG] GIF position: (%d, %d), size: 280x280\n", small_x, small_y);
/* 创建 bk.jpg 背景图片 */
lv_obj_t *bk_img = lv_image_create(disp.root_obj);
lv_image_set_src(bk_img, "A:data/pic/bk.jpeg");
lv_obj_set_pos(bk_img, 0, 0);
lv_obj_set_size(bk_img, 800, 1280);
lv_obj_clear_flag(bk_img, LV_OBJ_FLAG_HIDDEN);
printf("[INFO] bk.jpg loaded at (0, 0), size: 800x1280\n");
/* 创建 03.gif 在 02.gif 正上方 */
lv_obj_t *third_gif = lv_gif_create(disp.root_obj);
lv_gif_set_src(third_gif, "A:usrdata/pic/03.gif");
// 计算 03.gif 位置:在 02.gif 正上方
int third_x = small_x; // X 坐标相同
int third_y = small_y - 280 - 20; // Y 坐标在 02.gif 上方间距20像素
printf("[DEBUG] 03.gif position: (%d, %d), size: 280x280\n", third_x, third_y);
lv_obj_set_pos(third_gif, third_x, third_y);
lv_obj_set_size(third_gif, 280, 280);
lv_obj_clear_flag(third_gif, LV_OBJ_FLAG_HIDDEN);
lv_gif_restart(third_gif);
/* 创建 tag.png 图片 */
lv_obj_t *tag_img = lv_image_create(disp.root_obj);
lv_image_set_src(tag_img, "A:data/pic/tag.png");
lv_obj_set_pos(tag_img, 0, 0);
lv_obj_set_size(tag_img, 800, 1280);
lv_obj_clear_flag(tag_img, LV_OBJ_FLAG_HIDDEN);
printf("[INFO] tag.png loaded at (0, 0), size: 800x1280\n");
/* 创建底部细条状态栏 */
lv_obj_t *status_bar = lv_obj_create(disp.root_obj);
lv_obj_set_pos(status_bar, 320, 1240);
lv_obj_set_size(status_bar, 160, 24);
lv_obj_set_style_bg_color(status_bar, lv_color_make(0, 0, 0), LV_PART_MAIN);
lv_obj_set_style_bg_opa(status_bar, 100, LV_PART_MAIN);
lv_obj_set_style_border_width(status_bar, 0, LV_PART_MAIN);
lv_obj_set_style_radius(status_bar, 12, LV_PART_MAIN);
lv_obj_clear_flag(status_bar, LV_OBJ_FLAG_HIDDEN);
/* 在线状态绿点 */
lv_obj_t *online_dot = lv_obj_create(status_bar);
lv_obj_set_pos(online_dot, 10, 4);
lv_obj_set_size(online_dot, 16, 16);
lv_obj_set_style_bg_color(online_dot, lv_color_make(0, 255, 0), LV_PART_MAIN);
lv_obj_set_style_bg_opa(online_dot, 255, LV_PART_MAIN);
lv_obj_set_style_border_width(online_dot, 0, LV_PART_MAIN);
lv_obj_set_style_radius(online_dot, 8, LV_PART_MAIN);
lv_obj_clear_flag(online_dot, LV_OBJ_FLAG_HIDDEN);
/* 时间显示标签 */
lv_obj_t *time_label = lv_label_create(status_bar);
lv_obj_set_pos(time_label, 32, 2);
lv_obj_set_size(time_label, 80, 20);
lv_obj_set_style_text_color(time_label, lv_color_make(255, 255, 255), LV_PART_MAIN);
lv_obj_set_style_text_font(time_label, &lv_font_montserrat_22, LV_PART_MAIN);
lv_label_set_text(time_label, "00:00");
lv_obj_clear_flag(time_label, LV_OBJ_FLAG_HIDDEN);
/* 更新时间线程 */
pthread_t time_tid;
static volatile bool time_running = true;
void *time_update_thread(void *arg) {
(void)arg;
while (time_running) {
time_t now = time(NULL);
struct tm *tm_info = localtime(&now);
char time_str[16];
strftime(time_str, sizeof(time_str), "%H:%M", tm_info);
lv_label_set_text(time_label, time_str);
sleep(60);
}
return NULL;
}
pthread_create(&time_tid, NULL, time_update_thread, NULL);
pthread_detach(time_tid);
printf("[INFO] status bar created at bottom\n");
//创建视频播放器
VideoPlayer *video_player=video_player_init(0);
@ -162,8 +179,7 @@ int main(int argc, char **argv)
// 根据屏幕旋转调整视频区域
if (g_screen_rotation == 2) {
// 180度旋转视频应该显示在上半部分
area.y = 640; // 设置到下半部分,旋转后会显示在上半部分
area.y = 640;
}
video_player_set_size(video_player,area);
@ -176,12 +192,12 @@ int main(int argc, char **argv)
}
memset(media_path, 0, sizeof(MediaPath));
safe_strcpy(media_path->path, "/usrdata/downloads/lemon.MOV", MAX_URL_LEN);
safe_strcpy(media_path->path, "/data/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/lemon.MOV", MAX_NAME_LEN);
safe_strcpy(media_path->file_name, "/data/downloads/lemon.MOV", MAX_NAME_LEN);
media_path->type = 1; // 视频

BIN
tag.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB