Hi3516CV500 SDK开发:交叉编译环境与MPP视频通路排障指南
简介:这是基于海思芯片的官方软件开发套件,适用于安防监控、智能家居等视频处理类嵌入式项目的开发与维护场景。资源完整收录底层驱动、中间件、应用示例与开发文档,并附带编译、烧录、调试等工具链,可支撑从环境搭建、外设控制、音视频编解码到固件烧录的完整流程。压缩包共二十九个文件,以yaffs2、jffs2、ubifs等根文件系统镜像为主,覆盖不同闪存布局与文件系统格式,另有内核镜像、引导程序以及若干源码模块,能够满足不同硬件配置的选型需要,整体约九百三十七兆字节。目前已有七百八十一人浏览学习,适合有一定嵌入式基础、需要移植或适配海思平台的开发者。借助这批镜像与源码,可以按目录快速定位驱动、文件系统与系统初始化逻辑,复用现成配置,减少底层适配和文件系统选型上的重复劳动,同时也可对照模块源码深入理解芯片外设与多媒体处理链路。
1. Hi3516CV500 SDK 是什么:一套从 uboot 到编码库的全栈资源
如果你正在做基于 Hi3516CV500 这颗芯片的视频采集、编码或安防类产品,那么 Hi3516CV500_SDK_V2.0.0.3.tgz 几乎是绕不开的第一份资料。它不是单纯的一堆源码,而是把操作系统、驱动、媒体库、示例程序打包在一起的一整套可运行系统。拿到它,意味着你不需要从零开始移植内核和驱动,直接在这套基线上开发业务即可。
这套资源解决的核心问题,是把「一颗裸芯片」变成「一个能出画面的完整产品」:SDK 里自带 uboot、内核、根文件系统、交叉编译工具链,以及负责视频输入、处理、编码的媒体平台库 MPP 和对应的 sample 示例代码。适合正在做摄像头方案评估、板卡调试、图像处理 Demo 验证的嵌入式开发者。下面按照我实际拆包和编译的顺序,把这套资源的关键环节和踩过的坑一次说清楚。
2. 解包第一件事:目录结构、版本配套与 release note 的三个关键信息
拿到 tgz 压缩包后,很多人习惯性先解压再看,这没错,但解压后别急着编译,先花十几分钟把目录和文档过一遍,能省掉后面一整天的排障时间。
2.1 解压与总览:先认出 osdrv、mpp、doc 三大块
解压命令很简单,建议放在 Linux 主机上进行,不要传到 Windows 再解压上传,那样符号链接和文件权限会丢,后面编译直接翻车。
# 在 Linux 主机上解压 SDK
tar -xzf Hi3516CV500_SDK_V2.0.0.3.tgz
执行完后进入解压目录,用 ls -l 看一层结构。不同版本目录命名略有差异,但核心通常包含这三大块: osdrv 、 mpp 、 doc 或 docs 。其中 osdrv 是操作系统驱动工程,里面包含 opensource、uboot、kernel、rootfs、tools 等子目录,最终用来生成完整的系统镜像; mpp 是媒体处理平台,包含头文件、链接库、ko 模块和 sample 示例源码; doc 或 docs 目录放的是开发文档。
这三个目录的功能边界要明确: osdrv 解决「系统能不能跑起来」, mpp 解决「画面能不能进得来、编码能不能出得来」。业务代码基于 mpp 的 sample 修改,但系统级的 uboot 参数、内核配置、根文件系统打包,都得回到 osdrv 里改。我一般还会在解压后先 du -sh * 看一眼各目录大小,如果某个目录体积异常,十有八九是压缩包传输不完整。
2.2 release note 怎么看:工具链版本、patch 与主机环境
解压目录里通常有一份 release note 或发布说明文档,这可能是整个包里最容易被忽略、但信息密度最高的文件。拿到手先确认三个信息:交叉编译工具链的具体名字和版本,SDK 要求的 Linux 主机环境,以及有没有需要预先打入的 patch。
# 查找 release note 类文档
find . -iname "*release*" -o -iname "*readme*" -o -iname "*patch*"
我一般会先用这条命令把文档和补丁文件都找出来,patch 文件名里一般带有版本号,比如针对某次安全更新或硬件版本适配的补丁。以这套 SDK 的编译前提为例,常见配套是 arm-himix100-linux 工具链,主机推荐 64 位 Ubuntu 系统。如果 release note 里写了某几个 patch 必须在编译前打,就老老实实按顺序打入,跳过 patch 直接编译的后果通常是编译到一半莫名报错,而那些报错信息在搜索引擎里根本查不到对应场景。
提示: release note 里如果写了「推荐使用 Ubuntu 某个版本」,别用更新的系统去硬刚。工具链对主机 glibc 版本有依赖,盲目追新会让后面每一步编译都变得不可控。
2.3 文档目录里优先看哪三份
文档不用全看,但有三类是值得先读的:媒体处理开发参考(讲 MPP 整体架构和 API 流程)、平台 FAQ 或已知问题列表、编译和烧录指南。媒体处理开发参考解决的是「VI、VPSS、VENC 之间的关系是什么、初始化顺序怎么定」这类整体认知问题,这比单独看 sample 代码重要得多。FAQ 则直接记录了这个芯片型号上常见的坑,很多第 5 章遇到的现象,其实 FAQ 里早就写过。
编译和烧录指南解决的是「命令怎么敲、镜像怎么下」的问题,不同板子的启动介质不同,nand、nor、sd 对应的编译参数和烧录方式都不一样,这些细节只能以文档为准,不要凭经验直接套用其他芯片型号的命令,芯片不同,DDR 基地址和 addr 参数可能完全不一样。
3. 交叉编译环境与 osdrv 编译:工具链装好、一条命令出系统镜像
整个 SDK 里第一个真正动手的地方是交叉编译环境。环境不对,后面 osdrv 和 sample 的编译全部会卡在同一个地方:找不到编译器,或者编译器版本不匹配。
3.1 工具链安装:交叉编译器解压到 /opt,再 source 环境脚本
工具链一般在 SDK 的 tools 目录下,或者随包以独立 tgz 形式提供。常见的是 arm-himix100-linux 工具链压缩包,解压目标通常是 /opt/himix100 或类似路径,具体以包内说明为准。下面是典型安装流程:
# 解压工具链到 /opt,以实际文件名为准
tar -xzf arm-himix100-linux.tar.gz -C /opt
解压完成后,工具链目录里通常带一个环境设置脚本,路径类似 /opt/himix100/environment-setup-arm-himix100-linux 。运行它,编译器路径就进 PATH 了:
source /opt/himix100/environment-setup-arm-himix100-linux
# 验证交叉编译器可用
arm-himix100-linux-gcc -v
如果 gcc -v 能正常打印版本信息,环境就通了。注意每次打开新的终端窗口都需要重新 source,否则 PATH 里没有工具链路径。我个人的习惯是直接把这行 source 写进 ~/.bashrc ,免得反复忘记。还有一种做法是手动 export PATH=/opt/himix100/bin:$PATH ,效果等价,但 source 环境脚本通常还会顺带设置交叉编译常用的 CFLAGS、CROSS_COMPILE 变量,对后续编译更省事。
3.2 编译 osdrv:整条 Makefile 命令的参数拆解
工具链就绪后,进入 osdrv 目录编译系统镜像。常见做法是在 osdrv 目录下执行 make,并传入工具链前缀和芯片型号。具体参数以 SDK 文档为准,下面给出典型形式:
cd osdrv
make OSDRV_CROSS=arm-himix100-linux CHIP=hi3516cv500
这条命令会依次编译 uboot、kernel 和根文件系统。 OSDRV_CROSS 指定交叉编译器的前缀, CHIP 指定芯片型号,编译系统根据它来选择对应的内核配置和设备树。如果你的板子启动介质是 SPI NOR,可能还要额外传 BOOT_MEDIA 参数,取值一般是 nor、nand 或 sd;不传时按 SDK 默认介质处理。
第一次编译时间大概 15 到 30 分钟,取决于主机性能。看到终端滚动刷屏不要慌,只要没有 Error 、 No rule to make target 之类的关键词,就让它跑完。我经历过的最长一次编译是因为虚拟机的磁盘 I/O 太差,整个 osdrv 编了四十分钟,但只要日志在推进就不是死掉。
3.3 编译产物与烧录镜像:pub 目录里哪些文件要拿来用
编译完成后,产物会集中在 osdrv 的 pub 目录里。这里只需要关注几个关键文件,其他中间产物不用管:
| 镜像文件 | 用途 |
|---|---|
| u-boot-hi3516cv500.bin | uboot 引导程序,烧写到启动介质起始位置 |
| uImage_hi3516cv500 | 内核镜像,uboot 通过网络或存储读取后引导 |
| rootfs 相关镜像文件 | 根文件系统,启动后挂载为 / |
| 其他如 logo、设备树 bin 文件 | 按烧录指南决定是否需要烧写 |
上板前要把这三类镜像按照烧录文档的地址表烧进对应位置,地址表通常在 SDK 文档或 release note 里。烧录地址写错是最常见的「起不来」原因,而且表现很迷惑:uboot 打印正常,内核加载到一半卡住。看到这种情况,优先怀疑镜像烧录地址和内核启动参数不匹配。
3.4 识别编译是否正常:日志里的关键字与常见假死
有同事在 osdrv 编译时遇到过一种情况:终端停在某一行很久不动,看着像死掉,其实是根文件系统在做 squashfs 或 jffs2 打包,这一步对大文件比较慢。判断是不是真死,可以看 CPU 占用率,或者按回车确认终端是否还响应。另一个容易误判的点是编译过程中出现大量 warning,比如内核编译常见的 unused variable ,这些不影响产物,不要因为 warning 多就中断编译。
如果编译中途确实失败,先看最后一个 Error 前后五行日志,绝大多数问题出在工具链没找到、主机缺少依赖库、patch 没打全这三类原因上。不要直接重新 make,先把 make clean 做掉再编,否则旧产物会干扰判断。
4. 跑通第一条视频通路:sample 编译、NFS 上板与参数调整
系统镜像能启动后,下一步就是把 mpp 里的 sample 编译出来,上板跑通 VI 到 VPSS 再到 VENC 的媒体链路。这条链路通了,才真正说明这套 SDK 在你的板子上是可用的。
4.1 mpp 库与 sample 的编译顺序:先出库,再出可执行文件
sample 依赖 mpp 的静态库或动态库,所以编译顺序不能反。通常先进 mpp 目录编译出库文件,再进 sample 子目录编示例程序。常见流程如下:
# 编译 mpp 库,生成 lib 目录下的媒体库文件
cd mpp
make
# 编译 sample,生成可执行文件
cd sample
make
第一遍编译时可以在 sample 目录只编一个目标,比如 sample_venc,避免一次编出所有可执行文件浪费时间。 make 时注意观察链接命令,确认它确实用的是刚才这套交叉编译器,而不是主机自带的 gcc。链接阶段如果报找不到 libmpp 之类,多半是库的搜索路径没指到 mpp/lib 目录,在 sample 的 Makefile 里查一下 LIBPATH 或 -L 参数即可。
编译产物通常在 sample 目录下直接生成,文件名类似 sample_venc 。用 file sample_venc 确认这是 ARM 架构的可执行文件,不是 x86 的,这一步能避免把宿主机的程序直接拷到板子上跑。
4.2 网络启动上板:bootargs 环境变量与 NFS 根文件系统
调试阶段最省事的运行方式是 NFS 根文件系统启动:内核从 TFTP 下载,根文件系统挂载到主机上的某个目录,sample 编译完直接拷进该目录就能运行,不用反复烧写 flash。uboot 里的典型配置如下:
# 在 uboot 提示符下设置
setenv serverip 192.168.1.10
setenv ipaddr 192.168.1.66
setenv bootargs 'mem=64M console=ttyAMA0,115200 root=/dev/nfs nfsroot=192.168.1.10:/home/nfs_rootfs,v3,tcp rw ip=192.168.1.66:192.168.1.10:192.168.1.1:255.255.255.0::eth0:on'
tftp 0x82000000 uImage_hi3516cv500
bootm 0x82000000
这里面 mem 是内核可用内存大小, console 是串口参数, root=/dev/nfs 指明根文件系统走 NFS, nfsroot 后面是主机 IP 与导出目录, ip= 后面依次是本机 IP、服务端 IP、网关、掩码。加载地址 0x82000000 是这类芯片常见的 uboot 内存加载地址,具体以你自己的 uboot 打印为准。
NFS 启动时,主机上要提前把根文件系统解压到对应导出目录,并配置好 NFS 服务。板子启动后进入系统,把 sample_venc 用 scp 或 NFS 直接拷到 /mnt 下,加执行权限运行:
# 板端执行,先看 usage
./sample_venc -h
带 -h 跑一下,确认帮助信息正常输出,再按实际需求选参数运行。到这里,SDK 部署验证就完成一大半了。
4.3 修改编码参数:分辨率、码率、帧率从 sample 源码的哪个结构体改起
sample 里的编码参数并不是配置文件,而是一组静态结构体,定义在 sample_venc 的源码里。平时调参数要改源码后重新 make,再替换板端可执行文件。比如设置通道编码属性的地方,通常能看到码率类型、目标码率、帧率、GOP 长度和 profile 等级:
| 参数项 | 常见取值 | 说明 |
|---|---|---|
| u32Profile | 0 或 1 | 0 对应 baseline,1 对应 main profile |
| u32BFrameNum | 0 | 0 表示不含 B 帧,编码延迟更低 |
| u32FrameRate | 25 或 30 | 帧率,注意和 sensor 输出匹配 |
| u32BitRate | 按分辨率估算 | CBR 模式下决定码流大小 |
| enRcMode | CBR 或 VBR | CBR 码率稳定,VBR 画质优先 |
分辨率通常由 VENC 通道的图片属性结构体控制,长宽和编码格式都在里面。改完以后,重新在 sample 目录执行 make,再覆盖到板端对应路径,重启 sample 就能看到新参数生效。经常有人改完忘记重新编译,直接跑旧二进制,然后怀疑参数没写对,这属于典型的低级消耗,编译和拷贝两步都确认一次再运行。
5. 常见问题排查:六个踩坑记录,从编译环境到板端运行失败
以下六类问题,是围绕这套 SDK 最容易遇到的。每一条都按「现象 → 原因 → 处理」说明,你在复现时可以直接对照。
5.1 arm-himix100-linux-gcc: command not found
现象: 执行编译命令时终端直接提示找不到交叉编译器,或者提示 arm-himix100-linux-gcc: command not found 。
原因: 工具链没有安装,或者安装了但 PATH 环境变量里没有包含工具链的 bin 路径。大多数情况下是新开的终端窗口没有 source 环境脚本,之前的 source 只在那个终端里生效。
处理: 先检查工具链目录是否存在,再手动 source 后验证:
find /opt -maxdepth 2 -name "*himix*" -type d
source /opt/himix100/environment-setup-arm-himix100-linux
which arm-himix100-linux-gcc
which 能输出路径就说明环境正常。建议把 source 写进 ~/.bashrc ,以后每次开终端自动生效。
5.2 编译 osdrv 时 crt1.o: No such file
现象: 编译过程中 GCC 本身工作正常,但链接阶段报找不到 crt1.o 、 crti.o ,或者提示 cannot find -lgcc 。
原因: 工具链是 32 位或按 32 位方式链接的,而主机是 64 位系统且缺少 32 位运行库;也可能是主机 glibc 版本太新,老工具链不兼容。
处理: 在 Ubuntu 18.04 上安装 32 位兼容库通常能解决:
sudo apt-get install lib32z1 lib32gcc1 lib32stdc++6
如果用的是 Ubuntu 20.04 及以上版本,装完库可能仍然报错,那多半是工具链和系统默认库的冲突。别在一个系统上死磕,直接开一个干净容器或者用旧版系统编译 osdrv,把编译产物拿到当前环境继续用。这不算绕路,而是这套老工具链的实际情况。
5.3 mkfs.jffs2 command not found
现象: osdrv 编译到根文件系统打包阶段,报 mkfs.jffs2: command not found 或者 mkimage: command not found 。
原因: 主机缺少打包根文件系统所需的工具,这些工具属于 mtd-utils 和 u-boot-tools,默认系统没有安装全。
处理: 安装依赖后重新执行打包:
sudo apt-get install mtd-utils u-boot-tools
装完后回到 osdrv 目录,不需要全部重新编译,找到打包相关的 make 目标重新执行即可。整个依赖问题是最省心的一种,装完就好。
5.4 板端运行 sample 提示 Insufficient memory
现象: sample 启动时打印类似 Insufficient memory 或 MPP 初始化报错,创建 VI 或 VENC 通道失败。
原因: 内核启动参数里给 MPP 预留的内存空间不足。视频通道多、分辨率高、码率缓冲大时,默认预留可能不够用。这类问题在部分文档里被描述成「MMZ 空间不足」,本质上是启动参数里那段内存配置的值太小。
处理: 修改 uboot 的 bootargs,在 mem= 后面按需求调整 MPP 预留内存的大小,常见做法是在 bootargs 里追加 mmz= 参数并指定起始地址和大小。具体地址要看 release note 和内存布局文档,不要照抄别的芯片型号的值。调完重启板子再运行 sample,逐次加大直到创建通道成功。
5.5 第二次运行 sample 时提示 Device or resource busy
现象: 第一次运行 sample 能正常出流,Ctrl+C 退出后再运行,初始化阶段直接报设备忙或打开设备失败。
原因: sample 是直接操作 MPP 设备的程序,上一次退出没有完整走模块释放流程,驱动里的设备节点仍被占用。如果你用 ps 看,可能会发现旧进程没退干净。
处理: 先确认并结束残留进程,然后复位设备再跑:
# 板端执行
ps -ef | grep sample_venc | grep -v grep
kill -9 <PID>
如果 kill 不解决,直接 reboot 板子。embedded 调试板频繁调参时,reboot 是最快的后悔药。为了避免亲手制造这个问题,退出 sample 尽量用程序内部的退出命令而不是 kill -9 ,给 MPP 释放流程一点时间。
5.6 NFS 启动卡在 VFS: Unable to mount root fs
现象: 板子上电后内核打印 VFS: Unable to mount root fs via NFS ,卡在挂载根文件系统这一步。
原因: bootargs 里 nfsroot 写的路径、协议版本或 IP 参数有误,主机 NFS 服务没有配置好,或者 export 目录和实际路径不匹配。这是网络启动最常见的问题,百分之八十是 nfsroot 少写了 v3,tcp 或 ip= 字段没写全。
处理: 在主机端先检查导出路径:
exportfs -v
sudo cat /etc/exports
确认导出目录存在且权限是 rw,insecure 后,再核对 uboot 的 bootargs。注意 nfsroot=192.168.1.10:/home/nfs_rootfs 后面必须跟上 ,v3,tcp ,NFS 协议版本不匹配时会直接挂载失败。改完 bootargs 重新 bootm 即可,不需要重烧镜像。
6. 进阶用法:快速验证编码通路与二次开发的几个习惯
系统能跑起来、sample 能出流之后,剩下的是效率和稳定性的问题。这里分享一个快速验证编码通路的技巧,以及我从这套 SDK 迁移到业务代码时的经验。
6.1 快速验证编码链路:循环编码与码流落盘
每次改动硬件或参数后,最想确认的就是「编码链路是不是真的健康」。我的做法是先把 sample 的循环编码打开,让它连续编码一段时间,把输出码流直接落盘。
在 sample 源码里找到编码帧数或循环次数的控制位置,把循环次数设成一个大值或设为无限循环,重新编译后运行,让程序持续编码两三分钟,然后检查生成的文件大小和帧率是否匹配。比如 25 帧 1080p 的 H.265 码流,设定码率 2Mbps,跑两分钟文件大小应该在 30MB 左右。文件大小差太多,说明编码器实际输出码率和配置不一致,多半是参数没真正生效。
这个验证法不用依赖任何图形界面,只要能看到文件大小和帧率对得上,链路就是通的。跑完记得把循环次数改回业务需要的值,避免调试版本直接当正式版本发出去。
6.2 从 sample 到业务代码:初始化顺序和 buffer 管理的三点注意
第一,MPP 初始化顺序不要随意调整。先系统初始化,再创建 VI、VPSS、VENC 各模块,最后启动通道,这个顺序在 MPP 开发参考里有明确流程图。我见过有人为了让画面更快出,把 VPSS 创建放到 VI 启动之后,结果运行十分钟后内存报错,查了半天才发现是初始化顺序问题。
第二,buffer 管理要理解「池」的机制。VPSS、VENC 各自的 buffer 从公共池里分配,通道多、分辨率高时,池大小和块数量必须提前算好。帧率不稳时,先加 buffer 数量,别急着拉高码率。
第三,sensor 配置要和实际硬件匹配。sample 里默认的 sensor 型号不一定是你板子上的型号,跑不起来时先确认板端 sensor 的型号,再找对应的配置或驱动替换。这个替换过程不是改一个参数那么简单,但至少先从 sample 的 usage 参数里看看它支持哪些类型。
6.3 建立自己的基线验证流程
从最初拿到这套 SDK 到现在,我养成了一个固定习惯:完整解压后,先把 release note 里的 patch 清单抄下来;再在干净环境里编译 osdrv 和 sample;上板后直接用 NFS 方式跑一遍 sample_venc,确认出流正常。这个「解压 → 打 patch → 编译 → 跑 sample」的过程,我只在第一次做全量,之后每次拿到新版本 SDK 都强制走一遍完整基线。
这个习惯看起来笨,但实际排障时非常有用。很多「玄学」问题最终都能回到某个环节没做干净:patch 没打、环境没 source、旧产物没清掉、参数没重新编译。从那以后我每次都会先确认编译时间和产物时间戳,再决定要不要继续排查。希望帮到你。
更多推荐

所有评论(0)