跳转至

图形视频模块开发

按场景展开模块开发

在完成前述最小送显闭环后,按业务场景继续开发:图层绘制、混合和格式转换依次使用 VAU 与 DPU;图片预览在 JPEG 解码后将输出 Surface 交给 VAU/DPU;屏幕适配先完成 LCD 初始化;视频采集、编码、解码分别进入 VICAP、VENC、VDEC 分支。以下内容保留各场景的功能限制、参数表、流程图和代码示例,阅读时应只选择当前链路需要的分支。

VAU

接口参考:/src/middleware/utils/common_headers/gpu/external/soc_vau_api.h

VAU 概述

矢量加速单元VAU(Vector Acceleration Unit)主要包含矢量绘制、矩阵变换、2.5D、多层混合叠加、低功耗、高性能(60@fps)、低内存等功能。

VAU 功能描述

VAU模块提供如表1所示接口。

表 1 VAU模块接口

接口

描述

uapi_vau_create

返回对应任务的句柄。

uapi_vau_cancel

取消对应任务。

uapi_vau_destroy

销毁对应任务

uapi_vau_fill

快速填充颜色,对surface填充的颜色为color值,color的格式支持:ARGB8888、RGB888。

uapi_vau_render

矢量图形绘制,主要用于绘制矢量基本图形。

uapi_vau_compose

多图层叠加,可支持叠加、仿射变换、ColorKey、ROP等操作(多个操作一次性提交)。

uapi_vau_submit

提交任务。

uapi_vau_parse_cmp_header

解析压缩文件头。

uapi_vau_wait_for_done

等待任务完成。

  • 矩形填充

    用某种颜色填充表面的某一矩形区域,矩形填充支持Alpha混和。

  • 数据搬移

    数据搬移过程中可以完成像素格式转换、Alpha混和、ColorKey、ROP等,也可进行缩放、旋转、镜像变换。

  • 像素格式转换

    Blit模块支持以下像素格式转换:

    • 源位图像素格式:ARGB8888、RGB888、RGB565、ARGB1555、ARGB4444、A1、A8。
    • 目标位图像素格式:ARGB8888、RGB888、RGB565、ARGB1555、ARGB4444。
  • Alpha混和

    将多个位图的像素值按照Alpha值进行加权求和,得到一个Alpha混和后的位图。Alpha可来源于源位图、目标位图和全局Alpha。

  • ColorKey

    • 对源位图进行ColorKey,则把位图从源地址搬移到输出地址,在此过程中,颜色为关键色的位图像素使用目标位图数据替换。
    • 对目标位图进行ColorKey,则把位图从目标地址搬移到输出地址,在此过程中,颜色为与关键色不相同的位图像素用源位图数据替换。
  • ROP

    对源位图和目标位图的颜色值进行布尔运算。

VAU 开发指引

以使用VAU两层叠加为例,surface1作为背景通过VAU纯色填充,surface2作为前景,surface1与surface2进行叠加。

  1. 设置surface1和surface2的属性配置:

    #define TEST_VAU_W 454
    #define TEST_VAU_H 454
    #define TEST_VAU_PSRAM_OFFSET         0x6C200000
    #define TEST_VAU_MAX_BUF_SIZE         0x10000000
    
    ext_vau_surface src_surface[2] = {0};
    ext_vau_surface dst_surface = {0};
    ext_vau_surface_list surface_list = {0};
    ext_vau_blit_opt opt = {0};
    
    /* src_surface[0] backgroud fill color red */
    src_surface[0].width          = TEST_VAU_W;
    src_surface[0].height         = TEST_VAU_H;
    src_surface[0].phy_addr       = TEST_VAU_PSRAM_OFFSET + 0xD0000;
    src_surface[0].color_fmt      = EXT_GFX_FMT_ARGB8888;
    src_surface[0].compress_mode  = EXT_GFX_COMPRESS_NONE;
    src_surface[0].argb_order     = EXT_GFX_FMT_ORDER_ARGB;
    src_surface[0].rect.x         = 100;
    src_surface[0].rect.y         = 100;
    src_surface[0].rect.width     = 256; /* 256:index */
    src_surface[0].rect.height    = 256; /* 256:index */
    src_surface[0].stride         = 1816; /* 454 * 32 / 8 = 1816 */
    src_surface[0].is_color_surface = TD_TRUE;
    src_surface[0].color            = 0xffff0000;
    memset_s((void *)src_surface[0].phy_addr, TEST_VAU_MAX_BUF_SIZE,
    0xff, src_surface[0].stride * src_surface[0].height);
    
    /* src_surface[1] foreground white */
    src_surface[1].width          = 256; /* 256:index */
    src_surface[1].height         = 256; /* 256:index */
    src_surface[1].phy_addr       = TEST_VAU_PSRAM_OFFSET;
    src_surface[1].color_fmt      = EXT_GFX_FMT_RGB565;
    src_surface[1].argb_order     = EXT_GFX_FMT_ORDER_ARGB;
    src_surface[1].compress_mode  = EXT_GFX_COMPRESS_NONE;
    src_surface[1].rect.x         = 0;
    src_surface[1].rect.y         = 0;
    src_surface[1].rect.width     = src_surface[1].width;
    src_surface[1].rect.height    = src_surface[1].height;
    src_surface[1].stride         = 912; /* 454 * 16 / 8 = 908, 8字节对齐得912 */
    
    memset_s((void *)src_surface[1].phy_addr, TEST_VAU_MAX_BUF_SIZE,
    0x0, src_surface[1].stride * src_surface[1].height);
    src_surface[1].alpha_info.global_alpha_en = TD_TRUE;
    src_surface[1].alpha_info.global_alpha    = 0x50;
    src_surface[1].alpha_info.pixel_alpha_en  = TD_TRUE;
    src_surface[1].alpha_info.premult_en      = TD_TRUE;
    
  2. 设置dst surface的属性:

    /* dst surface */
    dst_surface.width          = TEST_VAU_W;
    dst_surface.height         = TEST_VAU_H;
    dst_surface.phy_addr       = TEST_VAU_PSRAM_OFFSET + 0xD0000;
    dst_surface.color_fmt      = EXT_GFX_FMT_ARGB8888;
    dst_surface.compress_mode  = EXT_GFX_COMPRESS_NONE;
    dst_surface.argb_order     = EXT_GFX_FMT_ORDER_ARGB;
    dst_surface.rect.x         = src_surface[0].rect.x;
    dst_surface.rect.y         = src_surface[0].rect.y;
    dst_surface.rect.width     = src_surface[0].rect.width;
    dst_surface.rect.height    = src_surface[0].rect.height;
    dst_surface.stride         = 1816; /* 454 * 32 / 8 = 1816 */
    opt.blend_opt.blend_enable   = TD_TRUE;
    opt.blend_opt.blend_cmd      = EXT_VAU_BLENDCMD_SRCOVER; /* 正常绘制显示,上下层绘制叠加 */
    opt.blend_opt.out_alpha_mode = EXT_VAU_OUTALPHA_FROM_FOREGROUND; /* alpha来自前景 */
    surface_list.src_surface_cnt = 2; /* 2:index */
    surface_list.src_surface = src_surface;
    surface_list.dst_surface = &dst_surface;
    surface_list.opt = &opt;
    
  3. 执行一次blit操作:

    td_s32 ret;
    td_handle handle;
    handle = uapi_vau_create();
    if (handle <= 0) {
        printf("uapi_vau_create failed\n");
        return EXT_FAILURE;
    }
    ret = uapi_vau_compose(handle, &surface_list);
    if (ret != EXT_SUCCESS) {
        printf("uapi_vau_compose failed\n");
        uapi_vau_destroy(handle);
        return ret;
    }
    ret = uapi_vau_submit(handle, TD_TRUE, 1000); /* 1000 ms timeout */
    if (ret != EXT_SUCCESS) {
        uapi_vau_cancel(handle);
        printf("uapi_vau_submit failed\n");
        uapi_vau_destroy(handle);
        return ret;
    }
    uapi_vau_destroy(handle);
    

DPU

接口参考:/src/middleware/utils/common_headers/gpu/external/soc_dpu_api.h

DPU 概述

显示处理单元DPU(Display Processing Unit)主要对图形显示通路的处理,包含多层叠加、自研压缩数据解压、局部刷新、低功耗等功能。

DPU 功能描述

主要功能:

  • 支持两层在线叠加。
  • 支持RTOS操作系统。
  • 支持SRAM存储访问。
  • 支持PSRAM存储访问。
  • 支持低功耗。
  • 支持输入分辨率可设。
  • 支持CMD模式刷新显示。
  • 支持对接MIPI接口实现图形显示。
  • 支持对接QSPI接口实现图形显示。
  • 支持DFX。
  • 支持低Flash下DPU运行。
  • 支持低内存下DPU运行。
  • 支持图层ColorKey。

硬件约束:

  • 申请地址16Byte对齐。
  • 输入stride要求16Byte对齐。
  • G0/G1支持的颜色格式:RGB888/RGB565。

DPU模块提供以下接口:

表 1 DPU模块接口

接口

说明

uapi_dpu_create_layer

创建图层。

uapi_dpu_destroy_layer

销毁图层。

uapi_dpu_set_layer_alpha

设置图层全局Alpha。

uapi_dpu_get_layer_alpha

获取图层全局Alpha。

uapi_dpu_set_layer_pos

设置图层在屏上的显示位置。

uapi_dpu_get_layer_pos

获取图层在屏上的显示位置。

uapi_dpu_set_layer_zorder

设置图层Z序。

uapi_dpu_get_layer_zorder

获取图层Z序。

uapi_dpu_show_layer

显示图层。

uapi_dpu_hide_layer

隐藏图层。

uapi_dpu_set_layer_info

设置图层信息。

uapi_dpu_get_layer_info

获取图层信息。

uapi_dpu_set_layer_colorkey

设置图层的ColorKey。

uapi_dpu_get_layer_colorkey

获取图层的ColorKey。

uapi_dpu_refresh_layers

刷新显示。

uapi_dpu_wait_layer_vsync

等待显示完成。

uapi_dpu_set_layer_vblank

设置等待标记。

uapi_dpu_get_layer_vblank

获取等待标记。

uapi_dpu_query_layer_state

查询图层的显示完成状态。

uapi_dpu_set_output_info

配置输出参数。

DPU 开发指引

  1. 通过接口uapi_dpu_create_layer创建显示图层,并返回图层句柄:

    td_s32 ret;
    td_handle dpu_handle;
    ext_dpu_surface dpu_canvas = { 0 };
    ext_dpu_layer_info layer_info = { 0 };
    /* dst_surface vau的输出surface */
    layer_info.width           = dst_surface->width;
    layer_info.height          = dst_surface->height;
    layer_info.layer_id        = EXT_DPU_LAYER_ID1;
    layer_info.layer_fmt       = dst_surface->color_fmt;
    layer_info.compress_mode   = dst_surface->compress_mode;
    /* NORMAL模式(双canvas送显模式) */
    layer_info.buf_mode        = EXT_DPU_BUFFER_MODE_NORMAL;
    ret = uapi_dpu_create_layer(&layer_info, &dpu_handle);
    if (ret != EXT_SUCCESS) {
        printf("call uapi_dpu_create_layer fail, ret:0x%x\n", ret);
        return ret;
    }
    
  2. 通过接口uapi_dpu_set_layer_info设置图层显示信息:

    dpu_canvas.width             = dst_surface->width;
    dpu_canvas.height            = dst_surface->height;
    dpu_canvas.stride            = dst_surface->stride;
    dpu_canvas.size              = dpu_canvas.height * dpu_canvas.stride;
    dpu_canvas.phy_addr          = dst_surface->phy_addr;
    dpu_canvas.vir_addr          = dst_surface->vir_addr;
    dpu_canvas.update_rect       = TD_NULL;
    dpu_canvas.color_fmt         = dst_surface->color_fmt;
    dpu_canvas.compress_mode     = dst_surface->compress_mode;
    ret = uapi_dpu_set_layer_info(dpu_handle, &dpu_canvas);
    if (ret != EXT_SUCCESS) {
        printf("call uapi_dpu_set_layer_info fail, ret:0x%x\n", ret);
        return ret;
    }
    
  3. 调用接口uapi_dpu_refresh_layers刷新显示内容:

    ret = uapi_dpu_refresh_layers();
    if (ret != EXT_SUCCESS) {
        printf("call uapi_dpu_refresh_layers fail, ret:0x%x\n", ret);
        return ret;
    }
    

JPEG

接口参考:/src/middleware/utils/common_headers/gpu/external/soc_jpeg_api.h

JPEG 概述

穿戴手表对体验的需求越来越高,如视频预览(手表控制手机拍照,在手表端可看到要拍照的内容)、本地视频播放(如视频表盘),而这些应用需要支持JPEG解码的功能。

图 1 JPEG解码微架构图

JPEG解码微架构图

JPEG 功能描述

  • 支持文件方式输入。
  • 支持内存方式输入。
  • 支持解码输出yuv420 semi-planer格式的数据。
  • 支持解码缩小1倍、2倍、4倍、8倍。
  • 支持获取缩略图。

JPEG 开发指引

JPEG提供的接口说明请参考API说明,后续章节通过demo来指导应用如何使用。

获取缩略图
void demo_get_exif_data(char *file_name)
{
    int ret;
    static int cnt = 0;
    FILE *in_file = NULL;
    FILE *ou_file = NULL;
    struct jpeg_decompress_struct dinfo = { 0 };
    struct jpeg_source_struct src = { 0 };

    in_file = fopen(file_name, "rb");
    if (in_file == NULL) {
        return;
    }

    /* 设置输入流信息 */
    src.infile = in_file;
    /* 缩略图操作使能 */
    dinfo.thumbnail_en = TD_TRUE;

    /* 创建解码器,该函数包含对文件头的解析处理 */
    ret = uapi_jpeg_decomress_create(&dinfo, &src, TD_FALSE);
    if (ret != 0) {
        fclose(in_file);
        return;
    }
    /* 缩略图要写入的文件路径和文件名 */
    snprintf(file_name, SAMPLE_JPEG_EXIF_FILE_PATH_LEN, "%s/out_%d.jpg", SAMPLE_JPEG_EXIF_FILE_DIR, cnt++);

    /*  将缩略图数据写到文件中 */
    ou_file = fopen(file_name, "wb");
    fwrite(dinfo.thumbnail.buffer, 1, dinfo.thumbnail.size, ou_file);
    fclose(ou_file);

    /*  销毁解码器 */
    uapi_jpeg_decompress_destroy(&dinfo);

    fclose(in_file);
    return;
}

解码后数据输出 yuv420 semi-planar
void demo_decompress_to_yuvsp(char *file_name)
{
    int ret;
    FILE *in_file = NULL;
    struct jpeg_decompress_struct dinfo = { 0 };
    struct jpeg_source_struct src = { 0 };
    struct jpeg_dst_struct dst = { 0 };

    in_file = fopen(file_name, "rb");
    if (in_file == NULL) {
        return;
    }

    /* 设置输入流信息 */
    src.infile = in_file;
    /* 缩小1倍 */
    dinfo.scale = JPEG_SCALE_1;
    /* 解码输出格式和图片格式保持一致 */
    dinfo.output_yuv420sp = TD_TRUE;

    /* 创建解码器 */
    ret = uapi_jpeg_decomress_create(&dinfo, &src, TD_FALSE);
    if (ret != 0) {
        fclose(in_file);
        return;
    }

    /* 根据图片信息分配内存 */
    dst.stride    = dinfo.output.stride[0];
    dst.uv_stride = dinfo.output.stride[1];
    dst.size      = dinfo.output.size[0] + dinfo.output.size[1];
    dst.uv_offset = dinfo.output.size[0];

    /* 内存分配 */
    dst.phy_buf = mpi_mmz_new(dst.size, 64, NULL, "JPEG");
    if (dst.phy_buf == 0) {
    fclose(in_file);
        return;
    }

    dst.vir_buf = (td_char *)mpi_mmz_map(dst.phy_buf, 0);
    if (dst.vir_buf == NULL) {
        mpi_mmz_delete(dst.phy_buf);
        fclose(in_file);
        return;
    }

    /* 启动解码 */
    uapi_jpeg_decompress_start(&dinfo, &dst);

    /* 销毁解码器 */
    uapi_jpeg_decompress_destroy(&dinfo);

    /* 释放资源 */
    mpi_mmz_unmap(dst.phy_buf);
    mpi_mmz_delete(dst.phy_buf);

    fclose(in_file);
    return;
}

JPEG 注意事项

只支持baseline,数据精度为8的JPEG图片。

LCD

接口参考:/src/drivers/drivers/driver/lcd/include/soc_lcd_api.h

LCD 概述

LCD为屏端控制驱动提供显示、进出睡眠、进出IDLE、读写屏端控制寄存器、设置获取屏幕亮度等功能。

LCD 功能描述

LCD模块提供以下接口:

表 1 LCD提供的接口

接口

描述

uapi_lcd_info_register

屏幕信息注册,包括屏幕分辨率、帧率、通信串口类型及指令集等。

uapi_lcd_init

LCD驱动初始化。

uapi_lcd_deinit

LCD驱动去初始化。

uapi_lcd_get_status

获取屏幕当前状态。

uapi_lcd_enter_sleep_mode

使屏端进入睡眠模式。

uapi_lcd_exit_sleep_mode

使屏端退出睡眠模式。

uapi_lcd_enter_idle_mode

使屏端进入IDLE模式。

uapi_lcd_exit_idle_mode

使屏端退出IDLE模式。

uapi_lcd_te_on

使能te信号。

uapi_lcd_te_off

关闭te信号。

uapi_lcd_set_brightness

设置屏幕亮度。

uapi_lcd_get_brightness

获取当前屏幕亮度。

uapi_lcd_write_reg

将数据写入屏端寄存器。

uapi_lcd_read_reg

从屏端寄存器读取数据。

初始化

uapi_lcd_init接口支持屏端复位、串口初始化、屏端初始化、送显使能等配置,主要配置流程如图1所示。

图 1 初始化配置流程图

初始化配置流程图

通信串口说明

驱动内部支持两种串口协议:QSPI协议与MIPI协议。完成硬件环境搭建后,通过uapi_lcd_info_register接口注册屏幕信息,屏蔽了底层协议的差异。

LCD 开发指引

  1. LCD信息注册:

    信息注册的参数结构:

    typedef struct {
        lcd_bus_type bus_type;
        combo_dev_cfg_t *bus_cfg;
        uint16_t x_start;
        uint16_t y_start;
        uint32_t fps;
        uint32_t lcd_id;
        uint32_t ddic_id;
        lcd_cmds_sequ *display_on_cmds;
        lcd_cmds_sequ *display_off_cmds;
        lcd_cmds_sequ *enter_idle_cmds;
        lcd_cmds_sequ *exit_idle_cmds;
        lcd_cmds_sequ *te_on_cmds;
        lcd_cmds_sequ *te_off_cmds;
        lcd_cmds_sequ *set_brightnes_cmds;
        lcd_cmds_sequ *sleep_in_cmds;
        lcd_cmds_sequ *sleep_out_cmds;
        ext_lcd_read_info lcd_id_info;
    } lcd_drv_cfg;
    

    combo_dev_cfg_t结构体定义:

    typedef struct {
        uint32_t            devno;
        short               lane_id[LANE_MAX_NUM];
        out_mode_t          out_mode;
        video_mode_t        video_mode;
        out_format_t        out_format;
        sync_info_t         sync_info;
        pck_en_t            pck_en;
        uint32_t            phy_data_rate;
        uint32_t            pixel_clk;
    } combo_dev_cfg_t;
    

    sync_info_t 结构体定义:

    typedef struct {
        uint16_t            hsa_pixels;
        uint16_t            hbp_pixels;
        uint16_t            hact_pixels;
        uint16_t            hfp_pixels;
        uint16_t            vsa_lines;
        uint16_t            vbp_lines;
        uint16_t            vact_lines;
        uint16_t            vfp_lines;
    } sync_info_t;
    

    指令集结构体定义:

    typedef struct lcd_cmd_sequ {
        uint8_t dcs_flag; /* 当前数据是否通过DCS协议命令下发,为0表示不是DCS命令 */
        uint8_t data_len; /* payload length, 小于等于64 */
        uint8_t data[MAX_DATA_LENGTH]; /* data内包含cmd和参数,有效数据最短为1(例如0x11),最长为128 */
        uint16_t delay_ms; /* 发送命令后等待时间,单位:ms */
    } lcd_cmd_sequ;
    typedef struct lcd_cmds_sequ {
        lcd_cmd_sequ *cmd; /* dsi命令数组 */
        uint16_t cmd_cnt; /* dsi命令个数 */
    } lcd_cmds_sequ;
    

    LCD信息注册示例代码:

    BUS配置信息

    /* MIPI配置参数,根据实际屏幕信息修改 */
    combo_dev_cfg_t g_mipi_config = {
        .devno = 0,
        .lane_id = {0, -1},
        .out_mode = OUT_MODE_DSI_CMD,
        .out_format = OUT_FORMAT_RGB_24BIT,
        .sync_info = {
            .hsa_pixels   = 10,   // hsa 10 pixels
            .hbp_pixels   = 10,   // hbp 10 pixels
            .hact_pixels  = 454,  // hact 454 pixels
            .hfp_pixels   = 10,   // hfp 10 pixels
            .vsa_lines    = 4,    // vsa 4 lines
            .vbp_lines    = 12,   // vbp 12 lines
            .vact_lines   = 454,  // vact 454 lines
            .vfp_lines    = 10,   // vfp 10 lines
        },
        .phy_data_rate = 480,     // 480Mbps
        .pixel_clk = 20000,       // 20000KHz
    };
    /*QSPI屏幕配置与MIP屏幕一致*/
    

    指令集

    /* display off sequence for common lcd */
    lcd_cmd_sequ g_common_cmd_display_off[] = {
        {1, 2, {0xfe, 0x00}, 0},   /* select default cmd page */
        {1, 1, {0x28}, 0},         /* display off */
        {1, 1, {0x10}, 120},       /* sleep in */
    };
    /* sleep in sequence for common lcd */
    
    const lcd_cmd_sequ g_common_cmd_sleep_in[] = {
        {1, 2, {0xfe, 0x00}, 0},   /* select default cmd page */
        {1, 1, {0x28}, 0},         /* display off */
        {1, 1, {0x10}, 120},       /* sleep in */
    };
    /* sleep out sequence */
    
    const lcd_cmd_sequ g_common_cmd_sleep_out[] = {
        {1, 2, {0xfe, 0x00}, 0},   /* select default cmd page */
        {1, 1, {0x11}, 120},       /* sleep out */
        {1, 1, {0x29}, 0},         /* display on */
    };
    /* idle in sequence */
    lcd_cmd_sequ g_common_cmd_idle_in[] = {
        {1, 2, {0xfe, 0x00}, 0},
        {1, 1, {0x39}, 0},
    };
    /* idle out sequence */
    lcd_cmd_sequ g_common_cmd_idle_out[] = {
        {1, 2, {0xfe, 0x00}, 0},
        {1, 1, {0x38}, 0},
    };
    /* te on sequence */
    lcd_cmd_sequ g_common_cmd_te_on[] = {
        {1, 2, {0xfe, 0x00}, 0},
        {1, 1, {0x35}, 0},
    };
    /* te off sequence */
    lcd_cmd_sequ g_common_cmd_te_off[] = {
        {1, 2, {0xfe, 0x00}, 0},
        {1, 1, {0x34}, 0},
    };
    /* set brightness sequence */
    lcd_cmd_sequ g_common_cmd_brightness[] = {
        {1, 2, {0xfe, 0x00}, 0},
        {1, 2, {0x51, 0xff}, 0},
    };
    /* init sequence, 根据屏端提供的手册输入 */
    lcd_cmd_sequ g_screen_init[] = {
        {1, 2, {0xfe, 0x01}, 0},
        {1, 2, {0x30, 0x43}, 0}, /* set LCD frequency to 15HZ */
        {1, 2, {0xfe, 0x00}, 0},
        {1, 2, {0x3a, 0x77}, 0},
        {1, 2, {0x53, 0x20}, 0},
        {1, 2, {0x51, 0xff}, 0},
        {0, 5, {0x2a, 0x00, 0x0e, 0x01, 0xd3}, 0},
        {0, 5, {0x2b, 0x00, 0x00, 0x01, 0xc5}, 0},
        {1, 2, {0x35, 0x00}, 0},
        {1, 1, {0x11}, 120},
        {1, 1, {0x29}, 0},
    };
    

    信息注册

    lcd_drv_cfg g_lcd_info = {
        .bus_type             = BUS_DISPLAY_MIPI, /* BUS_DISPLAY_QSPI */
        .bus_cfg              = &g_mipi_config, /* g_qspi_config */
        .x_start              = 0xe,
        .y_start              = 0,
        .fps                  = 60,
        .lcd_id               = 0xf00,
        .display_on_cmds      = &g_screen_init,
        .display_off_cmds     = &g_display_off_cmds,
        .enter_idle_cmds      = &g_idle_in_cmds,
        .exit_idle_cmds       = &g_idle_out_cmds,
        .te_on_cmds           = &g_te_on_cmds,
        .te_off_cmds          = &g_te_off_cmds,
        .set_brightnes_cmds   = &g_brightness_cmds,
        .sleep_in_cmds        = &g_sleep_in_cmds,
        .sleep_out_cmds       = &g_sleep_out_cmds,
        .lcd_id_info.reg_addr = 0x04,
        .lcd_id_info.read_len = 3,
    };
    ext_errno ret = uapi_lcd_info_register(&g_lcd_info);
    if (ret != EXT_ERR_SUCCESS) {
        ...
    }
    
  2. LCD初始化:

    ext_errno ret = uapi_lcd_init();
    if (ret != EXT_ERR_SUCCESS) {
        ...
    }
    
  3. 送显。参考VAU及DPU接口说明,本章不做说明。

  4. 设置亮度或其他控制功能,以设置亮度为例:

    uint32_t brightness = 0x80;
    ext_errno ret = uapi_lcd_set_brightness(brightness);
    if (ret != EXT_ERR_SUCCESS) {
        ...
    }
    
  5. 读写其他控制寄存器。

    • 写操作:

      lcd_cmd_sequ wdata = {0};
      wdata.data[0] = 0x3A; /* 修改像素格式 */
      wdata.data[1] = 0x77; /* 像素格式为RGB888 */
      wdata.data_len = 2;
      ext_errno ret = uapi_lcd_write_reg(&wdata, 1);
      if (ret != EXT_ERR_SUCCESS) {
          ...
      }
      
    • 读操作:

      uint8_t data;
      ext_errno ret = uapi_lcd_read_reg(0xC, &data, 1); /* 0xC读像素格式 */
      if (ret != EXT_ERR_SUCCESS) {
         ...
      }
      

VENC

接口参考:/src/middleware/utils/common_headers/venc/external/soc_venc_api.h

VENC 概述

视频编码器VENC(Video Encoder)主要对输入图像或图像序列进行编码,并输出二进制码流,支持多路、多协议、高性能、低功耗等功能。

当前Hi3322V100HiDiTingV100版本VENC支持JPEG、MJPEG协议编码。

VENC 功能描述

VENC模块具有以下功能特点:

  • 支持JPEG、MJPEG协议编码。
  • 支持最大分辨率1280×720、最小120×120。
  • 支持8bit YUV semi-planar 420。
  • 支持最多2个编码通道,不区分协议。
  • 支持输出码流缓存大小设置。
  • 支持用户主动送图和前级绑定送图。
  • 支持编码通道状态查询。
  • 支持编码私有用户数据。
  • 支持输入输出帧率设置。
  • 支持码率控制RC参数设置。
  • 支持设置序列码率过冲策略。
  • 支持设置单帧码率过冲策略。
  • 支持JPEG支持Baseline编码。

    • JPEG支持FixQP码控模式。
    • JPEG支持ECS MCU个数设置。
    • JPEG支持量化表设置。
  • 支持MJPEG编码,由JPEG Baseline构成。

    • MJPEG支持FixQP、CBR、VBR码控模式。
    • MJPEG支持ECS MCU个数设置,中断使能。
    • MJPEG支持量化表参数设置。

VENC模块提供如表1所示接口。

表 1 VENC模块接口

接口

描述

uapi_venc_module_init

编码模块初始化。

uapi_venc_module_exit

编码模块去初始化。

uapi_venc_is_standard_support

判断编码器是否支持给定协议。

uapi_venc_get_default_attr

获取编码器默认配置值。

uapi_venc_create

创建编码通道。

uapi_venc_destroy

销毁编码通道。

uapi_venc_reset

复位编码通道。

uapi_venc_start

开启编码通道接收图像。

uapi_venc_stop

停止编码通道接收图像。

uapi_venc_get_status

获取编码通道状态。

uapi_venc_send_frame

用户发送图像。

uapi_venc_send_userdata

发送用户数据。

uapi_venc_get_stream

获取编码码流。

uapi_venc_put_stream

释放码流缓存。

uapi_venc_get_attr

获取编码属性。

uapi_venc_set_attr

设置编码通道属性。

uapi_venc_get_rc_param

获取码控参数。

uapi_venc_set_rc_param

设置码控参数。

uapi_venc_get_bit_rate_overshoot

获取序列码率过冲应对策略设置。

uapi_venc_set_bit_rate_overshoot

设置序列码率过冲应对策略设置。

uapi_venc_get_frame_bits_overshoot

获取单帧码率过冲应对策略设置。

uapi_venc_set_frame_bits_overshoot

设置单帧码率过冲应对策略设置。

uapi_venc_get_jpeg_ecs

获取JPEG/MJPEG协议编码通道ecs参数。

uapi_venc_set_jpeg_ecs

设置JPEG/MJPEG协议编码通道ecs参数。

uapi_venc_get_jpeg_qt

获取JPEG/MJPEG协议编码量化表。

uapi_venc_set_jpeg_qt

设置JPEG/MJPEG协议编码量化表。

VENC 开发指引

图 1 VENC工作流程

VENC工作流程

VDEC

接口参考:/src/middleware/utils/common_headers/vdec/external/soc_vdec_api.h

VDEC 概述

VDEC(Video Decoder)即视频解码器,主要是对压缩数据例如H.264、MJPGE码流进行解码出YUV的功能。

VDEC 功能描述

VDEC模块具有以下功能特点:

  • 支持H.264解码,最高支持2个参考帧,参考帧类型为P帧/B帧。
  • 支持MJPEG解码。
  • 支持分辨率最大600×600分辨率。
  • 支持semi-planar420的输出。
  • 支持PTS纠正。
  • 支持帧率计算。
  • 解码性能:500×500@60fps(YUV420格式)。

硬件约束:

  • 首地址16Byte对齐。
  • stride16Byte对齐。

VDEC提供如表1所示接口。

表 1 VDEC接口说明

接口

说明

uapi_vdec_module_init

初始化VDEC模块。

uapi_vdec_module_exit

去初始化VDEC模块。

uapi_vdec_suspend

VDEC模块待机。

uapi_vdec_resume

VDEC模块唤醒。

uapi_vdec_create

创建解码器实例。

uapi_vdec_destroy

销毁解码器实例。

uapi_vdec_start

启动解码器。

uapi_vdec_stop

暂停解码器。

uapi_vdec_reset

复位解码器。

uapi_vdec_flush

刷新解码器。

uapi_vdec_decode

单帧解码(I帧)。

uapi_vdec_get_attr

获取实例属性。

uapi_vdec_set_attr

设置实例属性。

uapi_vdec_get_param

获取实例参数。

uapi_vdec_set_param

设置实例参数。

uapi_vdec_get_feature

获取实例特性。

uapi_vdec_get_status

获取实例状态。

uapi_vdec_get_stream

获取空闲的码流缓冲。

uapi_vdec_put_stream

发送码流缓冲。

uapi_vdec_acquire_frame

获取解码帧存。

uapi_vdec_release_frame

释放解码帧存。

uapi_vdec_register_event

注册事件。

uapi_vdec_listen_event

监测解码事件。

uapi_vdec_send_eos

发送码流结束标志。

uapi_vdec_bind_frame_buffer

绑定解码帧存。

表 2 VDEC静态实例属性表

属性名称

描述

standard

解码协议。

decode_mode

解码模式(IPB/IP/I)。

output_order

输出顺序,默认显示序输出。

frame_layout

帧存YUV布局方式。

max_stream_size

最大码流缓冲大小。

max_stream_num

最大码流缓冲个数。

extra_frame_num

额外解码缓冲帧数,不包含解码所需的最少帧存数。

error_threshold

错误阈值[0,100],当一帧的error_ratio大于错误阈值时此帧会被解码丢弃,小于等于错误阈值的帧输出,0:所有有错误的帧都会被丢弃;100:所有帧全部输出。

表 3 VDEC监测事件表

事件类型

作用

备注

EXT_VDEC_EVT_NEW_FRAME

新帧事件。

监测是否解码出帧。

EXT_VDEC_EVT_FREE_STREAM

码流空闲事件。

监测是否码流缓冲可用。

EXT_VDEC_EVT_EOS

码流结束事件。

监测是否码流解码结束。

EXT_VDEC_EVT_ERR_UNSUPPORT

不支持事件。

监测是否有不支持规格。

EXT_VDEC_EVT_ERR_FRAME

错误帧事件。

监测是否错误帧。

EXT_VDEC_EVT_ERR_DECODE

解码报错事件。

监测是否出现解码报错。

EXT_VDEC_EVT_ALL

所有事件。

监测以上所有事件。

VDEC 开发指引

图 1 VDEC工作流图

VDEC工作流图

VICAP

VICAP 概述

VICAP(Video Input Capture)为视频输入捕获模块,模块主要功能是接收不同接口、不同时序的视频数据,将捕获的图像写入PARAM。

VICAP 功能描述

VICAP模块具有以下功能特性:

  • 支持1路视频输入接口(PT0 DC时序),YUV422输入。
  • 支持1路CH写出 ,YUV422/YUV444写出。
  • 支持自建时序写出。

VICAP 开发指引

图 1 VICAP开发流程

**图 1** VICAP开发流程

注意事项

  • VAU、DPU 和 LCD 使用同一帧缓冲区时,widthheightstride、像素格式和压缩模式必须一致;任一项不匹配都可能造成花屏、颜色异常或刷新失败。
  • Surface 的物理地址必须位于硬件可访问的显存范围,并满足对应格式、压缩方式和硬件的地址对齐要求。VAU 任务未完成、DPU 仍在显示时不得复用或释放该缓冲区。
  • 屏幕时序、MIPI/QSPI 参数、初始化命令集和亮度命令必须来自实际屏幕规格书。示例中的分辨率、时钟和命令字节不能直接用于不同屏幕。
  • JPEG 仅支持 baseline、数据精度为 8 bit 的图片;解码输出的 YUV420SP stride、UV 偏移和缓冲区大小应使用解码器返回的值计算。
  • VENC、VDEC 与 VICAP 的编码规格、帧格式、缓冲区数量和事件处理要求以各自模块章节的表格、默认参数和流程图为准。

常见编译错误

现象 排查方法
找不到 soc_vau_api.hsoc_dpu_api.hsoc_jpeg_api.h 检查组件私有头文件目录是否包含对应的 /src/middleware/utils/common_headers/gpu/external 路径,并确认目标启用了图形显示配置。
gpu_at 未参与构建或 AT 中没有 GPU 命令 检查 /src/build/config/target_config/3322/target_config.py 的组件清单,以及 at_gpu_cmd/CMakeLists.txtAT_COMMAND_GPU 定义。
uapi_dpu_create_layer 参数类型不匹配 使用 ext_dpu_layer_infoext_dpu_surface,并以 /src/middleware/utils/common_headers/gpu/external/soc_dpu_type.h 的定义为准。
命令执行后无显示或显示异常 检查 LCD 初始化、面板连接、Surface 地址、颜色格式、stride、压缩模式以及 DPU/VAU DFX 输出。