简介:本资源是一套专为Windows平台开发者准备的librtmp静态库编译工程,适用于Win10环境下使用Visual Studio 2017进行RTMP协议客户端开发或音视频流接入项目。资源完整提供librtmp源码、依赖的OpenSSL 1.0.1c与zlib-1.2.8第三方库、预配置的VS2017解决方案(librtmp.sln)及全部头文件与构建中间产物,开箱即用,显著降低跨版本编译门槛。压缩包共238个文件,涵盖163个.h头文件(定义RTMP核心结构与API)、28个.dll动态链接库(含调试与运行时依赖)、8个.lib静态库(含librtmp.lib主库及加密/压缩模块),以及C源码、项目配置文件和构建日志等,总大小49.12MB,目录结构层次清晰,便于溯源依赖与定制修改。目前已有637人学习下载,适合中高级C/C++开发者快速集成RTMP推拉流能力,尤其适配直播SDK二次开发、嵌入式音视频工具链构建等实际工程场景。
1. VS2017 编译 librtmp.lib:Win10 下最易翻车的“三步走”陷阱
你是不是也试过:下载了 librtmp 源码,打开 VS2017,新建空项目,把.c文件拖进去,点生成——结果满屏LNK2019: unresolved external symbol?或者更玄学的是:编译通过了,但一运行就0xC000007B(架构不匹配),再查发现libssl.lib和libcrypto.lib版本对不上,而你根本不知道该用 OpenSSL 的哪个分支、哪个构建方式、甚至不确定 VS2017 默认用的是 v141 还是 v140 工具集……这不是你手生,是 librtmp 在 Win10 + VS2017 这个组合里,天然带着三重隐性依赖:OpenSSL(必须静态链接)、zlib(必须启用ZLIB_WINAPI宏)、以及 Windows SDK 版本与运行时库(/MT vs /MD)的精确咬合。这套环境不是“能跑就行”,而是“错一个参数,整个 lib 就成黑匣子”。它适合正在做 RTMP 推流/拉流模块集成的 C/C++ 开发者,尤其是需要将 librtmp 嵌入到已有 VS2017 工程中、又不想引入 CMake 或第三方包管理器的场景——你不需要懂网络协议细节,但必须让#include <librtmp/rtmp.h>后的RTMP_Alloc()调用真正返回非 NULL 指针。
2. 环境准备:VS2017 工具链、OpenSSL 与 zlib 的版本锁死策略
librtmp 本身不带加密和压缩逻辑,它把 SSL/TLS 握手交给 OpenSSL,把 DEFLATE 压缩交给 zlib。这意味着:你最终得到的librtmp.lib不是独立二进制,而是三者 ABI 层级的刚性绑定体。任何一方版本或编译选项错位,都会在链接期或运行期暴雷。我们不追求“最新版”,而追求“VS2017 官方工具链下验证过稳定”的组合。
2.1 VS2017 必须启用的组件与平台工具集
VS2017 安装时默认不勾选全部 C++ 组件。请确认以下三项已安装(可通过“Visual Studio Installer → 修改 → 工作负载 → 使用 C++ 的桌面开发”检查):
- ✅Windows 10 SDK(10.0.17763.0 或 10.0.18362.0)
提示:不要选 10.0.19041.0 及以上——VS2017 对新版 SDK 支持不完整,会导致
winsock2.h符号冲突。17763 是 Win10 1809 LTSB 的 SDK,兼容性最稳。 - ✅CMake tools for Visual Studio(可选但推荐)
用于后续验证 OpenSSL 构建脚本是否被正确识别,非必需但能提前暴露路径问题。
- ✅C++ ATL for latest v141 build tools(x86/x64)
librtmp 源码中部分 Windows API 调用(如
WSAStartup)隐式依赖 ATL 类型定义,缺它会报error C2065: 'SOCKET' : undeclared identifier。
注意:VS2017 默认使用v141 工具集(对应 MSVC 14.16.x)。你必须在项目属性 → 常规 → “平台工具集” 中显式设为
v141,不能留空或选v140。v140 是 VS2015 工具集,与 VS2017 的 CRT 库不兼容,会导致__stdio_common_vsscanf等符号找不到。
2.2 OpenSSL:必须用 1.1.1w 静态链接版(非 3.x)
librtmp 官方源码(截至 2023 年主干)完全不兼容 OpenSSL 3.x。其rtmp_openssl.c中大量使用已被废弃的SSL_library_init()、SSL_load_error_strings()、CRYPTO_malloc_init()等函数,且硬编码了EVP_md5()、EVP_sha1()等 legacy digest 方法。若强行用 OpenSSL 3.x,编译直接失败。
✅ 正确选择:OpenSSL 1.1.1w(2023 年 11 月发布的最终维护版,含所有安全补丁,且对 VS2017 支持最成熟)
❌ 错误选择:OpenSSL 3.0.0+、OpenSSL 1.0.2u(已 EOL,无 Win10 TLS 1.3 支持)、或任何预编译的“动态 DLL 版”。
我们不从源码编译 OpenSSL(太耗时且易出错),而是采用官方预编译静态库 + 头文件包:
- 下载地址:https://slproweb.com/products/Win32OpenSSL.html (选择
Win64 OpenSSL v1.1.1w,务必选 "Light" 版本—— 它只含libssl.lib、libcrypto.lib和头文件,不含openssl.exe等冗余二进制) - 解压后目录结构应为:
OpenSSL-Win64/ ├── include/ ← 头文件(openssl/ 目录必须存在) └── lib/ ← 静态库(VC\static\libssl.lib 和 libcrypto.lib) └── VC\static\
关键参数说明:
VC\static\下的库是/MT(多线程静态链接 CRT)编译的,这与我们后续 librtmp 的/MT设置严格一致。若你工程用/MD,则必须改用VC\dynamic\下的 DLL 导入库(但会引入libssl-1_1-x64.dll依赖,违背“纯静态 librtmp.lib”目标)。
2.3 zlib:必须启用ZLIB_WINAPI宏并用 1.2.13
librtmp 的rtmp.c中调用uncompress()和compress2()时,强制要求 zlib 导出函数遵循WINAPI调用约定(即__stdcall)。标准 zlib 编译默认是__cdecl,会导致链接时unresolved external symbol _uncompress@12(注意末尾@12是__stdcall的修饰名)。
✅ 正确做法:下载 zlib 1.2.13 源码(https://zlib.net/zlib1213.zip),解压后修改zconf.h:
// 找到 #ifdef WIN32 ... #endif 块,在其中添加: #ifndef ZLIB_WINAPI # define ZLIB_WINAPI #endif然后用 VS2017 打开contrib/vstudio/vc15/zlibvc.sln(VS2017 兼容 vc15 解决方案),仅生成zlibstat项目(Static Library),输出zlibstat.lib。
提示:
zlibstat.lib默认也是/MT编译,与 OpenSSL 1.1.1w 保持一致。无需额外配置。
3. librtmp 源码编译:从克隆到生成 librtmp.lib 的六步实操
我们不使用原始 rtmpdump 仓库(已多年未维护,Windows 支持差),而是采用社区维护最活跃的 fork:mstorsjo/rtmpdump(GitHub 上 star 数最高、Win10+VS2017 提交记录最密集)。其master分支已修复gethostbyname弃用、WSAStartup初始化顺序等关键问题。
3.1 获取源码并清理无关文件
# 在命令行(非 PowerShell)中执行,避免路径空格问题 cd /d D:\dev\libs git clone https://github.com/mstorsjo/rtmpdump.git librtmp-vs2017 cd librtmp-vs2017 # 删除 Linux/macOS 构建脚本和测试程序,只留核心 del /q /s librtmp\*.sh librtmp\*.m4 librtmp\configure* librtmp\Makefile* del /q rtmpdump.exe rtmpgw.exe rtmpsrv.exe rtmpsuck.exe逻辑说明:
mstorsjo/rtmpdump的librtmp/目录就是纯 C 库源码,rtmpdump/目录是命令行工具(我们不需要)。删除 shell 脚本可避免 VS2017 在“显示所有文件”模式下误索引。
3.2 创建 VS2017 静态库项目并导入源码
- 打开 VS2017 → “文件 → 新建 → 项目” → “Win32 → Win32 项目”
- 项目名填
librtmp,位置选D:\dev\libs\librtmp-vs2017(与源码同目录) - 点击“下一步”,在向导中勾选“静态库”,取消勾选“预编译头”和“安全开发”(librtmp 不需要)
- 完成后,在解决方案资源管理器中:
- 右键“源文件” → “添加 → 现有项” → 选择
librtmp-vs2017\librtmp\*.c(共 12 个文件,含rtmp.c,log.c,parseurl.c等) - 右键“头文件” → “添加 → 现有项” → 选择
librtmp-vs2017\librtmp\*.h(共 4 个:amf.h,bytes.h,log.h,rtmp.h)
- 右键“源文件” → “添加 → 现有项” → 选择
参数说明:不启用预编译头(PCH)是因为 librtmp 所有
.c文件都只包含标准头(<stdio.h>,<winsock2.h>),加 PCH 反而增加编译依赖和出错概率。
3.3 配置项目属性:四组关键设置
右键项目 → “属性”,按以下分组设置(必须逐项核对,漏一项就可能链接失败):
3.3.1 常规设置(Configuration Properties → General)
| 属性 | 值 | 说明 |
|---|---|---|
| 目标扩展名 | .lib | 确保输出是静态库 |
| 字符集 | 使用多字节字符集 | librtmp 源码无 Unicode 字符处理,用 Unicode 会触发LPCTSTR类型错误 |
| 平台工具集 | v141 | 再次强调,必须是 v141,不是自动继承 |
3.3.2 C/C++ 设置(C/C++ → General & Preprocessor)
| 属性 | 值 | 说明 |
|---|---|---|
| 附加包含目录 | D:\dev\libs\OpenSSL-Win64\include;D:\dev\libs\zlib-1.2.13\contrib\vstudio\vc15\zlibstat\include | 让#include <openssl/ssl.h>和#include "zlib.h"能找到 |
| 预处理器定义 | OPENSSL_NO_SSL2;OPENSSL_NO_SSL3;ZLIB_WINAPI;_CRT_SECURE_NO_WARNINGS | ZLIB_WINAPI是 zlib 调用约定开关;_CRT_SECURE_NO_WARNINGS屏蔽sprintf等警告(librtmp 源码大量使用) |
3.3.3 链接器设置(Linker → General & Input)
| 属性 | 值 | 说明 |
|---|---|---|
| 附加库目录 | D:\dev\libs\OpenSSL-Win64\lib\VC\static;D:\dev\libs\zlib-1.2.13\contrib\vstudio\vc15\zlibstat\lib | 指向libssl.lib和zlibstat.lib所在目录 |
| 附加依赖项 | libssl.lib;libcrypto.lib;zlibstat.lib;ws2_32.lib;crypt32.lib | ws2_32.lib(Winsock)、crypt32.lib(Windows Crypto API)是 Windows 平台必需 |
3.3.4 C/C++ 代码生成(C/C++ → Code Generation)
| 属性 | 值 | 说明 |
|---|---|---|
| 运行时库 | 多线程 (/MT) | 最关键!必须与 OpenSSL 和 zlib 的/MT版本一致。若选/MD,链接时会报LNK2038: mismatch detected for 'RuntimeLibrary' |
提示:所有路径请用绝对路径,避免相对路径在不同机器上解析失败。VS2017 对中文路径支持极差,路径中严禁出现中文、空格、括号。
3.4 修正源码两处 Win10 兼容性硬伤
即使配置全对,原始rtmp.c在 Win10 下仍有两处编译错误,需手动修改:
3.4.1 修复gethostbyname弃用警告(升级为getaddrinfo)
在librtmp\rtmp.c第 1720 行附近,找到:
struct hostent *he = gethostbyname(host);替换为:
struct addrinfo hints = {0}, *result = NULL; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; int ret = getaddrinfo(host, NULL, &hints, &result); if (ret != 0) { RTMP_Log(RTMP_LOGERROR, "%s, getaddrinfo() failed: %s", __FUNCTION__, gai_strerror(ret)); return FALSE; } // 后续用 result->ai_addr 替代 he->h_addr_list[0]并确保在文件顶部#include <ws2tcpip.h>(已在rtmp.h中包含,无需额外加)。
3.4.2 修复WSAStartup初始化时机
在librtmp\rtmp.c的RTMP_Init()函数开头(约第 120 行),找到:
#ifdef _WIN32 static int started = 0; if (!started) { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); started = 1; } #endif将其整体剪切,粘贴到RTMP_Alloc()函数开头(第 100 行左右)。
原因:
RTMP_Init()可能被多次调用,而WSAStartup只能调用一次;RTMP_Alloc()是用户创建 RTMP 实例的第一入口,此处初始化最安全。
4. 常见问题排查:五条血泪经验总结的“必现翻车点”
编译 librtmp.lib 是个典型的“一步错,步步错”过程。下面五条是我在某跨平台直播 SDK 项目中,连续三天调试后记下的真实踩坑记录,每一条都对应一个具体错误现象、根本原因和可立即执行的解决动作。
4.1 现象:LNK2019: unresolved external symbol _uncompress@12
- 原因:zlib 库未启用
ZLIB_WINAPI宏,导致导出函数名是_uncompress(cdecl),而 librtmp 调用的是_uncompress@12(stdcall)。链接器找不到匹配符号。 - 解决:确认
zconf.h中已定义#define ZLIB_WINAPI,并重新编译zlibstat.lib;检查项目属性 → C/C++ → 预处理器 → “预处理器定义” 是否包含ZLIB_WINAPI(大小写敏感)。
4.2 现象:LNK2001: unresolved external symbol _CRYPTO_malloc_init
- 原因:OpenSSL 1.1.1w 已移除
CRYPTO_malloc_init(),但 librtmp 源码(rtmp_openssl.c第 102 行)仍调用它。这是 mstorsjo 分支已修复,但如果你用的是旧 fork 或手动 patch 过源码,可能遗漏。 - 解决:打开
librtmp\rtmp_openssl.c,搜索CRYPTO_malloc_init,将其整行注释掉(OpenSSL 1.1.1+ 自动初始化内存函数);同时注释掉紧随其后的SSL_load_error_strings()和SSL_library_init()(它们也被废弃,由OPENSSL_init_ssl()替代,但 librtmp 尚未更新)。
4.3 现象:error C2065: 'SOCKET' : undeclared identifier
- 原因:
winsock2.h未被正确包含,或被windows.h中的winsock.h覆盖(后者定义的是老式SOCKET)。VS2017 项目默认包含windows.h,而windows.h会根据宏定义决定是否包含winsock.h。 - 解决:在
librtmp\rtmp.h的最顶部(#ifndef __RTMP_H__之后),第一行添加:
并确保#define WIN32_LEAN_AND_MEAN #include <winsock2.h> #include <ws2tcpip.h>#include <windows.h>出现在这些之后,或干脆删掉#include <windows.h>(librtmp 不需要它)。
4.4 现象:LNK2038: mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't match value 'MD_DynamicRelease'
- 原因:项目设置为
/MT,但某个源文件(如log.c)被意外设置了/MD,或引用的第三方头文件(如某些日志库)强制包含了/MD宏。 - 解决:右键每个
.c文件 → “属性” → C/C++ → 代码生成 → “运行时库” → 确认均为/MT;在项目属性 → C/C++ → 预处理器 → “预处理器定义” 中,删除所有含DLL或MD的宏(如_USRDLL,DLL_EXPORT)。
4.5 现象:编译通过,但运行时RTMP_Connect()返回 0,RTMP_Log显示Failed to initialize WinSock
- 原因:
WSAStartup未被调用,或被调用在错误时机(如在RTMP_Init()中多次调用失败)。 - 解决:确认已按 3.4.2 节将
WSAStartup移至RTMP_Alloc()开头;在RTMP_Alloc()中添加临时日志:
若此日志不打印,说明RTMP_Log(RTMP_LOGDEBUG, "WSAStartup called in RTMP_Alloc");RTMP_Alloc()根本没执行——检查你的调用链是否跳过了它(例如直接malloc了RTMP结构体)。
5. 验证 librtmp.lib:用一个最小 demo 工程跑通 RTMP 连接
光有librtmp.lib文件不等于成功。真正的验证,是把它集成进一个新工程,调用RTMP_Alloc()→RTMP_SetupURL()→RTMP_Connect()三步,并看到RTMP_Log输出连接成功的日志。这才是“能用”的唯一标准。
5.1 创建验证工程:三文件极简结构
新建一个 Win32 控制台应用(非空项目),命名为rtmp_test,目录结构:
rtmp_test/ ├── main.c ← 主程序 ├── rtmp_test.vcxproj ← VS2017 项目文件 └── librtmp.lib ← 你刚编译好的库(复制过来)5.1.1main.c内容(可直接复制)
#include <stdio.h> #include <stdlib.h> #include "librtmp/rtmp.h" // 自定义日志回调,把 RTMP 日志输出到控制台 void my_log(int level, const char *fmt, va_list args) { if (level <= RTMP_LOGINFO) { vprintf(fmt, args); printf("\n"); } } int main(int argc, char *argv[]) { // 1. 初始化日志(可选,但强烈建议) RTMP_LogSetCallback(my_log); RTMP_LogSetLevel(RTMP_LOGINFO); // 2. 分配 RTMP 结构体 RTMP *r = RTMP_Alloc(); if (!r) { printf("RTMP_Alloc failed!\n"); return -1; } RTMP_Init(r); // 3. 设置 RTMP URL(用一个公开的测试流) const char *url = "rtmp://127.0.0.1:1935/live/test"; if (!RTMP_SetupURL(r, (char*)url)) { printf("RTMP_SetupURL failed!\n"); RTMP_Free(r); return -1; } // 4. 连接(不带发布/播放参数,仅测试握手) if (!RTMP_Connect(r, NULL)) { printf("RTMP_Connect failed!\n"); RTMP_Free(r); return -1; } printf("✅ RTMP connection successful! Press any key to exit...\n"); getchar(); RTMP_Close(r); RTMP_Free(r); return 0; }逻辑说明:这个 demo 不依赖任何服务器,只要
RTMP_Connect()不返回 0,就证明librtmp.lib的 SSL、zlib、socket 三层调用链完全打通。RTMP_LogSetCallback是关键——它让你看到底层发生了什么,而不是靠printf猜。
5.2 验证工程属性配置(与 librtmp 项目严格一致)
右键rtmp_test项目 → 属性,设置:
- 常规 → 平台工具集:
v141 - C/C++ → 附加包含目录:
D:\dev\libs\librtmp-vs2017\librtmp;D:\dev\libs\OpenSSL-Win64\include;D:\dev\libs\zlib-1.2.13\contrib\vstudio\vc15\zlibstat\include - C/C++ → 预处理器定义:
OPENSSL_NO_SSL2;OPENSSL_NO_SSL3;ZLIB_WINAPI;_CRT_SECURE_NO_WARNINGS - 链接器 → 附加库目录:
D:\dev\libs\librtmp-vs2017\Debug;D:\dev\libs\OpenSSL-Win64\lib\VC\static;D:\dev\libs\zlib-1.2.13\contrib\vstudio\vc15\zlibstat\lib - 链接器 → 附加依赖项:
librtmp.lib;libssl.lib;libcrypto.lib;zlibstat.lib;ws2_32.lib;crypt32.lib - 链接器 → 输入 → 忽略特定库:
libcmt.lib;libcmtd.lib(防止与/MT冲突)
参数说明:
librtmp.lib的路径指向你编译输出的 Debug 目录(如librtmp-vs2017\Debug\librtmp.lib),不是源码目录。忽略libcmt.lib是 VS2017 的经典 workaround,避免多重定义malloc等符号。
5.3 运行验证与日志解读
按Ctrl+F5运行(不调试),你应该看到类似输出:
Setting buffer time to: 36000000ms Connected... Starting application session for live Sending play request for test ✅ RTMP connection successful! Press any key to exit...如果看到Connected...,恭喜,你的librtmp.lib已经通过终极考验。此时你可以:
- 把
librtmp.lib和librtmp/头文件打包,作为公司内部 SDK 分发; - 在 Qt、MFC 或其他 VS2017 工程中,按同样方式配置,即可直接调用;
- 若需推流,只需在
main.c中追加RTMP_EnableWrite(r); RTMP_ConnectStream(r, 0);即可。
从那以后我每次给新同事配环境,都强制走一遍这个rtmp_testdemo——它比任何文档都诚实,一行日志胜过千言解释。希望帮到你。
本文还有配套的精品资源,点击获取