ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

全志D1s Melis4.0系统下CedarX硬解码与LVGUI混合显示实践

2026/8/7 4:01:08 拓冰建站 浏览量
全志D1s Melis4.0系统下CedarX硬解码与LVGUI混合显示实践

1. 项目概述与核心价值

最近在折腾Melis4.0系统,目标平台是搭载了全志D1s芯片的开发板。这个项目听起来有点硬核,但说白了,就是想在这块资源有限的嵌入式板子上,同时干两件“吃资源”的事:流畅播放视频,并且把LVGL图形界面叠加上去,实现混合显示。这可不是简单的“能显示就行”,而是要追求流畅、稳定、不卡顿的体验。对于做智能家居中控、工业HMI或者便携式媒体设备的朋友来说,这个需求非常实在——你总不希望一个带界面的视频播放器一运行就卡成PPT吧。

D1s这颗芯片内置了CedarX多媒体硬件加速引擎,这是全志的看家本领之一。Melis4.0是全志为其自家芯片深度定制的实时操作系统,理论上对CedarX的支持应该是最原生的。而LVGL作为一款轻量级、开源且强大的嵌入式图形库,是构建现代化触控界面的首选。这个项目的核心挑战,就在于如何让硬件解码的视频流(通过CedarX)与软件渲染的LVGL界面,在同一块屏幕上和谐共处,资源共享而不冲突。成功的话,意味着你能在有限的算力下,实现更富表现力的交互产品。下面,我就把从环境搭建、库测试到混合显示实现的完整过程,以及踩过的坑和优化技巧,详细拆解一遍。

2. 系统环境搭建与源码获取

2.1 开发环境准备

工欲善其事,必先利其器。Melis4.0的开发环境有其特殊性,它基于较老的Buildroot构建,并且对主机环境有特定要求。经过实测,最稳定的方案是使用Ubuntu 18.04 LTS的64位系统。更高的版本(如20.04或22.04)可能会因为工具链或库的版本问题导致编译失败。

首先,需要安装一些基础的编译工具和依赖库:

sudo apt-get update sudo apt-get install -y git wget make gcc g++ bison flex unzip sudo apt-get install -y libncurses5-dev libssl-dev sudo apt-get install -y gcc-multilib g++-multilib

这里安装gcc-multilib是为了支持可能需要的32位库,虽然我们主要编译的是ARM架构的代码,但一些构建脚本可能会调用32位的本地工具。

2.2 获取Melis4.0 SDK

全志官方通常不会将Melis SDK完全开源到公共仓库,你需要通过特定的渠道获取,例如向芯片代理商或通过官方开发者平台申请。假设你已经拿到了SDK包,其目录结构大致如下:

melis-v4.0/ ├── e907_rtos/ # 协处理器固件 ├── lichee/ # Linux内核相关(Melis部分驱动借鉴于此) ├── melis/ # Melis系统核心源码 │ ├── source/ # 内核、组件源码 │ ├── project/ # 项目配置,D1s的配置通常在这里 │ └── ... └── tools/ # 编译工具链、打包工具等

拿到SDK后,第一件事是解压并设置环境变量。通常SDK会自带一个setup.shenvsetup.sh脚本。

cd /path/to/melis-v4.0 source setup.sh

这个脚本会设置诸如PROJECT_ROOTARCHCROSS_COMPILE(交叉编译工具链前缀)等关键环境变量。对于D1s(C906 RISC-V核心),交叉编译工具链通常是riscv64-unknown-linux-gnu-务必确认echo $CROSS_COMPILE输出正确,这是后续所有编译的基础。

2.3 配置与编译基础系统

在开始测试多媒体功能前,需要先确保一个最基础的、能启动到控制台的Melis系统镜像被正确编译出来。

cd /path/to/melis-v4.0 make menuconfig

在配置界面中,你需要:

  1. 选择正确的方案(Product):找到类似d1s_melisd1s_evb的选项。
  2. 在组件选择中,确保以下关键模块被选中:
    • Kernel->Drivers->Video and audio drivers-> 启用CedarX相关驱动。
    • Middleware-> 启用cedarx中间件库(这是应用程序调用的接口层)。
    • 为了后续测试,可以暂时在Applications中选上一个简单的命令行应用,确保系统能运行。

保存配置后,执行编译:

make -j$(nproc)

编译成功后会生成melis.binmelis.img等格式的镜像文件。使用全志的PhoenixSuit或LiveSuit工具,将其烧录到D1s开发板的SPI NAND Flash中。上电后,如果能在串口终端看到Melis的启动日志和命令行提示符,说明基础系统环境已经就绪。

注意:第一次编译可能会耗时较长,因为它会下载或编译工具链和部分依赖。确保网络通畅。如果编译失败,请首先检查环境变量和工具链路径是否正确,并查阅SDK中的READMEbuild.txt文档。

3. CedarX多媒体解码库解析与测试

3.1 CedarX架构浅析

在动手测试之前,有必要了解一下CedarX的软件架构,这能帮你更好地理解后续的测试步骤和问题排查。CedarX不是一个单一的库,而是一个软硬件结合的多媒体框架。

  • 硬件层:D1s芯片内部的视频解码硬核(VDEC)、视频编码硬核(VENC)、图像处理单元(ISP)等。
  • 内核驱动层:位于Melis内核中,以字符设备(如/dev/cedar_dev)的形式暴露硬件操作接口,负责内存管理(如VPU专用内存分配)、时钟控制、中断处理等底层硬件操作。
  • 用户空间中间件层:这就是我们常说的libcedarx.so库。它封装了底层驱动的复杂调用,向上提供统一的、易于使用的API,例如CdxPlayerCreate,CdxPlayerSetDataSource,CdxPlayerPrepare等。这一层处理了流解析、解码器调度、音视频同步等核心逻辑。
  • 应用层:我们编写的测试程序,调用libcedarx.so的API来实现播放功能。

我们的测试工作,主要聚焦在验证中间件库libcedarx.so是否被正确编译、链接,并且其功能是否正常。

3.2 编译与集成CedarX测试程序

SDK中通常会自带CedarX的测试用例,路径可能在melis/middleware/cedarx/testproject/d1s_evb/configs/application/cedarx_test。我们需要将其编译并打包进系统镜像。

  1. 定位测试代码:找到名为simple_cedarx_test.c或类似的文件。这个程序通常非常简洁,核心就是初始化CedarX、设置文件路径、开始播放、等待播放结束。

  2. 编写测试Makefile:如果测试程序没有独立的编译规则,你需要为其编写一个Makefile。关键点在于链接正确的库。

    # 示例Makefile片段 TARGET = cedarx_test SRCS = simple_cedarx_test.c OBJS = $(SRCS:.c=.o) # 使用Melis系统定义的交叉编译工具链 CC = $(CROSS_COMPILE)gcc CFLAGS = -I$(PROJECT_ROOT)/middleware/cedarx/include -I$(PROJECT_ROOT)/include LDFLAGS = -L$(PROJECT_ROOT)/middleware/cedarx/library -lcedarx -lpthread -lm all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(OBJS) -o $@ $(LDFLAGS) .c.o: $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f $(OBJS) $(TARGET)

    -lcedarx是链接多媒体库的关键。-lpthread是因为CedarX内部可能使用了多线程。

  3. 集成到系统编译体系:更规范的做法是将这个测试程序作为Melis的一个“应用组件”集成。这通常涉及在project/d1s_evb/configs/application/下创建或修改一个KconfigMakefile,将其加入make menuconfig的应用选单。对于初次测试,你可以先手动编译出可执行文件,通过ADB或TF卡拷贝到板端运行。

  4. 编译与部署:

    # 在测试程序目录下 make # 将生成的 cedarx_test 可执行文件放到板端文件系统,例如 /data 目录 # 同时准备一个测试视频文件 test.h264 也拷贝到板端

3.3 基础功能测试与问题排查

在板端执行测试程序:

cd /data ./cedarx_test test.h264

理想情况下,你应该能在屏幕上看到视频播放。但实际过程往往没那么顺利。

常见问题1:libcedarx.so未找到。

error while loading shared libraries: libcedarx.so: cannot open shared object file: No such file or directory

解决方案:这是因为动态链接器找不到库文件。你需要将libcedarx.so库放到板端文件系统的库路径下,例如/lib/usr/lib,并确保编译时LDFLAGS中的库路径是正确的。或者,在板端设置LD_LIBRARY_PATH环境变量:

export LD_LIBRARY_PATH=/data:$LD_LIBRARY_PATH ./cedarx_test test.h264

常见问题2:打开视频设备失败。

CdxPlayerCreate failed.

或者内核打印类似cedar_dev: open failed的错误。解决方案:

  • 检查驱动是否加载:在板端执行ls /dev/,查看是否存在cedar_devve之类的设备节点。如果没有,说明内核配置中CedarX驱动未启用或加载失败,需要返回make menuconfig检查驱动配置并重新编译内核。
  • 检查文件权限:确保板端上的测试用户有权限访问/dev/cedar_dev设备节点(通常是root权限)。
  • 检查视频格式:CedarX硬解码通常有明确的格式支持列表,如H.264 BP/MP/HP, H.265/HEVC, MPEG-4等。确保你的test.h264是标准的H.264 Annex B格式的裸流(无容器)。可以用PC上的FFmpeg工具转换:ffmpeg -i input.mp4 -c:v copy -an -bsf:v h264_mp4toannexb output.h264

常见问题3:播放卡顿、花屏或只有声音无图像。

  • 内存问题:CedarX解码需要连续的物理大内存(通常是VPU专用内存)。检查Melis系统配置中,为cedar模块预留的内存池大小是否足够。配置路径可能在make menuconfig->Kernel->Drivers->Video and audio drivers->Cedar memory size,一般需要设置为32M或64M。
  • 时钟问题:视频解码核心(VE)需要正确的时钟频率。检查D1s的时钟树配置,确保VE时钟源和频率设置正确。这部分配置可能在内核的设备树(dts)文件中。
  • 显示输出未配置:解码出的图像数据需要送到显示引擎(DE)才能显示。测试程序可能默认输出到某个显示层(如layer0)。你需要确保Melis的显示驱动已初始化,并且对应的显示接口(如RGB LCD)配置正确。一个简单的验证方法是:先编译一个只显示静态颜色的测试程序,看屏幕是否有输出。

实操心得:测试时,建议从最简单的、低分辨率(如480x272)、低帧率(15fps)的H.264裸流开始。同时,打开串口调试信息,关注内核printk和CedarX库自身的日志输出(有时需要通过编译选项打开调试宏,如CDX_DEBUG)。这些日志是定位问题的黄金线索。

4. LVGL图形库的移植与基础显示

4.1 LVGL在Melis上的移植要点

LVGL是一个纯C编写的库,移植性很好。在Melis上移植,核心是实现其“显示驱动”和“输入设备驱动”接口。由于我们目前只关注显示,所以先实现显示驱动。

  1. 获取LVGL源码:从LVGL官方GitHub仓库下载稳定版本(如v8.3.x)。将其放入Melis SDK的第三方库目录,例如melis/thirdparty/lvgl

  2. 实现lv_port_disp.c这是移植的关键文件。你需要在这个文件中实现一个函数,将LVGL的内部绘图缓冲区(draw_buf)的内容,搬运到实际的显示帧缓冲区(Framebuffer)中。

    • 帧缓冲区获取:Melis可能提供了Framebuffer驱动(如/dev/fb0)。你需要通过openmmap系统调用,将显存映射到用户空间。或者,Melis的显示驱动可能提供了直接分配图形层(G2D)缓冲区的API,这种方式性能更好。
    • 刷新函数disp_flush这是LVGL回调的核心。当LVGL完成一个区域的绘制后,会调用此函数,并传递需要更新的区域坐标和像素数据。你的任务就是将这个矩形区域的像素数据,拷贝到帧缓冲区的对应位置。
    // lv_port_disp.c 简化示例 static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { // 1. 将 color_p 中的数据拷贝到 frame_buffer 的指定区域 (area->x1, area->y1) 到 (area->x2, area->y2) int32_t x, y; for(y = area->y1; y <= area->y2; y++) { lv_color_t *fb_line = &frame_buffer[y * screen_width + area->x1]; lv_color_t *lv_line = &color_p[(y - area->y1) * lv_area_get_width(area)]; memcpy(fb_line, lv_line, lv_area_get_width(area) * sizeof(lv_color_t)); } // 2. 通知LVGL刷新完成 lv_disp_flush_ready(disp_drv); }
    • 颜色格式转换:LVGL默认使用LV_COLOR_DEPTH_16(RGB565)或LV_COLOR_DEPTH_32(ARGB8888)。你的显示设备可能支持不同的格式。如果格式不一致,需要在拷贝时进行转换,或者配置LVGL使用与硬件一致的格式。
  3. 配置与初始化:在系统启动的某个阶段(例如应用主函数中),初始化LVGL,并注册你实现的显示驱动。

    lv_init(); lv_disp_draw_buf_init(&draw_buf, buf1, buf2, screen_width * 10); // 双缓冲 lv_disp_drv_init(&disp_drv); disp_drv.draw_buf = &draw_buf; disp_drv.flush_cb = disp_flush; disp_drv.hor_res = screen_width; disp_drv.ver_res = screen_height; lv_disp_drv_register(&disp_drv);

4.2 创建简单的LVGL界面进行验证

移植完成后,编写一个简单的测试程序来验证LVGL能否正常工作。

void lvgl_test_task(void) { // 创建一个按钮 lv_obj_t * btn = lv_btn_create(lv_scr_act()); lv_obj_set_size(btn, 100, 50); lv_obj_center(btn); // 给按钮加个标签 lv_obj_t * label = lv_label_create(btn); lv_label_set_text(label, "Hello Melis!"); lv_obj_center(label); // 创建定时器,周期性调用 lv_timer_handler while(1) { lv_timer_handler(); usleep(5000); // LVGL推荐5ms左右调用一次 } }

将这个任务作为一个独立的线程启动。如果一切正常,你应该能在屏幕上看到一个居中的按钮,上面写着“Hello Melis!”。这证明了LVGL的图形渲染通路是通的。

注意事项:lv_timer_handler()必须在主循环或一个独立的任务中周期性调用,它负责处理LVGL的内部定时器、动画和屏幕刷新事件。调用间隔太大会导致界面卡顿,太小会浪费CPU。5-10ms是一个常见的经验值。另外,确保LVGL相关的操作(对象创建、属性设置等)都在同一个线程中执行,避免多线程竞争。

5. 视频与LVGL混合显示的核心实现

这是本项目最核心、最具挑战性的部分。目标是将CedarX解码出的视频画面,与LVGL渲染的UI界面,叠加显示在同一屏幕上。这里提供两种主流且可行的架构方案。

5.1 方案一:多层显示(硬件混合)架构

这是性能最优的方案,利用了D1s显示控制器(DE)的硬件多层混合功能。D1s的DE通常支持多个图形层(Layer),例如:

  • Layer0(底层):用于视频播放层。
  • Layer1(上层):用于LVGL UI层。
  • 背景层(可选):用于静态背景。

实现步骤:

  1. 初始化显示驱动与图层:

    • 初始化DE,配置屏幕参数(分辨率、时序)。
    • 分配两个独立的帧缓冲区(Framebuffer),分别给Video Layer和UI Layer。
    • 配置Video Layer为“视频层”模式(可能支持YUV格式直接输入,节省带宽),UI Layer为“图形层”模式(RGB格式)。
    • 设置图层的叠加顺序(Z-order),确保UI Layer在Video Layer之上。
    • 启用图层的Alpha混合功能。为UI Layer设置一个全局Alpha值(如0xFF为完全不透明),或者使用每像素Alpha(如果LVGL使用ARGB8888格式且你启用了透明控件)。
  2. 视频解码输出到指定图层:

    • 在CedarX的测试程序中,不再直接向“屏幕”输出,而是向为Video Layer分配的帧缓冲区输出。
    • 这通常需要修改CedarX的“渲染器”(Renderer)配置。CedarX中间件可能提供了设置输出缓冲区的API,或者你需要修改底层驱动,让解码后的图像数据直接DMA到指定物理内存(即Video Layer的FB)。
    • 一种更通用的方法是:让CedarX解码后,通过一个回调函数将YUV或RGB数据返回给应用,再由应用将数据写入Video Layer的FB。但这会增加一次CPU拷贝。
  3. LVGL输出到UI图层:

    • 在上一节实现的disp_flush函数中,不再向唯一的屏幕FB拷贝数据,而是向为UI Layer分配的帧缓冲区拷贝。
    • 确保LVGL的绘制区域坐标是相对于UI Layer的。
  4. 同步与刷新:

    • 视频解码是连续不断的,它会持续更新Video Layer的FB。
    • LVGL的刷新由lv_timer_handler触发,只更新有变化的区域到UI Layer的FB。
    • DE的硬件会自动将两个图层按照Alpha混合规则合成,并最终扫描输出到显示屏。无需软件干预,效率极高。

此方案的优点:性能最好,视频解码和UI渲染完全并行,硬件混合不消耗CPU。缺点:实现复杂度高,需要深入了解D1s的DE驱动和CedarX的输出配置,移植性较差。

5.2 方案二:单层软件混合架构

这是一种更通用、更易实现的方案,尤其适合显示控制器不支持硬件多层,或者驱动层接口不开放的情况。其核心思想是:将视频帧作为LVGL的一个“图像对象”来显示。

实现步骤:

  1. 创建LVGL图像对象:
    lv_obj_t * video_img; video_img = lv_img_create(lv_scr_act()); lv_obj_set_size(video_img, VIDEO_WIDTH, VIDEO_HEIGHT); lv_obj_align(video_img, LV_ALIGN_CENTER, 0, 0);
  2. 获取视频帧并转换为LVGL图像:
    • 在CedarX解码的回调线程中,获取到解码后的RGB数据(如果解码输出是YUV,需要先做软件转换到RGB,这个计算量较大,是性能瓶颈之一)。
    • 将RGB数据填充到一个lv_img_dsc_t结构体中。这个结构体描述了图像的头部信息和像素数据。
    static lv_img_dsc_t video_frame_desc = { .header.always_zero = 0, .header.w = VIDEO_WIDTH, .header.h = VIDEO_HEIGHT, .header.cf = LV_IMG_CF_TRUE_COLOR, // 假设是RGB888 .data_size = VIDEO_WIDTH * VIDEO_HEIGHT * 3, .data = video_frame_buffer, // 指向存放RGB数据的缓冲区 };
  3. 更新LVGL图像对象:
    • 在视频回调函数中,每当新的一帧准备好后,就调用lv_img_set_src(video_img, &video_frame_desc)
    • 但是,绝对不能在CedarX的回调线程(非LVGL主线程)中直接调用LVGL的API。这会导致内存竞争和崩溃。
    • 正确的做法是:使用LVGL的“任务”(Task)或“异步调用”(lv_async_call)机制。将更新图像的操作封装成一个函数,然后从视频线程“投递”给LVGL主线程执行。
    // 视频解码线程 static void video_decode_thread(void) { while(1) { // ... 解码获取一帧数据,放入 video_frame_buffer ... // 通知LVGL线程更新图像 lv_async_call(async_set_img_src, video_img); // async_set_img_src 是下面定义的函数 } } // 这个函数将在LVGL主线程(即调用lv_timer_handler的线程)中安全执行 static void async_set_img_src(void * img_ptr) { lv_obj_t * img = (lv_obj_t *)img_ptr; lv_img_set_src(img, &video_frame_desc); }
  4. UI控件叠加:video_img对象之上,你可以正常创建其他的LVGL控件(按钮、标签等)。因为LVGL的渲染顺序是基于对象创建顺序(后创建的在上层),只要确保UI控件在video_img之后创建,它们就会显示在视频之上。

此方案的优点:实现相对简单,与硬件细节解耦,移植性强。缺点:性能开销大。视频YUV到RGB的转换、整帧图像的像素数据拷贝、以及LVGL重绘整个图像对象,都会消耗大量CPU资源。高分辨率或高帧率视频下可能无法流畅。

5.3 方案选择与性能优化技巧

对于D1s这类性能有限的芯片,我强烈建议优先尝试方案一(硬件混合)。即使初期投入时间多,但一旦跑通,其流畅度是方案二无法比拟的。如果受限于资源或时间,只能采用方案二,那么以下优化手段至关重要:

  • 降低视频规格:播放低分辨率(如640x360)、低帧率(24fps或以下)的视频。
  • 优化色彩转换:如果CedarX可以配置解码输出格式,尝试输出RGB565(LVGL也配置为RGB565),这比RGB888节省一半的带宽和转换开销。使用NEON指令集(如果D1s的C906支持类似SIMD指令)或优化后的色彩转换库。
  • 局部更新:如果视频画面不是全屏,或者UI只覆盖部分区域,可以只更新图像对象的一部分区域,但这需要修改LVGL的底层驱动,较为复杂。
  • 双缓冲与直接内存操作:为视频帧准备两个缓冲区,解码线程写后台缓冲区,LVGL线程读取前台缓冲区,通过指针交换来避免拷贝。这需要精细的线程同步。
  • 调整LVGL刷新率:适当降低lv_timer_handler的调用频率(例如到10ms),并减少UI动画的复杂度。

6. 系统整合、调试与性能实测

6.1 整合应用程序框架

无论是采用方案一还是方案二,你都需要一个主程序来协调所有任务。一个典型的架构是多线程模型

  • 主线程(LVGL线程):负责执行lv_timer_handler(),处理所有LVGL对象的管理和事件响应。
  • 视频解码线程:独立线程运行CedarX播放器,负责解封装、解码。解码后的帧通过线程间通信(如队列、环形缓冲区)或异步回调机制传递给主线程。
  • 音频播放线程(可选):如果播放有声视频,音频解码和播放最好也放在独立线程,通过CedarX的音频输出接口或单独的音频驱动(如ALSA)处理。

你需要使用Melis提供的线程API(如pthread)或RTOS任务API来创建和管理这些线程。务必注意共享资源(如帧缓冲区)的互斥保护。

6.2 调试方法与工具

在混合显示项目中,调试是重中之重。

  1. 日志系统:在关键位置(线程入口、回调函数、错误处理)添加日志打印。Melis可能提供了printf或自定义的日志宏。将日志输出到串口,这是最可靠的调试手段。
  2. 性能 profiling:
    • CPU占用率:在串口shell中,使用topps命令查看各个线程的CPU使用率。视频解码线程和LVGL主线程是观察重点。持续接近100%则意味着瓶颈。
    • 内存查看:使用free命令查看系统内存和VPU专用内存的使用情况,防止内存泄漏。
    • 帧率测试:
      • 视频帧率:在视频解码回调中计数,每秒打印一次。
      • UI刷新帧率:在LVGL的disp_flush回调中计数,或者创建一个每秒移动一次的动画对象来直观感受流畅度。
  3. 图形调试:如果出现花屏、错位,可以尝试:
    • disp_flush中,将拷贝的矩形区域用固定颜色(如红色边框)标出,确认LVGL的绘制区域是否正确。
    • 将视频帧数据先保存为文件(如RAW RGB格式),在PC上用工具查看,确认解码输出是否正确。

6.3 典型问题排查实录

以下是我在实际开发中遇到的一些典型问题及解决思路:

问题:视频播放正常,但LVGL界面一出现,视频就严重卡顿。

  • 排查:使用top命令发现,LVGL主线程CPU占用率超过80%。
  • 分析:这很可能是采用了方案二(软件混合),且没有做任何优化。LVGL不断重绘巨大的图像对象,消耗了所有CPU资源,导致视频解码线程得不到足够的时间片。
  • 解决:
    1. 确认方案:如果可能,转向方案一。
    2. 优化方案二:如6.3节所述,降低视频分辨率/帧率,优化YUV转RGB,尝试双缓冲零拷贝。
    3. 调整线程优先级:适当提高视频解码线程的优先级,确保其能及时运行。

问题:屏幕闪烁,或视频与UI重叠部分显示异常。

  • 排查:现象类似于撕裂(tearing)。
  • 分析(针对方案一):可能是Video Layer和UI Layer的帧缓冲区更新不同步。比如在DE读取某一层进行混合时,应用正在写入该层的另一块缓冲区(如果用了双缓冲)。
  • 解决:实现简单的帧同步机制。例如,在应用写完一个图层的后台缓冲区后,通过一个IOCTL命令通知DE切换前台缓冲区(翻页)。确保两个图层的翻页操作在垂直消隐期间或同步进行。

问题:LVGL控件对触摸无反应。

  • 排查:视频播放和UI显示都正常,但点击按钮没反应。
  • 分析:LVGL的输入设备驱动未正确移植或启用。触摸事件没有传递给LVGL。
  • 解决:实现lv_port_indev.c,将Melis的触摸屏驱动(可能是输入子系统事件)转换为LVGL的输入事件。确保在lv_timer_handler循环中调用lv_indev_read相关的函数。

问题:系统运行一段时间后死机或重启。

  • 排查:查看死机前的串口日志,是否有内存分配失败(mallocfail)或驱动错误信息。
  • 分析:可能是内存泄漏。特别是CedarX解码每一帧都会分配内存,如果播放完毕没有正确释放,会导致VPU内存耗尽。
  • 解决:严格检查所有资源申请与释放的配对。使用Melis的内存检测工具(如果有)来监控内存分配。确保在播放停止或退出时,调用CedarX的CdxPlayerDestroy等清理函数。

整个项目从环境搭建到稳定运行,是一个不断迭代、调试和优化的过程。从最简单的裸机视频播放,到引入LVGL,再到实现混合显示,每一步都要扎实测试。当看到自己设计的UI流畅地叠加在视频画面上时,那种成就感是对所有调试工作最好的回报。这个框架搭好后,你就可以在此基础上,开发出功能丰富的嵌入式多媒体产品了。