ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Win10+VS2017编译librtmp.lib实战:从源码到推流集成

Win10+VS2017编译librtmp.lib实战:从源码到推流集成 简介这份资源面向需要在 Windows 10 与 VS2017 环境下使用 librtmp 的开发者尤其是从事流媒体推流、RTMP 协议对接或音视频项目移植的初中级工程师。它提供了一套可直接编译的 librtmp.lib 静态库工程省去自行配置 OpenSSL、zlib 等依赖的繁琐过程解决编译环境搭建与库文件生成的问题。压缩包共 238 个文件约 49.12MB以 163 个 h 头文件、28 个 dll 动态库、8 个 lib 库文件及少量 c 源码、vcxproj 工程文件为主并附带 openssl-1.0.1c、zlib-1.2.8 等依赖目录与 librtmp.sln 解决方案目录结构清晰便于按模块查阅与二次开发。目前已有 637 人学习下载适合希望快速获得可用 librtmp 库、减少环境配置踩坑的读者参考使用。1. 为什么在 Win10 VS2017 下编译 librtmp.lib 值得单独折腾一遍如果你正在 Win10 上做推流客户端、直播采集端或者要给某个老项目补上 RTMP 协议支持大概率绕不开 librtmp。它本身是 RTMPDump 里的核心库负责把音视频数据按 RTMP 协议打包、握手、推送到服务端。麻烦的地方在于官方源码是给 Linux 那套 autotools 准备的直接扔进 Visual Studio 会一脸懵。网上流传的很多“编译教程”要么缺头文件要么链接时一堆 unresolved external最后只能放弃改用别的库。这份资源的价值就在这儿——它把 VS2017 工程、引用库和源代码一起打包好了Win10 下打开就能编译省掉自己配 OpenSSL、zlib、pthread 那一堆依赖的功夫。适合两类人一是需要在 Windows 桌面端集成 RTMP 推流、又不想引入 FFmpeg 全家的开发者二是想读懂 librtmp 内部握手和 chunk 分片逻辑、拿它当学习样本的工程师。下面按“资源里有什么 → 怎么编译 → 怎么调用 → 坑在哪”的顺序拆一遍。2. 资源结构与依赖关系先看清目录再动手2.1 目录里到底放了什么拿到压缩包解压后通常能看到类似这样的结构不同打包方式可能略有差异但核心目录一致librtmp-vs2017/ ├── librtmp/ # librtmp 核心源码 │ ├── rtmp.c # 协议主逻辑握手/chunk/命令都在这里 │ ├── handshake.c # 握手实现 │ ├── rtmp.h # 对外头文件 │ ├── log.c │ ├── amf.c # AMF0/AMF3 编解码 │ ├── hashswf.c │ └── ... ├── deps/ # 预编译或源码形式的依赖 │ ├── openssl/ # 头文件 lib │ ├── zlib/ │ └── pthread/ # Windows 下的 pthread 兼容层 ├── librtmp.sln # VS2017 解决方案 └── librtmp.vcxproj # 工程文件核心是librtmp/下的源码deps/里放的是编译时需要的第三方库。librtmp 本身不复杂但它依赖三样东西OpenSSL 提供 RTMPS 和握手阶段的加密散列zlib 处理压缩pthread 做线程封装。Windows 上没有原生 pthread所以资源里一般会带一个 win32 的 pthread 兼容实现。2.2 依赖库的版本与链接方式依赖作用常见版本链接方式OpenSSLRTMPS、握手散列1.0.2 / 1.1.1静态 lib 或动态 dllzlib压缩支持1.2.x静态 libpthread线程封装win32-pthreads静态 lib这里有个关键点OpenSSL 1.0.2 和 1.1.1 的 API 不兼容。1.1.1 把很多结构体改成了不透明指针如果资源里带的是 1.0.2 的头文件你换成 1.1.1 的 lib 就会编译报错。所以不要随意替换 deps 里的库版本除非你确认源码已经适配。提示先看librtmp.vcxproj里“附加包含目录”和“附加库目录”指向哪里确认依赖路径没有写死成作者本机的绝对路径。如果写死了改成相对路径$(SolutionDir)deps\...。2.3 工程配置里必须确认的几项打开解决方案后别急着点生成。先右键 librtmp 项目 → 属性逐项核对配置类型应该是“静态库(.lib)”不是应用程序。平台工具集Visual Studio 2017 (v141)。C/C → 代码生成 → 运行库静态库一般用/MT或/MTd如果调用方用/MD这里要改成/MD否则链接时会报运行库冲突。C/C → 预处理器 → 预处理器定义确认有WIN32、_WINDOWS、NO_CRYPTO如果不需要 RTMPS等。是否需要NO_CRYPTO取决于你要不要加密推流。链接器 → 输入 → 附加依赖项应该能看到libssl.lib、libcrypto.lib、zlib.lib、pthread.lib之类。这些配置如果不对编译能过但链接必挂。我一般会先把运行库和预处理器定义对齐再动代码。3. 从源码到 librtmp.libVS2017 编译全流程3.1 打开工程与首次生成用 VS2017 打开librtmp.sln解决方案平台选x64或Win32看你目标程序是哪个。右键 librtmp 项目 → 生成。如果一切顺利输出窗口会显示librtmp.vcxproj - ...\librtmp.lib。但第一次生成大概率不会这么顺。常见的是头文件找不到比如openssl/ssl.h报错。这时候去项目属性的“附加包含目录”里把deps\openssl\include加进去。同理 zlib 和 pthread 的头文件目录也要加。3.2 手动补全缺失的源文件有些打包版本为了减小体积会把rtmp.c里用到的某些辅助文件漏掉比如hashswf.c或parseurl.c。如果链接时报unresolved external symbol _RTMP_...先检查这些文件是否在项目里。不在的话右键“源文件” → 添加 → 现有项把它们加进来。还有一种情况源码里用了#include sys/time.h这种 Linux 头Windows 下没有。资源如果已经改好了就没问题如果没改需要手动替换成#include winsock2.h和#include time.h并把gettimeofday换成 Windows 的GetSystemTimeAsFileTime封装。这一步比较繁琐但资源既然标了“可直接编译”通常已经处理过。3.3 编译命令行的等价写法如果你习惯用命令行或者要在 CI 里跑可以用 MSBuild:: 进入 VS2017 开发者命令提示符 cd /d D:\librtmp-vs2017 msbuild librtmp.sln /p:ConfigurationRelease /p:Platformx64 /m/p:ConfigurationRelease指定发布配置/p:Platformx64指定 64 位/m开启多核编译。生成的librtmp.lib在x64\Release\目录下。注意命令行编译前一定要先运行vcvars64.bat在 VS2017 安装目录的VC\Auxiliary\Build\下否则msbuild找不到编译器。3.4 验证 lib 是否可用编译出 lib 只是第一步还得确认它真能用。写一个最小测试程序只调用RTMP_Init和RTMP_Free#include stdio.h #include rtmp.h int main() { RTMP *rtmp RTMP_Alloc(); if (!rtmp) { printf(RTMP_Alloc failed\n); return -1; } RTMP_Init(rtmp); printf(librtmp init ok\n); RTMP_Free(rtmp); return 0; }把这个文件加入一个新建的控制台工程链接librtmp.lib和它的依赖库。如果能打印librtmp init ok说明 lib 编译正确、头文件路径也对。这一步能提前暴露运行库不匹配、符号缺失等问题比直接集成到大项目里再排查省事得多。4. 在推流程序里调用 librtmp连接、握手与推流4.1 建立 RTMP 连接的标准流程librtmp 的调用顺序比较固定分配 → 初始化 → 设置 URL → 连接 → 推流。下面是一个推本地 FLV 文件到 RTMP 服务端的简化示例#include rtmp.h #include stdio.h int main() { RTMP *rtmp RTMP_Alloc(); RTMP_Init(rtmp); // 设置推流地址例如 rtmp://live.example.com/app/streamkey if (!RTMP_SetupURL(rtmp, rtmp://live.example.com/app/streamkey)) { printf(RTMP_SetupURL failed\n); RTMP_Free(rtmp); return -1; } // 开启推流模式不开启就是播放模式 rtmp-Link.lFlags | RTMP_LF_LIVE; RTMP_SetBufferMS(rtmp, 3600 * 1000); // 缓冲 1 小时 if (!RTMP_Connect(rtmp, NULL)) { printf(RTMP_Connect failed\n); RTMP_Free(rtmp); return -1; } if (!RTMP_ConnectStream(rtmp, 0)) { printf(RTMP_ConnectStream failed\n); RTMP_Close(rtmp); RTMP_Free(rtmp); return -1; } printf(connected, ready to send\n); // 这里后续调用 RTMP_Write 发送 FLV tag RTMP_Close(rtmp); RTMP_Free(rtmp); return 0; }RTMP_SetupURL解析地址并填充内部字段RTMP_LF_LIVE告诉库这是直播推流不是点播RTMP_Connect完成 TCP 连接和 RTMP 握手RTMP_ConnectStream发送createStream和publish命令。顺序不能乱少了RTMP_ConnectStream直接RTMP_Write会失败。4.2 发送 FLV 数据的参数控制真正推流时数据是以 FLV Tag 为单位写入的。RTMP_Write的第二个参数是数据指针第三个是长度。关键参数是时间戳和帧类型这些封装在 FLV Tag 头部里librtmp 不负责解析需要你自己按 FLV 格式拼好。常见做法是读一个 FLV 文件跳过 9 字节文件头然后循环读 Tag。每个 Tag 的前 11 字节是 Tag Header包含类型、数据大小、时间戳。把整个 TagHeader Data传给RTMP_Write即可。// 伪代码循环发送 FLV Tag while (read_flv_tag(fp, tag)) { int n RTMP_Write(rtmp, tag.data, tag.size); if (n 0) { printf(RTMP_Write failed\n); break; } // 按时间戳控制发送节奏 usleep(tag.timestamp - last_ts); last_ts tag.timestamp; }RTMP_Write返回实际写入的字节数小于 0 表示出错。时间戳控制是推流流畅度的关键发太快服务端会丢帧发太慢观众端会卡顿。一般按 Tag 时间戳差值来 sleep不要一股脑全发出去。4.3 断开与资源释放推流结束后标准做法是RTMP_Close(rtmp); RTMP_Free(rtmp);RTMP_Close会发送FCUnpublish和deleteStream命令然后关闭 socket。RTMP_Free释放内存。如果程序异常退出没走这两步服务端可能残留一个“僵尸流”需要等超时才会断开。所以建议用atexit或信号处理确保释放逻辑一定执行。5. 避坑与排查编译和调用中最容易翻车的几个点5.1 链接报错 unresolved external symbol现象编译通过链接时一堆unresolved external symbol _SSL_...或_deflate。原因依赖库没链接进去或者链接顺序不对。MSVC 对静态库的链接顺序敏感librtmp.lib依赖的库要放在它后面。解决在“附加依赖项”里按librtmp.lib;libssl.lib;libcrypto.lib;zlib.lib;pthread.lib;ws2_32.lib;的顺序排列。ws2_32.lib是 Windows socket 库librtmp 内部用了 socket API必须链接。5.2 运行时报“无法定位程序输入点”或直接崩溃现象编译链接都过了一运行就崩或者提示找不到某个 DLL。原因运行库配置不一致。静态库用/MT编译调用方用/MD混在一起会导致堆内存管理冲突典型表现是RTMP_Free时崩溃。解决统一运行库。要么全用/MT要么全用/MD。在 VS 里就是项目属性 → C/C → 代码生成 → 运行库所有项目选同一个值。5.3 握手失败或连接被拒绝现象RTMP_Connect返回失败日志显示握手阶段就断了。原因常见有三种。一是地址写错RTMP_SetupURL对 URL 格式要求严格rtmp://不能少端口默认 1935 但有些服务端改过。二是服务端要求 RTMPS但编译时没启用 OpenSSL 支持。三是防火墙拦截了 1935 端口。解决先用telnet 服务器 1935确认端口通不通。如果服务端要 RTMPS确认编译时没有定义NO_CRYPTO并且 OpenSSL 库链接正确。URL 里如果带?参数注意转义。5.4 推流几秒后断开现象连接成功推了几秒数据后RTMP_Write返回错误连接断开。原因通常是时间戳跳变或发送速度不合理。服务端对时间戳有校验如果后一个 Tag 的时间戳比前一个小或者跳跃太大会被判定为异常流。另外如果长时间不发数据服务端也会超时断开。解决确保 FLV Tag 的时间戳单调递增。发送节奏按时间戳差值控制不要一次性把文件全推完。如果源是实时采集注意采集线程和发送线程之间的缓冲队列不要积压太久。5.5 编译 32 位和 64 位混用现象x64 工程链接了 Win32 的 lib报模块计算机类型“x86”与目标计算机类型“x64”冲突。原因依赖库的位数和主工程不一致。解决确认deps下的 lib 是哪个平台的。如果只有 32 位主工程就切到 Win32如果要 64 位得自己重新编译依赖库。VS2017 的开发者命令提示符分 x86 和 x64 两种编译依赖时别选错。6. 进阶技巧用 dump 工具验证 librtmp 行为与自定义日志编译出 lib 只是开始真正集成到项目里调试才是大头。librtmp 内部有日志开关但默认不输出。可以在RTMP_Init之后设置rtmp-m_outChunkSize和日志回调不过更实用的办法是抓包配合日志。我一般会先用 Wireshark 抓 1935 端口的包看握手是否完成、connect命令的返回码是不是NetConnection.Connect.Success。如果握手就失败问题在库或网络如果握手成功但publish失败多半是流名或权限问题。另一个技巧是重写RTMP_Log的输出。librtmp 里所有日志都走RTMP_Log函数你可以在自己的代码里定义一个同名函数覆盖它注意链接顺序把日志写到文件里。这样能看清内部 chunk 分片和命令交互的细节。void RTMP_Log(int level, const char *format, ...) { va_list args; va_start(args, format); FILE *fp fopen(rtmp_debug.log, a); if (fp) { vfprintf(fp, format, args); fclose(fp); } va_end(args); }这个函数要放在链接librtmp.lib之前确保链接器优先用你的实现。日志里能看到Handshake: ...、Sending connect packet、Server version这些关键信息排查问题时比盲猜强得多。还有一点librtmp 默认的 chunk size 是 128 字节推流时如果数据量大频繁分片会影响效率。可以在连接成功后发送SetChunkSize命令把 chunk size 调大比如 4096。不过这个操作要自己拼 AMF 包稍微麻烦一点。如果只是推流不改也能用只是 CPU 占用略高。从那以后我每次编译完 librtmp都会先跑一遍最小连接测试再抓一次包确认握手和connect返回最后才集成到业务代码里。这套流程帮我省掉了很多“编译过了但一跑就崩”的后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表