杰理 SDK 文档中心
首页
首页
  • 概述与快速开始

    • SDK 总览与芯片能力
    • 环境搭建与编译构建
    • 烧录与固件升级
    • 文档与版本资源
  • 应用与示例方案

    • demo 示例工程
    • WiFi 摄像头方案 (wifi_camera)
    • WiFi 音箱方案 (wifi_soundbox)
    • WiFi 婴儿监护方案 (wifi_bbm)
    • 公共应用模块库
    • 示例代码库 (example)
  • 系统架构与平台

    • 总体架构与工程分层
    • 系统启动与运行框架
    • 芯片驱动与板级适配
    • 设备管理与文件系统
    • 系统工具库与算法
  • 音频子系统

    • 音频框架与处理节点
    • 音频编解码与音效
    • 播放器与录音器
    • 语音交互与 AI 唤醒
    • LE Audio 与蓝牙音频
    • 音频调试与歌词
  • 视频与显示子系统

    • 摄像头驱动与 ISP
    • 视频编码与图像处理
    • 显示与 GPU 加速
    • 屏幕镜像 (screen_mirror)
  • 无线连接与网络

    • 蓝牙协议栈 (双模蓝牙)
    • WiFi 协议栈与配网
    • 网络协议栈
    • 云平台与 IoT 协议
  • UI 子系统

    • LVGL 集成与应用
    • UI 工程与工具链
  • 配置系统

    • 功能配置
    • 板级配置
    • 网络与蓝牙配置
    • 音频配置与提示音
  • 工具与测试

    • 产测与射频测试工具
    • 固件升级与更新机制
    • 调试与日志工具
  • 硬件参考设计

    • 原理图参考设计
    • 芯片数据手册

视频编码与图像处理

本文档介绍 AC792N SDK 中视频编码与图像处理子系统的整体架构与实现,涵盖 YUV 数据获取、JPEG 硬件编解码(encoder_one_jpeg / decoder_one_jpeg)、JPG 转 AVI、Logo 叠加、运动检测、视频录制/显示、网络 AVI 播放以及 LVGL 视频转图片等能力的源码级说明。

Purpose and Scope

本页面覆盖 sdk/apps/common/video/ 目录及 sdk/apps/wifi_bbm/stream/ 中与视频编解码、图像处理直接相关的实现:

  • JPEG 硬件编码:encoder_one_jpeg.c 中的 yuv_enc_jpeg() 应用层 API
  • JPEG 解码:decoder_one_jpeg.c 中的 decoder_one_jpeg() 示例流程
  • 配套的图像处理模块:get_yuv_data、jpg2avi、logo_show、motion_detect
  • 上层应用入口:user_video_disp / user_video_rec、video_dec_demo / video_rec_demo
  • 网络 AVI 播放器:net_avi_player/
  • LVGL 视频转图片工具:lvgl_v8/src/extra/jl_extra/libs/video_to_images/
  • 视频通话/流媒体管线:sdk/apps/wifi_bbm/stream/video_pipeline*、video_stream_*、video_call

以下主题属于其他页面,不在本文展开:USB 摄像头 Host 驱动(usb_video.c)、LVGL UI 画面本身、Wi-Fi 通信协议栈细节。有关系统启动流程请参见系统启动相关页面。

Overview

在 AC792N 这类带硬件 JPEG 编解码器的 SoC 上,视频/图像处理链路通常是:

  1. 从摄像头(或文件、网络)取得原始 YUV 数据;
  2. 使用硬件 JPEG 编码器把 YUV 压缩为 JPG 图片(asm/jpeg_codec.h 提供的 jpeg_encode_one_image);
  3. 反过来,把 JPG 解码为 YUV(jpeg_decode_image_info + jpeg_decode_one_image),再经 yuv_to_rgb.h / yuv_soft_scalling.h 转成 RGB 或缩放后送显示;
  4. 在录制场景中,多帧 JPG 由 jpg2avi 封装为 AVI 文件;播放场景则使用 net_avi_player 从本地/网络流解析 AVI 并逐帧解码。

该子系统的设计意图非常明确:把重计算(JPEG 编解码)交给硬件,应用层只负责缓冲管理、文件 I/O 与格式封装。因此应用层 API(如 yuv_enc_jpeg)的入参设计围绕"内存缓冲 + 分辨率 + 质量"展开,返回值为实际编码字节数,方便调用方直接落盘。

Architecture

flowchart TD
    subgraph sg_Source["数据源层"]
        Cam["摄像头/YUV 文件"]
        SD["SD 卡 JPG/AVI"]
        Net["网络流 (curl)"]
    end

    subgraph sg_Codec["编解码核心 (asm/jpeg_codec.h 硬件加速)"]
        Enc["jpeg_encode_one_image"]
        Dec["jpeg_decode_image_info / jpeg_decode_one_image"]
    end

    subgraph sg_App["应用层封装 (sdk/apps/common/video)"]
        EncDemo["encoder_one_jpeg.c / yuv_enc_jpeg"]
        DecDemo["decoder_one_jpeg.c / decoder_one_jpeg"]
        GetYuv["get_yuv_data.c"]
        Jpg2Avi["jpg2avi.c"]
        Logo["logo_show.c"]
        Motion["motion_detect.h"]
        Rec["user_video_rec / video_rec_demo"]
        Disp["user_video_disp / video_dec_demo"]
        AviPlayer["net_avi_player (avi_parse/avi_player)"]
    end

    subgraph sg_Ext["扩展集成"]
        LvglImg["lv_video_to_images (LVGL)"]
        WifiStream["video_pipeline / video_stream_* (wifi_bbm)"]
    end

    Cam --> GetYuv
    GetYuv --> EncDemo
    EncDemo --> Enc
    SD --> DecDemo
    DecDemo --> Dec
    Dec -->|"YUV/RGB565 输出"| Disp
    EncDemo -->|"JPG 字节"| Jpg2Avi
    Jpg2Avi --> SD
    Net --> AviPlayer
    AviPlayer --> Dec
    Logo --> Disp
    Motion --> Rec
    Rec --> EncDemo
    DecDemo --> LvglImg
    EncDemo --> WifiStream

各组件职责:

  • asm/jpeg_codec.h(位于 SDK 芯片库,未在本仓库应用层):硬件 JPEG 编解码的统一接口,提供 jpeg_encode_one_image、jpeg_decode_image_info、jpeg_decode_one_image、jpeg_codec_init 等函数。应用层所有编解码最终都落到这里。
  • encoder_one_jpeg.c:把 YUV 数据编码为 JPG 的应用层示例,核心 API 为 yuv_enc_jpeg(),自动根据数据长度推断 YUV444/422/420 采样格式,并支持"仅 Y 数据"模式(JPEG_ENC_ONLY_Y)。
  • decoder_one_jpeg.c:把 JPG 文件解码为 YUV(或 RGB565)的应用层示例,先解析图像信息(宽/高/采样格式),再按格式申请 YUV 缓冲。
  • get_yuv_data.c:负责从视频设备获取 YUV 数据(配合 video_ioctl.h / video.h)。
  • jpg2avi.c:把连续 JPG 帧封装为 AVI 容器,用于录像文件生成。
  • logo_show.c:把 Logo 图像叠加到视频画面,属于图像后处理。
  • motion_detect.h:运动检测接口,用于录像触发等场景。
  • net_avi_player/:本地/网络 AVI 播放器,包含 avi_parse(AVI 容器解析)、avi_player(播放控制)、curl_get_data(网络取流)、pipeline_jpeg_dec(JPEG 解码流水线)与 play_demo(示例入口)。
  • video_pipeline.c / video_stream_*(wifi_bbm 工程):视频通话与流媒体录制/接收/请求的管线实现,把上述编解码能力接入 Wi-Fi 应用。

注:除 encoder_one_jpeg.c、decoder_one_jpeg.c 外,上表多数模块的角色依据目录结构与头文件名归纳;其内部详细 API 请直接阅读对应源文件。

核心实现:JPEG 编码

yuv_enc_jpeg() — YUV 转 JPG 应用层 API

encoder_one_jpeg.c 第 32-90 行实现了最核心的编码入口。其设计要点在于根据 yuvdata_size 与 width*height 的关系自动判定采样格式:

  • 数据长度 = width * height * 3 → JPG_SAMP_FMT_YUV444
  • 数据长度 = width * height * 2 → JPG_SAMP_FMT_YUV422
  • 其他(默认)→ JPG_SAMP_FMT_YUV420;若长度恰好等于 width * height(只有 Y 平面),则内部申请 width*height + width*height/4 的缓冲,并把 U/V 平面填充为 0x80(中性色),从而用同一套接口兼容灰度源数据。
//应用层使用YUV编码JPG API
//yuvdata:YUV或Y数据地址,yuvdata_size:数据长度
//jpg_buf:JPG图片编码预先存放数据缓存区,jpg_buf_size:JPG数据缓存区长度(30K-100K:<=320*240->30K,480*320->40K,640*480->50K,1280*720*90K)
//width/height:YUV/Y数据源的分辨率宽高, q_val:图片编码质量:0-13
//返回值:0失败,非0:JPG实际编码的图片数据长度(用户调用该函数后保存JPG数据为jpg_buf,长度为返回值)
int yuv_enc_jpeg(char *yuvdata, int yuvdata_size, char *jpg_buf, int jpg_buf_size, int width, int height, int q_val)
{
    struct jpeg_encode_req req = {0};
    int err = 0;
    char only_y = 0;
    char yuv_alloc = 0;
    char *yuv = yuvdata;

    if (yuvdata_size == width * height * 3) {
        req.format = JPG_SAMP_FMT_YUV444;
    } else if (yuvdata_size == width * height * 2) {
        req.format = JPG_SAMP_FMT_YUV422;
    } else {
        req.format = JPG_SAMP_FMT_YUV420;
        only_y = (yuvdata_size == width * height) ? 1 : 0;
        if (only_y) {
            yuv = malloc(width * height + width * height / 4);
            yuv_alloc = 1;
        }
    }
    if (!yuv) {
        printf("err yuv buf not enough\n");
        return 0;
    }
    req.q = q_val;
    req.data.buf = (u8 *)jpg_buf;
    req.data.len = jpg_buf_size;
    req.width =  width;
    req.height = height;
    req.y = (u8 *)yuv;
    req.u = req.y + req.width * req.height;
    req.v = req.u + req.width * req.height / 4;

#if JPEG_ENC_ONLY_Y
    only_y = 1;
#endif
    if (only_y) {
        if (yuv != yuvdata) {
            memcpy(yuv, yuvdata, width * height);
        }
        memset(yuv + width * height, 0x80, width * height / 4);
        req.v = req.u;
    }
    if (jpeg_encode_one_image(&req) == 0) {
        printf("jpeg_encode_one_image ok\n");
        err = req.data.len;
    } else {
        printf("jpeg_encode_one_image err\n");
    }
    if (yuv_alloc) {
        free(yuv);
    }
    return err;
}

Source: encoder_one_jpeg.c

实现要点:

  1. 硬件请求结构体 struct jpeg_encode_req:q(质量 0-13)、data.buf/len(输出 JPG 缓冲)、width/height、y/u/v 三个平面指针、format 采样格式。U 平面紧跟 Y 之后(偏移 width*height),V 平面在 U 之后偏移 width*height/4,这是 YUV420 的典型内存布局。
  2. JPEG_ENC_ONLY_Y 编译宏:SDK 允许只编码 Y 平面以节省带宽/内存;开启后强制走 only_y 路径,V 平面指针直接指向 U(req.v = req.u),UV 数据为 0x80 中性色。
  3. 返回值语义:jpeg_encode_one_image 成功返回 0 时,req.data.len 被硬件/驱动回写为实际编码字节数,因此函数返回该值;失败返回 0。调用方只需把 jpg_buf 前 返回值 字节写盘即可。
  4. 内存纪律:only_y 路径内部 malloc 的临时 YUV 缓冲在退出前必须 free,避免在长时间录像循环中泄漏内存。

encoder_one_jpeg() — 文件级编码示例

encoder_one_jpeg(const char *path, int width, int height) 演示了从 SD 卡读取 YUV 文件、申请输出缓冲(100KB,见第 99 行注释"一般 50K-100K,不够再加大")、调用 yuv_enc_jpeg、再把 JPG 写回磁盘的完整流程。文件头部的 path_change_suf_name() 工具函数负责把源文件后缀替换为目标后缀(如 .yuv → .jpg),该函数在编码与解码示例中都被复用。

void encoder_one_jpeg(const char *path, int width, int height)
{
    int err = 0;
    FILE *fd = NULL;
    int yuv_size;
    char name[64];
    int pix = width * height;
    int jpg_size = 100 * 1024;//指定分辨率编码的数据长度缓冲区(一般50K-100K,不够再加大)
    char *jpg_img = NULL;
    char *yuvbuf = NULL;
    fd = fopen(path, "rb");
    if (fd == NULL) {
        printf("no file name :%s \n", path);
        goto exit;
    }
    yuv_size = flen(fd);//读取jYUV数据长度
    yuvbuf = malloc(yuv_size);//申请YUV内存块
    if (!yuvbuf) {
        printf("yuvbuf malloc err ...\n");
        goto exit;
    }
    if (fread(yuvbuf, yuv_size, 1, fd) != yuv_size) {//读取YUV数据
        printf("read file yuv_size err ...\n");
        goto exit;
    }
    fclose(fd);
    fd = NULL;
    //4.申请编码的JPEG的内存缓冲区,一般50K-100K即可
    /* VGA图片大小说明:低等质量(小于20K),中等质量(20K-40K),高质量(大于40K,极限70K)

Source: encoder_one_jpeg.c

该示例使用 goto exit 统一做错误清理(关闭文件、释放缓冲),这是嵌入式 C 代码中常见的"单出口"错误处理模式,保证任何失败路径都不会泄漏资源。

核心实现:JPEG 解码

decoder_one_jpeg() — 文件级解码示例

decoder_one_jpeg(const char *path) 演示解码流程,顺序为:打开文件 → 读取 JPG 数据 → jpeg_codec_init() 初始化硬件 → jpeg_decode_image_info() 解析图像信息 → 按采样格式计算 YUV 缓冲大小 → 申请缓冲 → 解码 → 按 JPEG_SAVE_FILE_YUV 选择保存 YUV 或 RGB565。

    jpeg_codec_init();
    //2.解析jpeg信息获取源JPEG YUV数据类型和分辨率
    struct jpeg_image_info info = {0};
    info.input.data.buf = buf;
    info.input.data.len = lenth;
    if (jpeg_decode_image_info(&info)) {
        printf("jpeg_decode_image_info err %s\n", path);
        goto exit;
    }
    width = info.width;
    height = info.height;
    pix = width * height;
    switch (info.sample_fmt) {
    case JPG_SAMP_FMT_YUV444:
        ytype = 1;
        printf("jpeg yuv444, pix : %dx%d \n", width, height);
        break;//444
    case JPG_SAMP_FMT_YUV420:
        ytype = 4;
        printf("jpeg yuv420, pix : %dx%d \n", width, height);
        break;//420
    default:
        ytype = 2;
        printf("jpeg yuv422, pix : %dx%d \n", width, height);
        break;//422
    }

    //3.申请YUV内存缓存
    len = pix + pix / ytype * 2;
    if (!yuv) {
        yuv = malloc(len);
        if (!yuv) {
            printf("yuv malloc err len : %d , width : %d , height : %d \n", width, height, len);
            goto exit;
        }

Source: decoder_one_jpeg.c

实现要点:

  1. 两阶段解码:先用 jpeg_decode_image_info 拿到 struct jpeg_image_info(含 width、height、sample_fmt),再据此精确计算 YUV 缓冲长度 pix + pix/ytype*2(YUV444 为 3 倍像素、YUV422 为 2 倍、YUV420 为 1.5 倍)。这种设计避免了盲目按最大尺寸申请内存,对 SRAM 有限的 MCU 至关重要。
  2. 采样格式映射:ytype 取值 1/2/4 分别对应 444/422/420,直接参与缓冲大小计算,默认分支把未知格式按 422 处理,保证解码不因未知格式而崩溃。
  3. 输出格式可配:文件头 #define JPEG_SAVE_FILE_YUV 1 决定保存为 YUV(1)还是 RGB565(0),配合 yuv_to_rgb.h 完成色彩空间转换。

Core Flow

编码流程

sequenceDiagram
    participant App as 应用调用方
    participant YuvEnc as yuv_enc_jpeg()
    participant Codec as jpeg_codec 硬件驱动
    participant Mem as 内存缓冲

    App->>YuvEnc: 传入 yuvdata/yuvdata_size/width/height/q_val
    YuvEnc->>YuvEnc: 按 yuvdata_size 判定采样格式 (444/422/420)
    alt 只有 Y 数据 (only_y)
        YuvEnc->>Mem: malloc(w*h + w*h/4)
        YuvEnc->>Mem: 复制 Y 平面, UV 填充 0x80
    end
    YuvEnc->>Codec: 填充 jpeg_encode_req (y/u/v/q/format)
    Codec->>Codec: 硬件压缩 YUV → JPG
    Codec-->>YuvEnc: 成功返回 0, req.data.len 回写实际长度
    YuvEnc-->>App: 返回 JPG 字节数 (失败返回 0)
    App->>App: 将 jpg_buf[0..len] 写盘/发送

解码流程

sequenceDiagram
    participant App as 应用调用方
    participant Dec as decoder_one_jpeg()
    participant Info as jpeg_decode_image_info
    participant Hw as jpeg_decode_one_image
    participant File as SD 卡

    App->>File: fopen(path) / flen / fread 读取 JPG
    Dec->>Info: 解析 width/height/sample_fmt
    Info-->>Dec: 图像信息
    Dec->>Dec: 计算 len = pix + pix/ytype*2 并 malloc
    Dec->>Hw: 解码 YUV 数据
    Hw-->>Dec: YUV 缓冲填充完成
    Dec->>Dec: 按 JPEG_SAVE_FILE_YUV 保存 YUV 或转 RGB565
    Dec-->>App: 输出文件/返回结果

相关图像处理模块

除编解码核心外,sdk/apps/common/video/ 目录还提供一系列配套能力(角色依据文件命名与目录结构归纳):

YUV 数据获取 — get_yuv_data.c/h

负责从视频设备(摄像头)取回 YUV 帧,供编码/显示链路使用。它与 video_ioctl.h、video.h 协同,是 yuv_enc_jpeg 的典型上游数据来源。录像类应用(user_video_rec、video_rec_demo)通常按"取帧 → 编码 → 落盘"的节奏循环。

JPG 转 AVI — jpg2avi.c/h

把连续编码得到的 JPG 帧按 AVI 容器格式封装成录像文件。设计动机是:JPEG 硬件编码速度快、单帧独立可解码,但裸 JPG 序列不便播放;AVI 容器提供索引与帧边界信息,使 PC 播放器可直接顺序播放。user_video_rec 录像流程即为"逐帧 yuv_enc_jpeg → jpg2avi 写帧"。

Logo 叠加 — logo_show.c/h

把 Logo 位图叠加到待显示/待编码的画面中,属于图像后处理(composition)。通常在解码/缩放之后、送显示之前调用,用于产品品牌标识。

运动检测 — motion_detect.h

提供运动检测接口,用于事件触发型录像(检测到运动才编码落盘),可显著降低存储与功耗开销。

视频录制/显示上层入口

  • user_video_rec.c、video_rec_demo.c:录像应用,展示"取 YUV → 编码 JPG → AVI 封装"的完整链路。
  • user_video_disp.c、video_dec_demo.c:显示应用,展示"解码 JPG → YUV → RGB565 → 显示"的完整链路,并演示 yuv_soft_scalling 缩放与 yuv_to_rgb 转换的用法。

网络 AVI 播放器 — net_avi_player/

  • avi_parse.c/h:解析 AVI 容器(RIFF 块、帧索引),不依赖文件系统类型。
  • curl_get_data.c/h:基于 curl 的网络取流,支持边下边播。
  • avi_player.c/h + pipeline_jpeg_dec.c/h:播放控制与 JPEG 解码流水线,play_demo.c 为示例入口。该子目录把"网络传输 → 容器解析 → 硬件解码 → 显示"串成一条完整管线,是视频通话/监控类功能的基础。

LVGL 视频转图片 — lv_video_to_images.h / diff_image_to_video_types.h

位于 lvgl_v8/src/extra/jl_extra/libs/video_to_images/,把视频帧转换为 LVGL 可用的图片资源(配合差分图类型定义),用于 UI 侧的动画/预览展示。

Wi-Fi 视频流管线 — video_pipeline.c/h、video_stream_*(wifi_bbm 工程)

video_pipeline 把采集、编码、发送、接收、解码、显示组装为可配置管线;video_stream_recorder、video_stream_recv、video_stream_request 分别对应录像、接收、请求三类流行为;video_call.c 提供视频通话模式入口。它们与 usb_video.c(USB 摄像头 Host)共同支撑实时音视频类应用。

配置选项

选项类型默认值说明
JPEG_ENC_ONLY_Y宏(encoder_one_jpeg.c)未定义定义后强制只编码 Y 平面,UV 填充 0x80,节省编码带宽
JPEG_SAVE_FILE_YUV宏(decoder_one_jpeg.c)1解码输出保存格式:1 保存 YUV,0 保存 RGB565
q_valyuv_enc_jpeg 参数调用方指定编码质量 0-13,值越大质量越高、体积越大
jpg_buf_sizeyuv_enc_jpeg 参数调用方指定JPG 输出缓冲长度,建议:≤320×240→30K、480×320→40K、640×480→50K、1280×720→90K
yuvdata_sizeyuv_enc_jpeg 参数调用方指定决定采样格式:w*h*3→YUV444、w*h*2→YUV422、w*h→仅 Y(YUV420)

API Reference

int yuv_enc_jpeg(char *yuvdata, int yuvdata_size, char *jpg_buf, int jpg_buf_size, int width, int height, int q_val)

把 YUV(或仅 Y)数据编码为 JPG。位于 encoder_one_jpeg.c。

参数:

  • yuvdata (char*):YUV 或 Y 数据源地址
  • yuvdata_size (int):源数据长度,用于推断采样格式
  • jpg_buf (char*):JPG 输出缓冲
  • jpg_buf_size (int):输出缓冲长度(见上表建议值)
  • width / height (int):图像分辨率
  • q_val (int):编码质量 0-13

返回: 实际编码的 JPG 字节数(非 0);失败返回 0。

说明: 内部调用 jpeg_encode_one_image(asm/jpeg_codec.h)。only_y 模式会临时 malloc YUV420 缓冲并在返回前释放。

void encoder_one_jpeg(const char *path, int width, int height)

文件级编码示例:读取 YUV 文件 → 编码 → 写 JPG 文件。位于 encoder_one_jpeg.c。

参数:

  • path (const char*):源 YUV 文件路径
  • width / height (int):YUV 分辨率

返回: 无(结果打印到日志)。

int decoder_one_jpeg(const char *path)

文件级解码示例:读取 JPG 文件 → 解析信息 → 解码 → 保存 YUV/RGB565。位于 decoder_one_jpeg.c。

参数:

  • path (const char*):JPG 文件路径

返回: 0 成功;非 0 失败(文件不存在、缓冲申请失败、解析失败等,均打印错误日志)。

硬件接口(asm/jpeg_codec.h,芯片库提供)

函数作用
jpeg_codec_init()初始化 JPEG 编解码硬件
jpeg_encode_one_image(struct jpeg_encode_req *req)单帧 YUV → JPG 编码,成功返回 0,req.data.len 回写实际长度
jpeg_decode_image_info(struct jpeg_image_info *info)解析 JPG 头信息(宽/高/采样格式),成功返回 0
jpeg_decode_one_image(...)单帧 JPG → YUV 解码

上述硬件接口的具体签名以 SDK 芯片库头文件为准,本仓库应用层仅通过 #include "asm/jpeg_codec.h" 使用。

失败模式与边界情况

源码中体现的失败处理模式如下:

场景处理方式来源
文件不存在打印 no file name 并 goto exit 返回 0encoder_one_jpeg.c
内存申请失败打印 xxx malloc err,goto exit 统一清理decoder_one_jpeg.c
文件读取长度不匹配fread 返回值校验,失败即退出encoder_one_jpeg.c
JPG 信息解析失败jpeg_decode_image_info 非 0 → 打印并退出decoder_one_jpeg.c
硬件编码失败jpeg_encode_one_image 非 0 → 返回 0 表示失败encoder_one_jpeg.c
未知采样格式解码默认按 YUV422(ytype=2)处理,避免崩溃decoder_one_jpeg.c

边界情况:

  • YUV420 缓冲布局:yuv_enc_jpeg 假设 U 平面紧邻 Y(偏移 w*h)、V 平面偏移 w*h + w*h/4。调用方传入非连续三平面数据时需自行拷贝为连续布局。
  • 输出缓冲不足:JPG 编码质量高、画面复杂时可能超出 jpg_buf_size,jpeg_encode_one_image 将失败。示例注释给出的 30K-100K 建议值正是为了规避该问题;更高分辨率(如 720P)需按 90K 以上配置。
  • 仅 Y 输入的色度填充:only_y 路径把 UV 填 0x80(128,即中性灰),编码结果可正常解码显示,但画面为灰度效果——这是设计上"省内存换灰度"的取舍。

并发与资源竞争:

  • 示例代码为单线程串行流程,jpeg_codec_init() 与编解码调用之间没有加锁;若多任务同时调用编解码(例如录像与预览并发),需要在应用层互斥,避免硬件编解码器被抢占。
  • 所有临时缓冲(YUV、JPG、AVI 封装)均来自 malloc,在内存紧张的 MCU 上需评估峰值占用:录像链路典型同时存在"YUV 帧缓冲 + JPG 输出缓冲 + AVI 写缓冲"三份内存。

性能与运维注意事项

  • 硬件加速是性能基石:编解码由硬件完成(asm/jpeg_codec.h),应用层瓶颈在内存拷贝(memcpy/memset)与文件 I/O,而非 CPU 计算。only_y 模式通过减少色度数据处理量进一步提升帧率。
  • 缓冲大小即帧率上限:JPG 输出缓冲越大,单帧可容纳的细节越多;但过大的 malloc 会抬高内存峰值。建议按目标分辨率上限配置(见配置表),并在初始化时一次性分配、循环复用。
  • 文件 I/O 建议:录像/播放场景使用 flen/fread/fwrite 流式读写;网络播放(net_avi_player)则依赖 curl_get_data 的分块拉取,避免整文件缓存。
  • 日志输出成本:示例在编码/解码关键点大量使用 printf,量产代码建议按日志级别裁剪,避免在高帧率循环中拖慢吞吐。

扩展点

  1. 新图像格式支持:decoder_one_jpeg 的 switch (info.sample_fmt) 分支是扩展点——在 JPG_SAMP_FMT_YUV444/420 之外增加新格式时,只需补充 ytype 映射与缓冲计算。
  2. 输出格式切换:JPEG_SAVE_FILE_YUV 宏与 yuv_to_rgb.h 提供 YUV/RGB565 双输出,可进一步扩展为 RGB888 等。
  3. 流水线组装:video_pipeline.c(wifi_bbm)把采集/编码/传输/解码/显示抽象为可配置管线,新增"录制到云端"等能力时可在该层插入新节点,复用 yuv_enc_jpeg 与 net_avi_player 的组件。
  4. UI 侧集成:lv_video_to_images 允许把视频帧转为 LVGL 图片资源,是 UI 预览类功能的扩展入口。

测试情况

本仓库 sdk/apps/common/video/ 下的 encoder_one_jpeg.c、decoder_one_jpeg.c、video_rec_demo.c、video_dec_demo.c、net_avi_player/play_demo.c 本身就是可独立运行的演示程序(demo),承担了"功能验证"角色:它们演示了 API 的正确调用顺序(初始化 → 编解码 → 落盘/显示)与预期的日志输出(jpeg_encode_one_image ok、jpeg yuv444, pix : WxH 等),可作为回归验证的基线。未发现独立的自动化单元测试文件。

Related Links

  • encoder_one_jpeg.c — YUV 编码 JPG 应用层实现
  • decoder_one_jpeg.c — JPG 解码 YUV 应用层实现
  • get_yuv_data.c — YUV 数据获取
  • jpg2avi.c — JPG 帧封装 AVI 容器
  • logo_show.c — Logo 叠加
  • user_video_rec.c / user_video_disp.c — 录像与显示上层应用
  • net_avi_player/ — 网络 AVI 播放器
  • lv_video_to_images.h — LVGL 视频转图片
  • video_pipeline.c — wifi_bbm 视频流管线
  • usb_video.c — USB 摄像头 Host(兄弟页面主题)
Prev
摄像头驱动与 ISP
Next
显示与 GPU 加速