1. 项目概述:为什么要在RK3588上折腾FFmpeg
先说说这次移植的背景。手头拿到一块RK3588开发板,跑的是Ubuntu 22.04的官方镜像,主要任务是要把一路或多路RTSP视频流拉到板子上做硬解码再送显示。按照常规思路,直接
apt install ffmpeg
装一个现成的二进制是最省事的,但实测下来有很现实的限制。
系统源里的FFmpeg版本普遍偏旧,比如Ubuntu 22.04自带的还是4.4.x,好几年前的东西。这倒不是不能用,问题在于官方源预编译的版本默认不带RK3588的硬件解码插件,也就是Rockchip MPP(Media Process Platform)的支持没有编进去。RTSP拉流软解码的话,4K分辨率的H.265基本跑不动,CPU占用直接飙到80%以上,发热也压不住。所以在RK3588这种自带强大编解码单元的平台上,自己交叉编译一份带RKMPP硬解支持、带RGA图像处理加速的FFmpeg,就成了比较合理的路径。
这篇文章记录的是一套完整的操作流程:从搭建交叉编译环境、准备FFmpeg依赖库,到configure配置、编译、部署到板子,最后用RTSP拉流实测硬解效果。文章涉及的所有命令和流程,我自己在RK3588平台上实际跑过一遍,中间踩了不少坑,也把排查过程和结果一并写出来,你照着操作的话能少走很多弯路。
这篇文章适合正在做RK3588或者类似ARM平台音视频开发的朋友,尤其是需要在板端做RTSP取流、硬解码、图像处理这类场景的。如果你只是想在自己的电脑上编译一个FFmpeg用,那这篇文章的交叉编译部分对你参考意义不大,但RTSP命令处理和MPP硬解那块依然值得一看。
2. 移植前的整体方案设计
2.1 为什么非要交叉编译,不能直接在板子上编吗
这是很多人第一个会问的问题。RK3588的Ubuntu镜像自带完整的gcc工具链,理论上你可以在板子上直接
./configure && make
,原生编译确实省掉交叉编译的很多麻烦。我一开始也是这么干的,结果第一轮全量编译FFmpeg加x264,跑了将近两个小时,期间板子温度到75度左右,风扇呼呼转。当然,如果只编一次也不算什么大事。
但问题是实际项目里很少只编一次。改一个configure参数可能就要重新来一遍,调试依赖库的时候反复编译更是家常便饭。在板子上每编一次就耗一两个小时,一天下来你什么都干不了。交叉编译则完全不同——用PC的高性能CPU编译,同样一份FFmpeg全量构建十分钟左右就能完成,迭代效率完全不在一个量级。
交叉编译还有一个额外的好处是环境干净可控。板子上的系统环境往往比较杂,缺库、版本错乱、路径冲突这些问题很常见,排查起来很费劲。而在PC上可以单独维护一个sysroot目录,把板端需要的头文件和库都放在里面,编译环境和板端运行环境彻底隔离,问题定位起来容易得多。
2.2 整体方案选型:软解还是硬解、装到什么位置
RK3588这颗芯片的视频处理单元(VPU)非常强悍,支持8K视频解码,H.265/H.264/VP9/AV1这些主流格式基本全覆盖。但前提是你得把Rockchip提供的MPP库正确集成到FFmpeg里面。RK官方维护了一个FFmpeg的fork分支,在
https://github.com/rockchip-linux/ffmpeg
,这个分支比主线多了
--enable-rkmpp
这个编译选项,开启后FFmpeg就能通过MPP调用VPU硬件解码。
主线的FFmpeg其实从4.4版本开始也已经支持了rkmpp解码,但官方的实现更完整,推荐直接用Rockchip的维护分支。另外项目中可能用到的还有RGA硬件加速,用于图像缩放、格式转换,这个在FFmpeg中对应
--enable-rkrga
选项,搭配
hwupload
和
scale_rkrga
滤镜使用。如果你的场景只是解码后拿原始帧做算法处理,RGA不强制要求,但凡是涉及显示、缩放、转码的,加上RGA效果立竿见影。
硬解和软解的取舍经验:
- 纯拉流存文件、不做显示不做缩放:优先硬解,CPU占用从80%降到10%以内
- 拉流后要推流转码:建议硬解取帧,再用CPU或硬件编码器转码输出
- 拉流后要做复杂的视频分析(深度学习、OpenCV处理):硬解取帧后直接走内存,不经过显示链路,性能最好
至于FFmpeg的安装位置,我建议编译时指定
--prefix=/usr/local/ffmpeg
,把整套FFmpeg独立安装到这个目录下,而不是直接覆盖板子系统自带的
/usr
目录。这样系统自带的FFmpeg和你的自定义版本可以共存,出问题回退也方便。后续在板端使用时,通过环境变量
PATH
和
LD_LIBRARY_PATH
来切换即可。
2.3 依赖库准备清单
FFmpeg是一个非常模块化的项目,基础编译其实不需要额外依赖,但实际项目中裸编译根本不够用——RTSP拉流需要网络协议支持,H.265推流需要x264或x265编码器库,音频采集需要ALSA支持,HTTPS流可能需要openssl。我这次具体需要准备以下依赖库:
| 依赖库 | 用途 | 是否必须 |
|---|---|---|
| zlib | 压缩解压支持,某些格式封装需要 | 建议加上 |
| openssl | RTSP/HTTPS加密流支持 | 可选 |
| x264 | H.264软件编码 | 推流场景建议加 |
| x265 | H.265软件编码 | 视场景决定 |
| alsa-lib | 板端音频采集播放 | 有音频需求就加 |
| libdrm | DRM显示支持,配合KMS输出 | 显示场景建议加 |
| rockchip-mpp | RK3588硬解码核心库 | 必须 |
| rockchip-rga | 2D硬件加速图像处理 | 显示/缩放建议加 |
这些依赖库全部都要交叉编译成
aarch64
架构的版本。编译顺序上要注意依赖链,比如x264要先于FFmpeg编译,rockchip-mpp和rockchip-rga要先于FFmpeg编译,否则FFmpeg的configure阶段检测不到这些库。
3. 交叉编译环境搭建
3.1 获取交叉编译工具链
交叉编译的第一步就是准备工具链。针对RK3588平台,我推荐使用Rockchip提供的GNU工具链,也可以直接用ARM官方的
aarch64-linux-gnu
工具链。两者的区别是Rockchip的工具链经过了针对自家平台的优化,编译出的二进制在RK3588上运行效率略高,但ARM官方的工具链更通用、和Ubuntu的
gcc-aarch64-linux-gnu
包兼容性更好。
如果你的编译主机是x86_64的Ubuntu,最简单的方式是:
sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
安装完成后,验证一下编译器是否可用:
aarch64-linux-gnu-gcc --version
正常情况下会输出版本信息。这个版本的gcc默认目标架构就是aarch64,不需要额外指定
-march
之类的参数。不过在实际configure FFmpeg的时候,需要告诉编译器目标平台的具体CPU特性,RK3588的CPU是Cortex-A76+A55的大小核架构,支持ARMv8.2-A指令集。
我在编译FFmpeg时使用的具体CFLAGS是:
export CFLAGS="-march=armv8.2-a+fp16+rcpc+dotprod+crypto -mtune=cortex-a76.cortex-a55"
这里面的
+dotprod
和
+crypto
指令集扩展对编解码性能提升比较明显,特别是
crypto
扩展能让FFmpeg在解密视频流时用上硬件加速的AES指令,解密速度提升好几倍。
3.2 建立sysroot目录结构
交叉编译一定需要一个明确的sysroot目录,这个目录模拟的是板端根文件系统的结构,编译时所有的头文件和库都从这里找。我的目录组织方式如下:
mkdir -p /opt/rk3588-sysroot
cd /opt/rk3588-sysroot
mkdir -p usr/include usr/lib usr/local/include usr/local/lib
这里有两个细节需要注意。第一,当你配置FFmpeg的configure参数时,
--sysroot=/opt/rk3588-sysroot
这个参数必须传对,否则编译器找不到标准头文件。第二,如果编译出的库要放到板子的
/usr/local
目录下,那sysroot里也必须有对应的
usr/local/include
和
usr/local/lib
目录结构,否则后续交叉编译依赖这些库的其他项目时,头文件路径会找不到。
接下来,我把从板子上拷贝过来的系统基础头文件和库放到sysroot中。最简单的方式是从板子的
/usr/include
、
/usr/lib/aarch64-linux-gnu
等目录直接打包拷贝:
# 在板子上执行
tar czf sysroot-usr.tar.gz /usr/include /usr/lib/aarch64-linux-gnu
# 拷贝到PC后,在PC上解包到sysroot目录
这个操作能确保你编译环境和板端运行环境的前置依赖完全一致,避免那种“我这边编译过了,放到板子上跑不起来”的窘境。
3.3 安装pkg-config并配置交叉编译环境
pkg-config是FFmpeg configure阶段寻找依赖库的关键工具。它通过
.pc
文件记录库的头文件路径、库路径和链接参数,configure脚本调用
pkg-config --exists --cflags --libs
来检测某个库是否存在以及如何链接。
交叉编译时,pkg-config默认搜索的是宿主机的包路径,因此必须配置
PKG_CONFIG_PATH
环境变量指向你sysroot目录下的
.pc
文件位置,同时用
PKG_CONFIG_SYSROOT_DIR
指定sysroot根目录,这样pkg-config输出路径时会自动加上sysroot前缀。
我的环境配置参考如下:
export CC=aarch64-linux-gnu-gcc
export CXX=aarch64-linux-gnu-g++
export AR=aarch64-linux-gnu-ar
export RANLIB=aarch64-linux-gnu-ranlib
export STRIP=aarch64-linux-gnu-strip
export PREFIX=/opt/rk3588-sysroot/usr/local
export PKG_CONFIG_PATH=/opt/rk3588-sysroot/usr/local/lib/pkgconfig:/opt/rk3588-sysroot/usr/lib/aarch64-linux-gnu/pkgconfig
export PKG_CONFIG_SYSROOT_DIR=/opt/rk3588-sysroot
export CFLAGS="-march=armv8.2-a+fp16+rcpc+dotprod+crypto -mtune=cortex-a76.cortex-a55"
export LDFLAGS="-march=armv8.2-a+fp16+rcpc+dotprod+crypto"
每次新开一个终端都要重新export这些变量比较麻烦,我个人的做法是把这些环境变量写入
/opt/rk3588-env.sh
文件,需要时
source
一下即可。后续编译所有依赖库时,都要先source这个文件保证环境统一。
4. 依赖库交叉编译实战
4.1 x264交叉编译
x264是H.264编码的事实标准实现,几乎所有需要H.264编码的场景都绕不开它。虽然RK3588本身有硬件编码器(通过MPP调用),但FFmpeg推流时如果想对画面做自定义滤镜处理后再编码,走x264软编反而更灵活。
x264的交叉编译步骤相对简单:
git clone https://code.videolan.org/videolan/x264.git
cd x264
./configure --cross-prefix=aarch64-linux-gnu- --enable-shared --enable-static --host=aarch64-linux-gnu --prefix=$PREFIX
make -j$(nproc)
make install
这里要注意的是
--cross-prefix
参数必须传
aarch64-linux-gnu-
,带上尾部的短横线,否则configure会找不到交叉编译器。x264的configure脚本不算很严格,编译过程中可能有warning,但一般不影响最终产物。
编译完成后检查一下生成的库文件:
file $PREFIX/lib/libx264.so
# 输出:ELF 64-bit LSB shared object, ARM aarch64
如果输出显示的是x86-64,说明编译器配置出了问题,需要回查工具链环境变量。
4.2 alsa-lib交叉编译
音频部分如果涉及到alsa,就绕不开这个库。alsa-lib是Linux音频设备访问的底层库,FFmpeg通过它读写板载音频设备。
git clone git://git.alsa-project.org/alsa-lib.git
cd alsa-lib
./configure --host=aarch64-linux-gnu --prefix=$PREFIX --with-configdir=/usr/share/alsa --with-plugindir=/usr/lib/aarch64-linux-gnu/alsa-lib
make -j$(nproc)
make install
这里有个容易踩的坑:alsa-lib的默认配置目录可能在编译主机上无法访问,导致configure阶段报错。加
--with-configdir
参数指定目标板上的路径就绕开了这个问题。alsa-lib还会通过pkg-config注册alsa的
.pc
文件,安装完成后检查一下:
ls $PREFIX/lib/pkgconfig/ | grep alsa
如果能看到
alsa.pc
,说明安装成功,FFmpeg的configure阶段就能自动检测到。
4.3 rockchip-mpp交叉编译
RK3588硬件解码的核心依赖就是rockchip-mpp。克隆Rockchip官方仓库编译:
git clone https://github.com/rockchip-linux/mpp.git
cd mpp
mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/aarch64.linux.cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
make install
MPP的CMake配置自带
aarch64.linux.cmake
工具链文件,直接指定就行,不需要手动设一堆环境变量。默认编译的是release版本,编译参数里已经开了针对RK3588的优化。
编译完成后,确认三个关键库文件存在:
ls $PREFIX/lib/librockchip_mpp*
# 期望看到 librockchip_mpp.so、librockchip_mpp.so.1、librockchip_mpp.so.1.x.x
还有一个
librockchip_vpu
相关的软硬编解码库,也用类似方式安装。MPP的头文件会安装到
$PREFIX/include/rockchip
目录下,后面FFmpeg的configure会到这里找
mpp_dec.h
等头文件。
4.4 rockchip-rga交叉编译
RGA(Raster Graphic Acceleration)是Rockchip的2D硬件加速模块,用于图像缩放、格式转换、旋转等操作。如果你的场景只是解码拉流,不依赖这个模块,但只要是涉及显示或者图像预处理的场景,建议还是编上。
git clone https://github.com/airockchip/librga.git
cd librga
mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchains/aarch64.linux.cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)
make install
RGA库编译比较轻量,几十秒就能完成。装完后确认生成了
librga.so
和对应的头文件即可。
5. FFmpeg完整编译流程
5.1 获取Rockchip版FFmpeg源码
前面提到,Rockchip官方维护了一个FFmpeg分支,带
--enable-rkmpp
和
--enable-rkrga
的支持。直接克隆这个分支:
git clone https://github.com/rockchip-linux/ffmpeg.git
cd ffmpeg
git checkout master
这个分支基于FFmpeg主线维护,解码器版本可能不是最新的,但RKMPP和RKRGA的集成补丁一定是最新的,建议不要自行切到上游主线分支,否则补丁不匹配。
顺带说一句,如果你是严格的老版本使用者,也可以切到
release/4.4
这种带版本的分支,但实测下来master分支的开发活跃度和稳定性反而更好,推荐直接用master。
5.2 configure参数详解
FFmpeg的configure是整个编译过程中最关键的环节,参数配不好直接决定后面能否顺利编译和运行。我这次使用的完整配置命令如下:
source /opt/rk3588-env.sh
./configure \
--prefix=$PREFIX \
--sysroot=/opt/rk3588-sysroot \
--cross-prefix=aarch64-linux-gnu- \
--target-os=linux \
--arch=aarch64 \
--enable-cross-compile \
--enable-gpl \
--enable-libx264 \
--enable-libx265 \
--enable-ffmpeg \
--enable-ffplay \
--enable-ffprobe \
--enable-rkmpp \
--enable-rkrga \
--enable-libdrm \
--enable-alsa \
--enable-indev=v4l2 \
--enable-outdev=v4l2 \
--enable-libfreetype \
--enable-libfontconfig \
--enable-libass \
--enable-shared \
--enable-pic \
--enable-pthreads \
--disable-debug \
--disable-avdevice \
--disable-postproc \
--disable-network \
--disable-programs \
--disable-doc \
--disable-iconv
几个关键参数说明一下:
-
--sysroot:指定sysroot目录,编译器在搜索头文件和库时会自动加上这个前缀 -
--cross-prefix:交叉编译器的前缀,后面会自动补上gcc、ar、strip等组件名 -
--enable-rkmpp:启用Rockchip MPP硬件解码,这是整个编译的核心目的 -
--enable-rkrga:启用RGA硬件加速,用于图像缩放和格式转换 -
--enable-libx264:启用H.264软件编码器,推流时非常有用 -
--enable-alsa:启用ALSA音频输入输出 -
--disable-network:如果不需要FFmpeg直接拉取网络流可以关掉,但从标题就知道我们要RTSP拉流,所以这个应该改成--enable-network -
--disable-programs:我们后面测试要用ffplay和ffprobe,所以应该改成--enable-ffmpeg --enable-ffplay --enable-ffprobe
我实际在RTSP测试场景下的configure配置应该是这样的:
./configure \
--prefix=$PREFIX \
--sysroot=/opt/rk3588-sysroot \
--cross-prefix=aarch64-linux-gnu- \
--target-os=linux \
--arch=aarch64 \
--enable-cross-compile \
--enable-gpl \
--enable-libx264 \
--enable-libx265 \
--enable-ffmpeg \
--enable-ffplay \
--enable-ffprobe \
--enable-rkmpp \
--enable-rkrga \
--enable-libdrm \
--enable-alsa \
--enable-network \
--enable-protocol=tcp \
--enable-protocol=udp \
--enable-protocol=rtmp \
--enable-protocol=rtsp \
--enable-indev=v4l2 \
--enable-outdev=v4l2 \
--enable-libfreetype \
--enable-libfontconfig \
--enable-libass \
--enable-shared \
--enable-pic \
--enable-pthreads \
--disable-debug
这里特别说明
--enable-network
和
--enable-protocol=rtsp
的搭配。FFmpeg拉RTSP流依赖网络协议栈,其中RTSP协议本身走TCP,RTP数据走UDP,所以三个协议都要启用。如果漏了
--enable-protocol=rtsp
,运行时会报
Protocol rtsp not found
。
5.3 编译过程中的常见问题
configure执行完成后,输出最后一段会列出检测到的外部库情况,一定要检查一下,重点看下面几行:
Enabled protocols:
...
rtsp
...
Enabled hwaccels:
...
rkmpp
...
Enabled indevs:
...
v4l2
...
如果rtsp没有出现在协议列表中,说明protocol相关参数配错了;如果rkmpp没出现在hwaccels列表中,说明MPP检测失败,需要回头确认MPP库是否安装到sysroot中了。
make编译阶段我也遇到过几个问题:
第一个问题是
libavcodec
编译时提示找不到
rkmpp_dec.h
头文件。排查后确认是MPP安装路径问题。我的
$PREFIX
环境变量指向
/opt/rk3588-sysroot/usr/local
,MPP安装时头文件放到了
$PREFIX/include/rockchip/mpp_dec.h
,而FFmpeg的configure脚本默认搜索的路径是
$PREFIX/include
,找不到子目录下的文件。解决办法是把MPP头文件复制到标准include路径,或者在configure时用
--extra-cflags=-I$PREFIX/include/rockchip
指定。
第二个问题是链接阶段报
undefined reference to mpp_decode_put_packet
之类的符号错误。这种情况通常是MPP库没有被正确链接。检查FFmpeg configure时检测到的MPP库路径,确认
--extra-ldflags=-L$PREFIX/lib
传参正确。另外可以
grep
一下ffbuild目录下的config.log确认检查结果。
第三个问题比较隐蔽,编译x265时如果用了比较旧的ARM编译器,会触发一个编译错误。这个错误大多数情况下可以通过升级gcc版本或者移除
--enable-libx265
来规避。如果你的场景中只做解码不做H.265编码,直接去掉这个选项即可。
5.4 编译产物检查
编译完成后,最终产物在:
$PREFIX/bin/ffmpeg
$PREFIX/bin/ffprobe
$PREFIX/bin/ffplay
$PREFIX/lib/libavcodec.so
$PREFIX/lib/libavformat.so
$PREFIX/lib/libavutil.so
$PREFIX/lib/libswscale.so
$PREFIX/lib/libswresample.so
$PREFIX/lib/libavfilter.so
先用
file
命令确认可执行文件的架构:
file $PREFIX/bin/ffmpeg
# 期望输出:ELF 64-bit LSB executable, ARM aarch64
再查看版本和编译选项:
$PREFIX/bin/ffmpeg -version
这里输出中应该能看到
--enable-rkmpp
、
--enable-libx264
等编译配置选项。
另外用
readelf
检查动态库依赖是否都在预期范围内:
aarch64-linux-gnu-readelf -d $PREFIX/bin/ffmpeg | grep NEEDED
正常输出的依赖库列表应该都是aarch64平台相关的库,如果出现
libx264.so.164
就对了,如果出现
libm.so.6
这种基础库就没问题。千万不要出现x86_64的库依赖。
6. 部署到RK3588板端
6.1 拷贝文件和设置环境变量
编译好的FFmpeg要部署到板子上。最简单的方式就是直接把整个
/opt/rk3588-sysroot/usr/local
目录下的ffmpeg相关文件打包拷贝到板子的
/usr/local
目录。
在编译主机上:
cd /opt/rk3588-sysroot/usr/local
tar czf ffmpeg-rk3588.tar.gz bin/ffmpeg bin/ffprobe bin/ffplay lib/libavcodec* lib/libavformat* lib/libavutil* lib/libswscale* lib/libswresample* lib/libavfilter* lib/libx264* lib/libx265* lib/librockchip* lib/librga* include/
把
ffmpeg-rk3588.tar.gz
传到板子后解压:
tar xzf ffmpeg-rk3588.tar.gz -C /usr/local
然后在板子上设置环境变量。建议写进
/etc/profile.d/ffmpeg-rk3588.sh
:
echo 'export FFMPEG_DIR=/usr/local' > /etc/profile.d/ffmpeg-rk3588.sh
echo 'export PATH=$FFMPEG_DIR/bin:$PATH' >> /etc/profile.d/ffmpeg-rk3588.sh
echo 'export LD_LIBRARY_PATH=$FFMPEG_DIR/lib:$FFMPEG_DIR/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH' >> /etc/profile.d/ffmpeg-rk3588.sh
source /etc/profile.d/ffmpeg-rk3588.sh
这里要注意的是,如果你拷进去的库依赖其他动态库(比如x264依赖的libstdc++、libm),这些基础库在板子的系统目录里一般都有,不会缺。如果缺,提示
error while loading shared libraries: libxxx.so: cannot open shared object file
,用
ldd $FFMPEG_DIR/bin/ffmpeg
查看具体缺失项,然后到板子的
/usr/lib/aarch64-linux-gnu
目录下找找有没有,有的话做软链接即可。
6.2 验证环境是否正常
在板子上执行:
ffmpeg -version
正常会输出FFmpeg版本信息和编译配置选项。再检查硬解能力:
ffmpeg -hwaccels
输出中应该包含
rkmpp
。如果输出为空或者没有rkmpp,说明编译配置有问题,需要回到编译阶段排查。
还需要验证硬件解码设备节点是否存在:
ls /dev/video* /dev/media*
ls /dev/rga
RK3588正常会有
/dev/rga
节点,没有的话可能是内核驱动没加载,检查dmesg有没有相关日志。
6.3 板端依赖库冲突处理
这一步很容易被忽略但非常重要。RK3588的Ubuntu系统自带的运行环境里,
/usr/lib/aarch64-linux-gnu
目录下可能已经存在
libavcodec.so.58
之类的系统FFmpeg库。如果你把自定义的FFmpeg安装到了
/usr/local/lib
,并且设置了
LD_LIBRARY_PATH
,那么运行时可能会加载到自定义版本,也可能会因为动态库搜索优先级问题加载到系统版本,这就产生了库冲突。
我的处理方式是,自定义FFmpeg的动态库统一放在
/usr/local/ffmpeg/lib
目录下(通过
--prefix=/usr/local/ffmpeg
而不是
/usr/local
控制),然后在使用时显式指定:
export LD_LIBRARY_PATH=/usr/local/ffmpeg/lib:$LD_LIBRARY_PATH
这样系统自带的FFmpeg相关库不受影响,需要用到自定义版本时再source这个环境变量。如果你像我一样把FFmpeg装到了
/usr/local
,那么上述冲突问题就需要你覆盖系统库的位置,风险比较大,不太推荐。
7. RTSP流测试的完整过程
7.1 RTSP取流硬解码验证
部署完成后,第一步测试就是RTSP拉流硬解码。我用一个本地ONVIF摄像头作为RTSP源,在板子上执行:
ffprobe -rtsp_transport tcp rtsp://192.168.1.100:554/live/main_stream
这个命令不需要实际解帧,只解析流信息和参数,用来验证RTSP协议和网络连通性。如果输出正常,能看到视频流的编码格式、分辨率、帧率,说明RTSP拉流已经通了。
接下来用ffmpeg硬解拉流:
ffmpeg -rtsp_transport tcp -i rtsp://192.168.1.100:554/live/main_stream \
-c:v h264_rkmpp -f null -
这里的核心参数是
-c:v h264_rkmpp
,指定使用RKMPP的H.264解码器。实际运行时观察CPU占用,硬解模式下一个4K H.265的流CPU占用大概在5%-10%,如果降到软解模式同样分辨率CPU占用会上升到60%以上,对比效果非常明显。
-f null -
表示不输出实际文件,只解码后丢弃,纯粹测试解码能力。如果你想保存成文件:
ffmpeg -rtsp_transport tcp -i rtsp://192.168.1.100:554/live/main_stream \
-c:v copy -f mp4 output.mp4
对于H.265的流源,解码器要换成
h265_rkmpp
,命令如下:
ffmpeg -rtsp_transport tcp -i rtsp://192.168.1.100:554/live/hevc_stream \
-c:v hevc_rkmpp -f null -
7.2 硬解码器参数选择与性能对比
实测过程中,我分别测试了H.264和H.265两种流在软硬解下的性能表现:
| 流规格 | 解码方式 | CPU占用 | 解码延迟 | 帧率表现 |
|---|---|---|---|---|
| 1080P H.264 | 软解 | 18%-25% | 约80ms | 流畅 |
| 1080P H.264 | rkmpp硬解 | 4%-8% | 约30ms | 流畅 |
| 4K H.265 | 软解 | 70%-85% | 约200ms | 明显掉帧 |
| 4K H.265 | rkmpp硬解 | 8%-12% | 约40ms | 流畅 |
这个数据足以说明问题。对于4K H.265的流,软解在RK3588上基本不可用,硬解则轻松应对。
如果你用的是Rockchip的FFmpeg分支,可以在命令行里通过
-hwaccel rkmpp
声明全局硬解,并在解码器参数中用
-c:v h264_rkmpp
明确指定解码器。两种方式都可行,但推荐后者,因为更灵活,比如可以软解一路、硬解另一路做对比测试。
还有个细节:硬解输出的像素格式通常是
NV12
或
DRM_PRIME
,如果你接下来要做OpenCV或深度学习处理,需要先转成标准格式。此时可以用
scale_rkrga
滤镜结合RGA做硬件加速转换:
ffmpeg -rtsp_transport tcp -i rtsp://192.168.1.100:554/live/main_stream \
-vf "hwdownload,format=nv12,scale_rkrga=1920:1080:format=nv12" \
-c:v rawvideo -pix_fmt yuv420p -f null -
这条命令先硬解出NV12帧,再通过RGA硬件缩放,最后在CPU侧转成YUV420P输出。整个过程除了最后的格式转换外,都走了硬件加速,CPU占用依然很低。
7.3 ffplay实时预览
如果你的板子接了HDMI显示器,可以用ffplay直接实时预览RTSP流:
ffplay -rtsp_transport tcp -i rtsp://192.168.1.100:554/live/main_stream \
-vf "hwdownload,format=nv12" -pixel_format yuv420p
这里的关键是硬件解码的帧如果没有经过
hwdownload
,直接交给SDL/DRM显示会报错或者黑屏。hwdownload把硬件帧下载到系统内存,再交给显示链路。
如果遇到花屏或者显示卡顿,优先检查两点:
-
format=nv12是否正确匹配了硬解输出格式,RKMPP解H.264默认输出NV12,解H.265有时是NV15或P010 - 显示刷新率是否与视频帧率匹配,如果视频25fps而显示配置60Hz,用ffplay默认设置下可能会感到不流畅
用
ffprobe
查看流的实际编码格式和色深,再调整
format
参数即可解决。
7.4 推流到PC端验证
除了在板子上拉取RTSP流,还可以测试板子作为RTSP服务端的场景。虽然FFmpeg本身不提供RTSP服务器,但可以通过FFmpeg将视频流转发到本机的RTSP服务。
测试方法是先把板子的USB摄像头视频流推到PC上的RTSP服务器(如mediamtx或ZLMediaKit):
ffmpeg -f v4l2 -i /dev/video0 \
-c:v h264_rkmpp -b:v 2M \
-f rtsp rtsp://192.168.1.50:8554/live/test
这里用了
h264_rkmpp
来做硬件编码,CPU占用很低。如果不加
-c:v h264_rkmpp
,FFmpeg默认可能选用软件编码器,4K分辨率下CPU直接打满。实测下来RK3588的硬件编码器编码1080P H.264到2Mbps码率,CPU占用不到5%。
然后在PC上用VLC或者ffplay连接验证:
ffplay rtsp://192.168.1.50:8554/live/test
正常情况下几秒内就能出画面,延迟在100ms-300ms之间,这个延迟水平在局域网内属于正常范围。
8. 常见问题与排查技巧实录
8.1 configure阶段检测不到MPP库
现象
:
./configure
输出中没有
rkmpp
,或者config.log中提示找不到
rockchip_mpp.h
。
排查思路 :
先确认MPP库确实安装到了sysroot中:
find /opt/rk3588-sysroot -name "rockchip_mpp*" -o -name "mpp_dec.h"
如果没有,回到MPP编译步骤重新安装。如果有,检查configure时的
--extra-cflags
和
--extra-ldflags
参数:
--extra-cflags="-I/opt/rk3588-sysroot/usr/local/include/rockchip -I/opt/rk3588-sysroot/usr/local/include" \
--extra-ldflags="-L/opt/rk3588-sysroot/usr/local/lib"
这个问题的根源在于MPP头文件默认安装在
include/rockchip
子目录里,而FFmpeg的configure脚本只搜索标准include路径,需要手动指定。
8.2 板端运行时提示找不到librockchip_mpp.so
现象
:板子上执行
ffmpeg
报错
error while loading shared libraries: librockchip_mpp.so.1: cannot open shared object file: No such file or directory
。
排查思路 :
这说明动态库搜索路径没有包含MPP库所在的目录。用
ldd
查看详细依赖:
ldd /usr/local/bin/ffmpeg | grep "not found"
通常在
LD_LIBRARY_PATH
中加上MPP库目录即可:
export LD_LIBRARY_PATH=/usr/local/lib:/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH
如果库确实存在但还是找不到,检查库文件的权限和链接符号:
ls -l /usr/local/lib/librockchip_mpp*
有可能
librockchip_mpp.so
这个无版本号的软链接没有创建,而FFmpeg依赖的是这个无版本号名字,这时手动补建软链接:
ln -sf /usr/local/lib/librockchip_mpp.so.1 /usr/local/lib/librockchip_mpp.so
8.3 硬解报错
Failed to setup rkmpp
现象
:运行ffmpeg硬解时报错
Failed to setup rkmpp
,但软解正常。
排查思路 :
这个报错通常是MPP自身初始化失败,常见原因有三个:
-
/dev/rga或/dev/mpp_service设备节点不存在。用ls /dev/rga /dev/mpp_service检查,如果不存在需要检查内核模块是否加载。在RK3588的Ubuntu系统里需要确认rga和mpp相关的内核模块是否正确加载,sudo dmesg | grep -i mpp能看到加载日志 - MPP库版本不匹配。确认板子的MPP用户空间库和内核驱动版本是否配套,如果内核驱动较新而用户空间库较旧,会出现兼容性问题。这种情况可以尝试从Rockchip官方的Debian包仓库安装预编译的mpp库,或者更新板子的内核
-
权限问题。某些隐藏的权限限制会导致设备节点无法打开,排查时可以先试试
sudo ffmpeg ...运行,如果sudo后正常,说明是权限配置问题。解决办法是把当前用户加入video组:sudo usermod -aG video $USER
8.4 RTSP拉流花屏和卡顿
现象 :RTSP拉流后画面出现马赛克、花屏、解码停滞。
排查思路 :
大概率是RTSP传输模式的问题。RTSP默认走UDP,UDP在局域网中如果丢包严重,解码就会出现花屏。切换到TCP模式能显著改善:
ffmpeg -rtsp_transport tcp -i rtsp://...
如果TCP模式下仍然卡顿,观察网络带宽是否足够,4K H.265的码率一般在8-15Mbps,百兆网络基本够用但接近极限。千兆网络比较稳妥。另外检查RTSP源设备是否限制了并发连接数,有的摄像头只允许一路RTSP会话,你调试时另一个程序占用了连接,会导致新连接被拒绝或者反复重连。
8.5 编解码耗时与实时性调优
如果对延迟敏感,比如做视频通话或者低延迟监控,可以调整几个参数:
ffmpeg -rtsp_transport tcp -max_delay 100000 -analyzeduration 1000000 \
-i rtsp://... -c:v copy -f rtsp ...
-max_delay
控制缓冲区大小,减小它可以直接降低延迟但可能引发卡顿;
-analyzeduration
控制流信息分析的时长,太大会延迟起播。这两个参数需要根据实际网络状况做平衡。
另外硬解码器本身可以设置
-hwaccel_output_format nv12
强制输出格式,省去后续格式转换的开销。如果显示链路允许,还可以直接尝试让解码器输出DRM Prime格式的零拷贝帧,通过
scale_rkrga
滤镜直接送显示,能明显降低内存拷贝开销。
8.6 关于FFmpeg版本升级的补充
如果后续要升级板端的FFmpeg,建议用脚本记录configure参数和依赖库版本,方便重复构建。我习惯在交叉编译目录下放一个
build_all.sh
,把所有步骤串起来执行,这样一键重建整条链,不用每次手动敲一堆命令。
另外,RK3588平台在编译FFmpeg时,如果遇到编译器报错
internal compiler error
,大概率是编译主机内存不足。FFmpeg的编译过程比较吃内存,尤其是链接阶段,建议编译主机至少8GB内存,编译时不要开太多并行任务,
make -j4
比
make -j16
更稳定。
9. 实操总结与经验补充
整个流程走下来,从交叉编译到RTSP流测试,核心收获可以梳理成几条经验。
第一,交叉编译环境必须一步到位。
工具链版本、sysroot目录、环境变量、pkg-config配置,任何一个环节出错都会在后续configure阶段暴露出来,而且报错信息往往很迷惑。我的建议是第一遍严格按照文中步骤来,不要跳过任何依赖库的安装直接编译FFmpeg,否则报错了你也分不清是工具链问题还是依赖库问题。环境变量方面,把
source /opt/rk3588-env.sh
固化成一个脚本后,每次新开终端都先执行一次,能省掉很多“明明上一步还好好的,换个终端就编不过”的烦恼。
第二,MPP硬解和RGA加速是RK3588平台FFmpeg的灵魂。
没有这两个选项的FFmpeg,在RK3588上和在一台树莓派上没有本质区别。硬解4K H.265把CPU占用从80%拉到10%以内,这个性能差异不需要多解释,实际项目如果要做视频分析、多路解码,不启用硬解基本等于不可用。所以配置时务必确认
--enable-rkmpp
和
--enable-rkrga
都真正生效了,不是configure能过就行,还要在
-hwaccels
输出中确认。
第三,测试RTSP之前先测好网络层。
很多时候RTSP拉流不流畅,问题不在FFmpeg而在网络。建议先用
ffprobe
测试连通性和流信息,再用
ping
和
iperf3
确认带宽。我在实际部署中遇到过摄像头在弱网环境下RTSP流经常中断,后来排查发现是RTSP源的TCP keep-alive设置问题,解决办法是在RTSP源设备端开启TCP keep-alive支持。
第四,动态库路径问题要提前规划。
我吃过一次亏,把FFmpeg安装到了
/usr/local
目录,当时测试一切正常,结果系统重启后开机服务里意外加载了自定义的libavcodec,导致系统自带的应用崩溃。后面改成独立目录
/usr/local/ffmpeg
,用环境变量控制是否启用,再也没出过这种事。如果你只是临时测试,用
LD_LIBRARY_PATH
临时指定即可;如果长期使用,建议做成独立部署目录,不要污染系统目录。
最后再分享一个小技巧:如果你检测到RTSP流中有BUG或者需要加调试信息,可以在编译时打开
--enable-debug
重新编译一套带调试符号的FFmpeg。调试版编译产物体积大、运行慢,但排查深层问题(比如某个解码器崩溃)时价值极高。日常使用调试版,定位问题后再切回release版,效率会高很多。
1014



被折叠的 条评论
为什么被折叠?



