简介:这套librtmp源码包是专为需要在Linux环境下进行交叉编译的开发者准备的完整工程资源。librtmp是rtmpdump的核心组件,提供RTMP协议底层实现;该资源实测可在Linux主机上为ARM等目标架构构建库文件,解决嵌入式实时流媒体应用的移植需求。压缩包共106个文件、约4.35MB,以86个h头文件、5个c源文件及6个lib库文件为主,同时包含Makefile、vcxproj工程文件和COPYING授权说明等,结构清晰,便于直接查看和修改编译配置。内容涵盖rtmp.c、amf.c、hashswf.c、parseurl.c、log.c等关键模块,可帮助理解RTMP握手、消息解析、AMF编解码及URL处理等实现细节。目前已有1422人学习下载,适合Linux开发者和嵌入式工程师参考,尤其适用于需要定制或移植librtmp以接入RTMP直播服务的项目。
1. 为什么要在 Linux 下交叉编译 librtmp:一个推流设备的血泪起点
做嵌入式直播推流的人,迟早会遇到同一个坎:设备端是 ARM 架构,跑的是 Linux,但你的开发机是 x86,上面跑着 Ubuntu。直接在 ARM 板子上编 librtmp 也不是不行,但交叉编译才是正路。librtmp 是 RTMP 协议实际上的事实标准客户端库,几乎所有开源推流方案都绕不开它,无论是做摄像头直播、无人机图传还是边缘计算盒子,最终都要把视频流通过 RTMP 推到媒体服务器上。这篇文章就是把我自己踩过的交叉编译流程完整走一遍,从工具链选型、依赖库处理、Makefile 参数到最终在目标板上跑起来,每一步都写清楚参数和坑在哪,给正在做嵌入式流媒体开发的人一份能直接照着干的参考。适合手里有具体推流任务、打算在 Linux 环境下把 librtmp 编到 ARM 平台的开发者。
2. 交叉编译前的三个准备:工具链、依赖库与配置参数
2.1 为什么依赖库必须自己先交叉编译一遍
librtmp 本身不是一个完全自包含的库,它依赖 OpenSSL 提供加密和握手能力,依赖 zlib 处理压缩。这两个库在开发机上通常都有现成的版本,但那些是给 x86 架构编译的,目标板上根本没法用。交叉编译的核心逻辑是:你在一台 x86 机器上,用针对 ARM 架构的编译器,产出一份 ARM 机器能运行的库文件。
很多人在这里会犯第一个错误:觉得 librtmp 的 configure 脚本会自动处理依赖。实际上 librtmp 的 Makefile 设计得非常朴素,它不会帮你自动定位 OpenSSL 和 zlib 的头文件与库文件位置,全靠你在编译时通过参数告诉它。所以交叉编译的第一步,不是碰 librtmp,而是先把 OpenSSL 和 zlib 交叉编译好,产出一套针对 ARM 的安装目录,再把这个目录的路径传给 librtmp。
我一般会在工作目录下建一个_install文件夹,把所有交叉编译产物的头文件和静态库都统一放到里面,这样后续编译 librtmp 时,只需要把INC指向_install/include,把XLDFLAGS指向_install/lib,既干净又不容易漏路径。
2.2 工具链选择与核心参数说明
交叉编译工具链的选择取决于你的目标架构。我这边用的是 arm-linux-gnueabihf-gcc,这对应的是 ARM 32 位硬浮点架构。如果你的板子是 ARM 64 位,那就换成 aarch64-linux-gnu-gcc。选错工具链是最难排查的问题之一,因为编译过程有时能过,但跑起来直接报 Illegal instruction。
先确认工具链能正常工作:
arm-linux-gnueabihf-gcc --version输出正常后,顺手确认一下它默认的 sysroot 路径,这决定了后续要不要手动指定额外的头文件路径。
工具链确认没问题之后,开始配置交叉编译环境变量。我通常会在编译前把下面这几个变量 export 出来:
export CC=arm-linux-gnueabihf-gcc export AR=arm-linux-gnueabihf-ar export RANLIB=arm-linux-gnueabihf-ranlib export CROSS_COMPILE=arm-linux-gnueabihf-CC是 C 编译器,AR是静态库打包工具,RANLIB是索引工具,CROSS_COMPILE是 librtmp 的 Makefile 里用来拼工具链前缀的变量。这几个变量在后续编译 OpenSSL、zlib 和 librtmp 时全部都要用到,提前设好可以避免每个包里重复写。
2.3 configure 脚本与 Makefile 的取舍逻辑
OpenSSL 和 zlib 都有 configure 脚本,但 librtmp 没有。librtmp 的源码包自带一个 Makefile,编译时直接传参数即可。这意味着你不需要也不可能对 librtmp 执行./configure,它的所有配置项全部集中在 Makefile 的变量里。
我在第一次操作的时候习惯性地去找 configure,没找到,还以为源码包不完整,后来才意识到 librtmp 的设计就是让你直接改 Makefile 变量。这一点其实挺反直觉的,但它反而简化了交叉编译的流程。你不需要担心 configure 检测到主机架构然后擅自启用某些不支持的特性,所有决定都在你自己的掌控里。
3. 实战:三步完成 librtmp 交叉编译全流程
3.1 第一步:交叉编译 OpenSSL
OpenSSL 是 librtmp 最核心的依赖,RTMP 握手、RTMPS 加密都靠它。交叉编译 OpenSSL 时最关键的参数是Configure而不是config,因为后者检测的是当前主机环境,编出来的一定是 x86 架构。
cd openssl-1.0.2u ./Configure linux-armv4 --prefix=$PWD/../_install --cross-compile-prefix=arm-linux-gnueabihf- shared no-asm make -j4 make installlinux-armv4指定了目标架构,--prefix指定安装路径,no-asm很重要,它关闭了汇编优化。交叉编译时汇编优化经常会因为工具链版本不匹配而出错,关掉它虽然损失一点性能,但能保证编译顺利通过。shared表示编译动态库,如果你打算做静态链接,这一步可以去掉。
这版本选择上我踩过一个坑:OpenSSL 1.1.0 以上的编译参数和 1.0.x 差别很大。如果你拿到的是 1.1.x 版本,Configure的参数要改成linux-armv4 -march=armv7-a,多了一个-march选项。建议先用 1.0.2u 熟悉整个链路,跑通后再升级到 1.1.x。
编译完成后,去_install目录确认一下产物架构:
file _install/lib/libcrypto.so.1.0.0看到ARM字样就说明架构对了,如果显示x86-64,说明 Configure 那一步没生效。
3.2 第二步:交叉编译 zlib
zlib 的交叉编译比 OpenSSL 简单得多,它有一个非常朴素的 configure 脚本,直接指定编译器就行:
cd zlib-1.2.11 ./configure --prefix=$PWD/../_install make CC=arm-linux-gnueabihf-gcc AR="arm-linux-gnueabihf-ar rc" make installzlib 的 configure 脚本不会像 OpenSSL 那样自动交叉编译,你需要手动指定CC和AR。AR后面那个rc参数是 ar 工具的创建归档模式,必须加上,否则静态库打不出来。
zlib 本身的代码量不大,编译速度很快。它的作用是为 librtmp 提供解压能力,RTMP 流里某些扩展头部或者 AMF 数据会经过压缩处理,没有 zlib 可能在解析某些特定流时直接崩溃。这个库不是可选依赖,必须编进系统里。
确认 zlib 编译成功:
file _install/lib/libz.a静态库没有架构信息,但你可以检查它的大小,通常在几百 KB 左右。如果特别小,大概率是编译期间出了什么怪问题。
3.3 第三步:librtmp 的 Makefile 参数配置
这是整个交叉编译中最关键的一步,也是参数最多的一步。librtmp 的 Makefile 支持通过命令行直接覆盖变量,不需要改文件本身:
cd librtmp make CROSS_COMPILE=arm-linux-gnueabihf- \ INC="-I$PWD/../_install/include" \ XLDFLAGS="-L$PWD/../_install/lib -ldl -lpthread" \ prefix=$PWD/../_install \ SHARED=noINC指定了额外的头文件搜索路径,这里同时包含了 OpenSSL 和 zlib 的头文件,因为它们都安装在_install/include下了。XLDFLAGS是链接选项,除了-L指定库目录外,-ldl和-lpthread是必须的。-ldl链接的是动态加载库,OpenSSL 在很多地方会调用dlopen加载引擎模块;-lpthread则是线程支持。少了这两个,链接阶段报错会让你怀疑人生。
SHARED=no表示编译静态库。这个是我在实践里总结出来的经验:嵌入式设备上动态库的排查成本太高,目标板上缺一个.so就得重新打包固件,静态链接虽然会让最终程序的体积大几十 KB,但省去了运行时依赖的麻烦。做嵌入式开发的,少一个动态依赖就少一个更新固件的理由。
编译完成后,产物会出现在 librtmp 目录下:
ls -la librtmp.a看到librtmp.a就说明静态库编译成功了。如果你还需要动态库,把SHARED=no去掉再编一次,两种产物可以共存。
4. 把编译好的 librtmp 集成进你的业务代码
4.1 头文件路径与链接参数怎么配
现在你已经有了针对 ARM 架构的librtmp.a、libcrypto.a和libz.a,接下来要做的就是把它们链进你自己的推流程序。这一步如果是在自己的 Makefile 里操作,链接参数有一个固定的顺序要求,乱排会直接导致undefined reference。
我一般这样写链接参数:
arm-linux-gnueabihf-gcc main.c -o rtmp_push \ -I./_install/include \ -L./_install/lib \ -lrtmp -lcrypto -lz -ldl -lpthread-lrtmp必须放在-lcrypto和-lz前面。GNU 链接器在处理静态库时是单向扫描的,它会从-lrtmp的库文件里找没解析的符号,然后继续在后面的库里找定义。如果你把-lcrypto放在-lrtmp前面,链接器先扫描了 libcrypto,发现里面没有未解析的符号就不管了,等扫描到 liblibrtmp 时发现有符号引用了 libcrypto 里的函数,但此时 libcrypto 已经没有再被扫描的机会了,结果就是一堆undefined reference to SSL_*。
这个顺序规则是链接器的工作机制决定的,不是玄学。整理成一条经验就是:被依赖的库放在依赖者的右边,从右往左解析。
4.2 静态链接与动态链接的选择
在交叉编译的场景里,我强烈建议用静态链接。理由很实际:动态链接需要目标板子上有对应版本的librtmp.so、libcrypto.so和libz.so,这三个库的版本只要有一个对不上,程序启动就会报cannot open shared object file。而静态链接把所有代码都打包进了最终的可执行文件里,目标板上只需要有基本的 C 运行库就行。
不过静态链接也有它的问题,最明显的就是体积。librtmp.a本身不大,但libcrypto.a是个大块头,静态链接后你的可执行文件可能会比动态链接大 1MB 以上。这对存储空间有限的嵌入式设备是个压力,好在现在大多数板子的 flash 都在 16MB 以上,1MB 的代价换来的稳定性是值得的。
如果你确实要动态链接,记得把编译好的librtmp.so一并拷贝到目标板的/usr/lib目录下,然后执行ldconfig刷新动态链接器缓存。这两个动作缺一个,程序在运行时都会找不到库。
4.3 pkg-config 文件的修正
librtmp 源码包里自带一个librtmp.pc.in模板,安装后会生成pkgconfig/librtmp.pc,但交叉编译时这个文件是错的,因为它的路径直接指向了编译机器的目录。如果你习惯用 pkg-config 管理编译选项,需要手动改正这个文件的内容:
prefix=/home/build/arm_install exec_prefix=${prefix} libdir=${prefix}/lib includedir=${prefix}/include Name: librtmp Description: RTMP implementation Version: 2.4 Libs: -L${libdir} -lrtmp -lz -lcrypto Cflags: -I${includedir}重点是把prefix改成你实际的安装路径,并且Libs字段要手动加上-lz -lcrypto,原版文件默认不包含这两个依赖。修改完复制到工具链的 sysroot 目录里,后续用pkg-config --cflags --libs librtmp就能正常获取路径。
5. 避坑:我踩过的五个交叉编译翻车现场
5.1 现象:编译时报openssl/rsa.h: No such file or directory
原因:INC参数没有正确指向 OpenSSL 头文件所在的目录,编译器找不到 RSA 相关的定义。
解决:检查INC是否确实指向了_install/include,并且确认这个目录下存在openssl/rsa.h文件。很多时候是因为编译 OpenSSL 时--prefix没有生效,头文件根本没安装过来,重新执行make install就行。
5.2 现象:链接阶段报undefined reference to SSL_library_init
原因:链接库的顺序不对。这种情况几乎可以断定是把-lcrypto放在了-lrtmp前面,导致 libcrypto 没有被正确扫描。
解决:把-lcrypto调整到-lrtmp的右端,或者直接复制我的链接参数模板,不要自己重组顺序。
5.3 现象:编译完成后在目标板上运行,报cannot open shared object file: No such file
原因:你用了动态链接,但目标板上缺少librtmp.so或者它的依赖库没有被拷贝过去。
解决:用静态链接,或者在编译时加-static强制全部静态化。另外一个溜的办法是把readelf -d查看可执行文件的动态依赖列表,逐条核对是否都在目标板上存在。
5.4 现象:configure 脚本检测的架构不对,编出来的库是 x86 的
原因:OpenSSL 用了./config而不是./Configure,导致它自动检测到了主机架构。
解决:强制使用./Configure linux-armv4,并且在执行后检查Makefile里的CC变量是否确实带上了交叉编译前缀。我遇到过Makefile里显示的CC被自动改了回来,检查一遍能少走很多弯路。
5.5 现象:程序能跑,但卡在RTMP_Connect超时
原因:这是最迷惑人的一种情况,编译没问题、链接没问题、架构也对,但就是连不上服务器。我排查了很久才发现问题出在交叉编译 OpenSSL 时no-asm这个选项加得太随意,SSL 握手过程中的某些计算路径在特定版本的 OpenSSL 里出现了分支错误。
解决:先用取消 SSL 的方式测试 RTMP 连接,如果正常说明是 TLS 握手环节的问题。然后强制重新编译 OpenSSL 时加no-asm并且确认配置生效,或者换一个 OpenSSL 版本再试。经验是:librtmp 交叉编译失败了可以用strace看系统调用,用tcpdump抓包看 RTMP 握手,别在那里瞎猜。
6. 验证与进阶:从 file 命令到体积优化的一整套习惯
6.1 用 file 和 readelf 验证产物架构
拿到交叉编译产物后,不验证就直接拷到目标板上,等于在拒绝排错。我每次编译完都会跑三连命令:
file librtmp.a file rtmp_push readelf -d rtmp_push | grep NEEDEDfile确认可执行文件是 ARM 架构,readelf -d查看动态依赖列表。如果readelf的输出里有libc.so.6以外的条目,就说明这个可执行文件并不完全静态,需要把这些库一并拷到目标板。
6.2 体积优化:裁剪 OpenSSL 的编译选项
编译 OpenSSL 时,no-asm选项除了规避汇编版本的坑,还有一个好处是减小体积。ARM 汇编优化会加入很多特定架构的实现代码,这些代码在你只跑 RTMP 握手时完全是多余的。配合no-shared和no-ssl2、no-ssl3这些选项,编译出来的libcrypto.a能比默认配置小 30% 左右。
6.3 从血泪经验里沉淀出的编译习惯
从那以后我每次做 librtmp 交叉编译都强制走一遍同一套流程:检查工具链版本、确定_install目录是干净的、按 OpenSSL、zlib、librtmp 的顺序依次编译、每个环节完成后立刻用file验证架构、最后固定用静态链接集成到业务代码。这套流程虽然看起来繁琐,但每次都能在五分钟内跑完,而且基本不会翻车。特别是静态链接的那一步,让我再也没有为动态库缺失的问题重新烧过板子。希望这篇文章能帮你在 librtmp 交叉编译的路上少走几个来回,一次就把推流跑通。
本文还有配套的精品资源,点击获取