3、开发环境搭建:交叉编译工具链、CUDA/OpenCL驱动、FFmpeg源码编译
说实话,嵌入式GPU开发最让人头疼的,往往不是算法本身,而是环境搭建。我见过太多人卡在这一步,代码写好了,编译不过,或者跑不起来。今天咱们就把这事彻底捋清楚。
3.1 交叉编译工具链——你得先让电脑听懂嵌入式的话
交叉编译,说白了就是在一台电脑上(x86架构),生成另一台设备(ARM架构)能运行的二进制文件。你想想看,嵌入式设备性能有限,不可能在上面装个Visual Studio慢慢编译,对吧?
我个人习惯用Linaro提供的GCC工具链。以NVIDIA Jetson系列为例,它用的是aarch64架构,所以我们需要aarch64-linux-gnu-gcc。
核心思路:工具链版本必须与目标设备的glibc版本匹配。版本不匹配,编译出来的程序要么跑不起来,要么跑起来就崩。
安装步骤其实不复杂:
# 下载Linaro GCC 7.3.1(我推荐这个版本,兼容性好)
wget https://releases.linaro.org/components/toolchain/binaries/7.3-2018.05/aarch64-linux-gnu/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz
# 解压到指定目录
tar -xvf gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz -C /opt/
# 配置环境变量
export PATH=/opt/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin:$PATH
export CC=aarch64-linux-gnu-gcc
export CXX=aarch64-linux-gnu-g++
我的经验:我曾经在项目里直接用Ubuntu源里的gcc-aarch64-linux-gnu,结果编译出来的FFmpeg在Jetson Nano上跑起来就段错误。查了两天,最后发现是工具链版本太新,生成的代码对老内核不兼容。从那以后,我坚持用Linaro官方版本。
验证工具链是否安装成功:
aarch64-linux-gnu-gcc --version
# 输出类似:aarch64-linux-gnu-gcc (Linaro GCC 7.3-2018.05) 7.3.1 20180425
3.2 CUDA/OpenCL驱动——GPU的"开机密码"
嵌入式GPU和桌面GPU不一样。桌面GPU你装个驱动就行,嵌入式GPU的驱动往往和系统镜像绑在一起。以NVIDIA Jetson为例,它用的是JetPack SDK,里面包含了CUDA、cuDNN、TensorRT等全套工具。
嗯,这里要注意:JetPack版本和硬件型号必须对应。比如Jetson Nano最高支持JetPack 4.6,而Jetson Orin可以上JetPack 5.x。
| 硬件平台 | 推荐JetPack版本 | CUDA版本 | OpenCL版本 |
|---|---|---|---|
| Jetson Nano | 4.6.4 | 10.2 | 1.2 |
| Jetson TX2 | 4.6.4 | 10.2 | 1.2 |
| Jetson Xavier NX | 5.1.2 | 11.4 | 3.0 |
| Jetson Orin NX | 5.1.2 | 11.4 | 3.0 |
安装JetPack其实很简单,但有个坑:
# 下载JetPack安装包
wget https://developer.nvidia.com/downloads/embedded/jetpack-4-6-4_sdks
# 运行安装脚本
sudo ./JetPack_4.6.4_Linux_JETSON_NANO_TARGETS.run
# 安装完成后,验证CUDA
nvcc --version
# 验证OpenCL
clinfo | grep "Platform Name"
我曾经踩过的坑:有次我直接在Jetson上运行apt install nvidia-cuda-toolkit,结果装的是桌面版的CUDA,和嵌入式GPU的驱动不兼容。折腾了一整天,最后只能刷机重来。记住:嵌入式GPU的CUDA必须用JetPack自带的版本,别自己乱装。
对于OpenCL,Jetson平台默认是支持的。但如果你用的是其他嵌入式GPU(比如ARM Mali),可能需要单独安装OpenCL驱动:
# 以Mali GPU为例
sudo apt install mesa-opencl-icd
# 验证
clinfo
3.3 FFmpeg源码编译——把GPU加速"焊"进去
FFmpeg默认是不带GPU加速的。你得自己编译,把CUDA和OpenCL的支持加进去。说白了,就是给FFmpeg"开光"。
我个人习惯用源码编译,因为这样能精确控制哪些功能要、哪些不要。嵌入式设备存储空间有限,能省则省。
先安装依赖:
# 基础依赖
sudo apt install build-essential yasm nasm libx264-dev libx265-dev
# CUDA相关依赖(Jetson上已经自带)
# 确认CUDA路径
export CUDA_PATH=/usr/local/cuda-10.2
然后下载FFmpeg源码:
wget https://ffmpeg.org/releases/ffmpeg-4.4.1.tar.bz2
tar -xvf ffmpeg-4.4.1.tar.bz2
cd ffmpeg-4.4.1
配置编译选项——这是最关键的一步:
./configure \
--prefix=/opt/ffmpeg-gpu \
--enable-cross-compile \
--cross-prefix=aarch64-linux-gnu- \
--arch=aarch64 \
--target-os=linux \
--enable-cuda \
--enable-cuvid \
--enable-nvenc \
--enable-nonfree \
--enable-libx264 \
--enable-libx265 \
--enable-opencl \
--extra-cflags="-I/usr/local/cuda-10.2/include" \
--extra-ldflags="-L/usr/local/cuda-10.2/lib64"
重点说明:
--enable-cuda:开启CUDA支持,用于GPU编解码--enable-cuvid:开启NVIDIA硬件解码器--enable-nvenc:开启NVIDIA硬件编码器--enable-opencl:开启OpenCL支持,用于后处理滤镜
编译和安装:
make -j4
make install
验证编译结果:
/opt/ffmpeg-gpu/bin/ffmpeg -hwaccels
# 输出应该包含:cuda、cuvid、nvenc、opencl
我的经验:编译FFmpeg时,-j4参数要根据你的CPU核心数调整。Jetson Nano是4核,用-j4刚好。如果你用Jetson Orin(12核),可以开到-j8甚至-j12。但别开满,留一个核心给系统,否则容易卡死。
测试一下GPU加速是否生效:
# 使用CUDA硬件解码
/opt/ffmpeg-gpu/bin/ffmpeg -hwaccel cuda -i input.mp4 -f null -
# 使用OpenCL滤镜
/opt/ffmpeg-gpu/bin/ffmpeg -i input.mp4 -vf "hwupload,opencl=init,unsharp_opencl" output.mp4
如果看到输出里显示"Using CUDA for hardware decoding",那就说明成功了。
3.4 环境验证——别等到跑起来才发现问题
我建议你写一个简单的测试脚本,把整个环境串起来验证一遍:
#!/bin/bash
# 环境验证脚本
echo "=== 1. 检查交叉编译工具链 ==="
aarch64-linux-gnu-gcc --version || exit 1
echo "=== 2. 检查CUDA ==="
nvcc --version || exit 1
echo "=== 3. 检查OpenCL ==="
clinfo | grep "Platform Name" || exit 1
echo "=== 4. 检查FFmpeg GPU支持 ==="
/opt/ffmpeg-gpu/bin/ffmpeg -hwaccels | grep -E "cuda|opencl" || exit 1
echo "=== 环境搭建完成! ==="
最后提醒一句:嵌入式GPU的环境搭建,最忌讳的就是"差不多就行"。工具链版本、CUDA版本、FFmpeg版本,差一个数字都可能出问题。我建议你把每个组件的版本号记下来,贴在工位上。出了问题,先对版本号。
好了,环境搭好了,下一章咱们就开始写真正的GPU编解码代码了。到时候你会发现,前面这些折腾都是值得的。