跳转至

图形视频开发入门

本文档介绍 HiDiTing V100 图形显示与视频驱动的模块关系、功能边界和开发流程。开发者可先使用 GPU 填色场景确认 VAU、DPU 与显示屏链路正常,再按 VAU、DPU、JPEG、LCD、VENC、VDEC 和 VICAP 章节扩展图形处理、图像编解码与视频业务。

图形视频驱动背景知识

图形显示系统将绘制完成的内容显示在屏幕上,由 GUI 图形引擎、图形驱动、显示接口和显示设备组成:GUI 负责窗口、布局、动画、输入事件与绘制调度;VAU 负责填色、绘制、格式转换和图层合成;DPU 负责将 Surface 送往显示设备;JPEG 负责图片编解码;LCD 驱动负责 MIPI/QSPI 屏端控制。VENC、VDEC 和 VICAP 分别负责视频编码、视频解码和视频输入捕获。

图 1 图形显示系统架构

图形显示系统架构

模块 主要职责 接口参考
VAU Surface 填色、格式转换、图层混合、Alpha、ColorKey 与 ROP。 /src/middleware/utils/common_headers/gpu/external/soc_vau_api.h
DPU 创建显示层、设置显示 Surface、刷新图层与等待显示同步。 /src/middleware/utils/common_headers/gpu/external/soc_dpu_api.h
JPEG JPEG 文件或内存输入、缩略图、YUV420SP 输出与缩放解码。 /src/middleware/utils/common_headers/gpu/external/soc_jpeg_api.h
LCD / MIPI / QSPI 注册屏幕参数、初始化屏幕、设置亮度和读写屏端寄存器。 /src/drivers/drivers/driver/lcd/include/soc_lcd_api.h
VENC JPEG、MJPEG 视频编码,码流获取及码率、OSD 等控制。 /src/middleware/utils/common_headers/venc/external/soc_venc_api.h
VDEC 视频解码、码流缓冲获取与归还、帧获取与归还、事件监听。 /src/middleware/utils/common_headers/vdec/external/soc_vdec_api.h

快速跑通图形显示 Demo

功能说明

本节使用 SDK 已接入的 gpu_at 组件执行 AT+GPU=lcd_fill,0xFFFF0000。该命令先创建 VAU 任务并以指定 ARGB 颜色填充 Surface,再创建 DPU 图层、设置 Surface 并刷新显示;屏幕应显示为纯红色。这个场景覆盖最小的“显存 Surface → VAU → DPU → LCD”闭环,不涉及文件、摄像头或视频码流。

图形显示示例流程

准备工作

说明: 本文示例命令以一站式 CLI 为主。实际开发可从以下三种环境中选择,推荐使用一站式 CLI。

开发环境 适用场景 使用指南
一站式 CLI(推荐) 快速完成目标选择、构建、烧录和串口监视 一站式 CLI 开发环境使用指南
HiSpark Studio for VS Code 图形化编辑、编译、烧录和调试 HiSpark Studio for VS Code 开发环境使用指南
WSL 与 Docker 在 Windows 上使用一致的 Linux 容器构建环境 WSL 与 Docker 环境使用指南

一站式 CLI 开发环境使用指南准备环境、构建和烧录。运行前确认目标板已连接适配的显示屏,并使用 3322 图形显示配置;gpu_at 已在该目标的组件清单中启用。

文件结构与代码走读

文件 作用
/src/middleware/utils/at/at_gpu_cmd/CMakeLists.txt 将 AT 注册和图形显示代码构建为 gpu_at 组件。
/src/middleware/utils/at/at_gpu_cmd/at/at_gpu_cmd_table.h 注册 GPU AT 命令及其参数语法。
/src/middleware/utils/at/at_gpu_cmd/at/at_gpu.c 实现填色、冒烟显示、亮度、色条和 DFX 等图形场景。
/src/build/config/target_config/3322/target_config.py gpu_at 纳入 3322 目标的构建组件。
  1. at_gpu_sample_process() 解析 AT+GPU= 后的第一个参数,并在 g_at_gpu_func_map 中分发至 lcd_fillsmokelcd_light 等场景函数。
  2. wstp_lcd_fill() 根据显示屏实际宽高配置 ext_vau_surface:设置 EXT_GFX_FMT_ARGB8888、物理地址、stride 及 is_color_surface,再把 AT 参数写入 color
  3. 函数依次调用 uapi_vau_createuapi_vau_filluapi_vau_submit,将纯色写入 Surface。
  4. 随后配置 ext_dpu_layer_infoext_dpu_surface,调用 uapi_dpu_create_layeruapi_dpu_set_layer_infouapi_dpu_refresh_layers 完成送显。

核心调用片段如下;自定义应用应对每一步返回值进行检查,并在不再显示时释放 VAU 任务和 DPU 图层。

vau_handle = uapi_vau_create();
uapi_vau_fill(vau_handle, &src_surface);
uapi_vau_submit(vau_handle, TD_FALSE, 1000);

uapi_dpu_create_layer(&layer_info, &dpu_handle);
uapi_dpu_set_layer_info(dpu_handle, &dpu_surface);
uapi_dpu_refresh_layers();

运行、效果与调试

构建并烧录后,在 AT 串口执行:

AT+GPU=lcd_fill,0xFFFF0000

预期屏幕显示纯红色,串口打印 color = ffff0000。若无显示或花屏,先检查 LCD 是否已初始化、屏幕宽高和像素格式是否匹配、Surface 地址是否属于可访问显存、stride 是否满足格式和对齐要求;随后使用 AT+GPU=dpu_procAT+GPU=vau_procAT+GPU=lcd_proc 查看驱动状态。

基于图形显示 Demo 开发自己的应用

gpu_at 的填色场景跑通后,可按目标业务选择对应的模块组合:纯色或图层合成使用 VAU;屏幕输出使用 DPU;图片预览先经 JPEG 解码;摄像头或视频输入接入 VICAP;录像或图片编码使用 VENC;视频播放或码流解码使用 VDEC。一个 Surface 在交给下游模块前,必须明确其物理地址、格式、宽高、stride、压缩方式和所有权。

  1. /src/middleware/utils/at/at_gpu_cmd/CMakeLists.txt 的组件声明为模板,新建应用组件并在目标配置中纳入组件名。
  2. 为每个图形任务分配相互独立且满足对齐要求的输入、输出 Surface;不要复用显示中或尚未完成 VAU 任务的缓冲区。
  3. 两层合成按“配置源 Surface → 配置目标 Surface 和 ext_vau_blit_opt → 创建任务 → uapi_vau_compose → 提交并等待 → 销毁任务”执行。现有 VAU 开发指引保留完整字段示例。
  4. 将 VAU 输出交给 DPU 时,widthheightstridecolor_fmtcompress_mode 必须原样匹配;创建图层、设置图层信息、刷新后再等待显示同步。
  5. 应用退出或切换显示资源时,按“停止使用图层 → uapi_dpu_destroy_layeruapi_vau_destroy → 释放显存”的逆序释放。发生错误时也必须执行已成功步骤的逆序释放。

图形显示示例扩展流程

新建 C 应用的实现清单

下表给出实现一个“纯色或两层合成并显示到 LCD”的 C 应用所需的固定输入和对应参考位置。先补齐这些输入,再生成代码;不要根据其他板型的显示地址、屏幕时序或压缩模式猜测参数。

开发项 必须确定的内容 参考
应用组件 组件名、源文件、私有头文件目录、WHOLE_LINK 和是否加入 RAM 组件。 gpu_at/CMakeLists.txt/src/build/config/target_config/3322/target_config.py
屏幕与 LCD 屏幕型号、分辨率、MIPI/QSPI 类型、时钟、时序和初始化命令。 LCD 开发指引/src/drivers/drivers/driver/lcd/include/soc_lcd_api.h
Surface 内存 每一路输入、输出 Surface 的物理地址、可访问范围、宽高、stride、格式、压缩模式和所有权。 /src/middleware/utils/at/at_gpu_cmd/at/at_gpu.c/src/middleware/utils/common_headers/gpu/external/soc_vau_type.h/src/middleware/utils/common_headers/gpu/external/soc_dpu_type.h
图形场景 纯色填充、两层合成、格式转换或 JPEG 图片预览;每个场景只选择与目标一致的 VAU 操作。 VAU 开发指引JPEG 开发指引
显示输出 DPU layer ID、缓冲模式、输出 Surface 及刷新/同步策略。 DPU 开发指引/src/middleware/utils/common_headers/gpu/external/soc_dpu_api.h
验收现象 目标画面、串口日志、允许的帧率/刷新频率,以及无显示、花屏和超时的处理策略。 运行、效果与调试

场景选择、配置和验证条件

不同图形视频场景的输入资源、构建条件和可观察结果不同。实现应用时先从下表选择一行作为主链路,不要把 DFX 命令、测试宏和业务数据路径混为一套实现。

目标场景 可直接参考的代码 必须补齐的配置与资源 验收结果
纯色、两层合成或格式转换显示 /src/middleware/utils/at/at_gpu_cmd/at/at_gpu.clcd_fillsmokewstp_vau_fmt_transgpu_at 已在 3322 RAM 组件清单中。 目标板的 LCD 初始化参数;每个 Surface 的物理地址、格式、stride 和压缩模式。at_gpu.c 中的测试地址仅对应其已适配目标。 AT+GPU=lcd_fill,0xFFFF0000 显示纯红色,或应用显示预期的合成画面。
JPEG 图片预览 JPEG 开发指引/src/middleware/utils/common_headers/gpu/external/soc_jpeg_api.h JPEG 文件或内存输入、输出 YUV420SP 缓冲区、stride/UV 偏移和显示 Surface;3322 配置需启用 SUPPORT_GPU_JPEG 解码返回成功,输出 Surface 经 VAU/DPU 显示正确图片,无颜色或尺寸异常。
摄像头预览 /src/ohos/foundation/multimedia/camera_lite/sample/camera_sample.cpp/src/middleware/utils/at/at_camera_cmd/at/at_camera.c 摄像头模组、输入接口与时序、Camera 配置、预览 Surface 和 LCD 路径;通过 AT 运行时还需启用 SUPPORT_AT_CAMERA 可持续获取预览帧并显示;断开、停止和错误回调均可释放帧资源。
JPEG/MJPEG 编码 /src/middleware/utils/common_headers/venc/external/soc_venc_api.hVENC 工作流程 输入图像格式、分辨率、码率/质量、输出码流缓冲区和存储或传输去向;3322 的 VENC 库由 /src/build/config/target_config/3322/cmake/venc.cmake 接入。 按帧获取并归还码流,生成文件或上传端可解析 JPEG/MJPEG。
压缩视频解码并显示 /src/middleware/utils/common_headers/vdec/external/soc_vdec_api.hVDEC 工作流程 码流协议、分辨率、帧率、码流缓冲区、帧缓冲区、事件处理和 DPU 显示路径;3322 的 VDEC 库由 /src/build/config/target_config/3322/cmake/vdec.cmake 接入。 码流缓冲可按规则获取和归还,收到新帧事件后显示正确 YUV 画面,EOS 和错误事件可回收资源。

at_venc.cat_vdec.c 默认提供模块 DFX 命令入口;其中端到端测试分支分别受 SUPPORT_VENC_TESTSUPPORT_VDEC_TEST 控制。开发业务应用时,应以 VENC/VDEC 公共头文件中的创建、启动、送帧/送流、取码流/取帧、归还和销毁接口实现自己的数据链路,而不是把 DFX 命令当作编码或解码业务入口。

视频链路的资源闭环

摄像头、编码和解码场景必须把每个缓冲区的申请和归还写入同一条生命周期。以下顺序可作为实现和代码评审清单:

输入帧或码流到达
  → 获取/申请模块缓冲区
  → 填入或提交数据
  → 获取编码码流或解码帧
  → 存储、发送或交给 VAU/DPU 显示
  → 归还码流、帧和显示 Surface
  → 收到 EOS、停止或错误时停止模块并销毁句柄

实现 VENC/VDEC/VICAP 业务前,任务说明中应同时给出目标板、摄像头或码流来源、编码协议、分辨率、帧率、输入输出格式、缓存数量、存储/传输去向和验收画面。缺少这些输入时,只能完成接口骨架,不能假定默认参数在目标硬件上可用。

实现顺序如下:

  1. 参照 gpu_at 的组件 CMake 文件创建应用组件,并将组件名加入目标的 RAM 组件清单。应用入口可以是任务、服务或 UI 回调;仅在需要串口验证时才注册 AT 命令。
  2. 按 LCD 开发指引完成屏幕信息注册和初始化。LCD 未就绪时,不创建 DPU 图层或提交显示帧。
  3. 根据场景填充 ext_vau_surfaceext_vau_surface_list 和可选的 ext_vau_blit_opt。所有输入和输出 Surface 均写明格式、stride、物理地址和压缩方式。
  4. 调用 uapi_vau_create 创建任务;使用 uapi_vau_filluapi_vau_renderuapi_vau_compose 配置处理;提交后确认任务完成。
  5. 使用 uapi_dpu_create_layeruapi_dpu_set_layer_infouapi_dpu_refresh_layers 将 VAU 输出送显。仅在显示同步完成且不再被 DPU 使用后,才能复用输出 Surface。
  6. 在成功路径和失败路径均按逆序调用 uapi_dpu_destroy_layeruapi_vau_destroy,再释放显存和业务资源。为每个接口保留返回值日志,便于定位格式、地址和时序问题。

以下骨架用于启动显示链路;具体 Surface 参数必须来自前表的板级输入。启动成功后,应用应保存 vau_handledpu_handle 和 Surface 所有权,在业务结束时再调用停止路径释放资源:

td_s32 ret = EXT_FAILURE;
td_handle vau_handle = 0;
td_handle dpu_handle = 0;
td_bool dpu_created = TD_FALSE;
td_u32 timeout_ms = 1000;

/* 此前已完成 surface_list、layer_info 和 dpu_surface 的板级配置。 */
vau_handle = uapi_vau_create();
if (vau_handle <= 0) {
    goto exit;
}
ret = uapi_vau_compose(vau_handle, &surface_list);
if (ret != EXT_SUCCESS) {
    goto destroy_vau;
}
ret = uapi_vau_submit(vau_handle, TD_TRUE, timeout_ms);
if (ret != EXT_SUCCESS) {
    goto destroy_vau;
}
ret = uapi_dpu_create_layer(&layer_info, &dpu_handle);
if (ret != EXT_SUCCESS) {
    goto destroy_vau;
}
dpu_created = TD_TRUE;
ret = uapi_dpu_set_layer_info(dpu_handle, &dpu_surface);
if (ret == EXT_SUCCESS) {
    ret = uapi_dpu_refresh_layers();
}
if (ret == EXT_SUCCESS) {
    /* 显示期间保留 dpu_handle、vau_handle 和相关 Surface。 */
    return EXT_SUCCESS;
}

destroy_dpu:
    if (dpu_created) {
        (void)uapi_dpu_destroy_layer(dpu_handle);
    }
destroy_vau:
    (void)uapi_vau_destroy(vau_handle);
exit:
    return ret;

停止显示时,先确保 DPU 不再使用该 Surface,再执行以下释放顺序:

(void)uapi_dpu_destroy_layer(dpu_handle);
(void)uapi_vau_destroy(vau_handle);
/* 最后释放或归还输入、输出 Surface 的显存。 */