Windows下编译ZLMediaKit并启用WebRTC:完整踩坑与构建指南
前几天有朋友问我,ZLMediaKit在Windows下到底能不能编译出带WebRTC的版本。其实完全可以,步骤也没有想象中那么玄乎,但坑是真的不少。我这次专门在64位Windows 10 + Visual Studio 2022环境下完整走了一遍流程,从拉代码、装依赖、CMake配置,到最终跑通WebRTC推拉流,中间踩了四五个坑。如果你也打算在Windows上用ZLMediaKit做低延迟流媒体服务,或者想在本地折腾一下WebRTC信令和媒体转发,这篇文章应该能帮你省下不少时间。
先说清楚一个概念:ZLMediaKit是一个基于C++11的高性能流媒体服务器框架,支持RTSP、RTMP、HLS、HTTP-FLV、SRT,还有WebRTC。这里面的WebRTC模块不是默认编进去的,需要你在构建时显式打开开关,同时把依赖库准备好。Windows下最大的麻烦就在依赖库,用得不好就会出现一堆链接错误。好在这几年vcpkg已经非常成熟,大部分依赖可以一条命令拉下来,真正需要花时间的反而是理解CMake参数和排查编译错误。
1. 项目概述与环境准备
1.1 ZLMediaKit和WebRTC功能之间的关系
ZLMediaKit本身是一个多媒体服务框架,核心能力是接收各种协议的音视频流,再向终端用户分发。WebRTC是它其中一个比较特殊的接入和分发协议。普通HTTP-FLV或RTMP在浏览器播放时延迟只能做到几秒级别,WebRTC则可以把延迟压低到几百毫秒,而且不需要用户安装任何插件。
不过WebRTC不像RTMP那样只需要监听一个端口就完事。它内部涉及ICE连接管理、DTLS握手、SRTP加解密、UDP端口复用等一大堆机制。这套机制在Linux上相对好编,因为很多依赖库在Linux发行版里都有现成的包。到了Windows上就必须自己折腾一套干净的构建链。
我在Windows下编译的时候,最直观的感受是:ZLMediaKit本身代码是跨平台的,CMakeLists也维护得很好,真正卡的环节是第三方库。尤其是libsrtp和OpenSSL这两个,版本对不上、位数不对、链接库路径混乱,都非常致命。所以后面每一步都要踩稳。
1.2 为什么要在Windows上启用WebRTC
很多人的生产环境确实是Linux,但Windows下跑ZLMediaKit的需求一点都不少。比如做桌面端本地推流测试,或者内网环境里有一台Windows Server想兼做流媒体中转,又或者只是想在Visual Studio里断点调试WebRTC信令流程。
我自己遇到的实际场景是:客户那边服务器是Windows Server 2019,要求在同一台机器上跑ZLMediaKit,接收摄像头RTSP流,再通过WebRTC推给浏览器端的大屏展示。这种情况下就绕不开Windows下的WebRTC编译。
另外,Windows下编译还有一个隐性好处:如果你的业务模块也是C++写的,可以直接把ZLMediaKit作为子模块嵌入到Visual Studio解决方案里,和业务代码一起编译、一起调试,这比Linux下用gdb远程调试舒服多了。
1.3 环境准备:工具链和依赖清单
先把我这次使用的环境列出来,方便你对照参考:
- 操作系统:Windows 10 专业版 22H2(64位)
- 编译器:Visual Studio 2022 Community(17.x),需安装“使用C++的桌面开发”工作负载
- CMake:3.26.0(VS自带或单独安装均可)
- Git:2.40.x
- 包管理器:vcpkg(需要提前拉取到本地)
- 依赖库:openssl、libsrtp(带openssl feature)、zlib
为什么特别强调64位?因为WebRTC相关库和生成的服务进程,我建议直接用x64版本。一是vcpkg默认安装的版本就是x64-windows triplet,二是ZLMediaKit这类流媒体服务在高并发下需要更大内存寻址空间,三是现在绝大多数机器都是64位系统,继续用32位没有任何意义。
如果你之前用过vcpkg,记得先把vcpkg根目录配到环境变量
VCPKG_ROOT
里,后面CMake会省事很多。没有配置也没关系,在CMake命令行里手动指定toolchain文件路径效果一样。
还有一个容易被忽略的点:Visual Studio的版本会影响生成器名称。VS2022对应
Visual Studio 17 2022
,VS2019对应
Visual Studio 16 2019
,甚至还可以用Ninja。我这次用VS2022,因为后面压测时要看线程栈。
2. 编译的整体思路与方案选型
2.1 官方推荐的编译方式到底是怎么工作的
ZLMediaKit的编译通常分三步:准备代码、安装依赖、CMake配置后构建。在Windows上,官方Wiki建议用vcpkg管理依赖。把这件事拆开看,其实就是一个标准的C++项目构建流程:
-
CMake读取
CMakeLists.txt,判断当前系统、编译器、可用依赖。 -
如果开启
ENABLE_WEBRTC,CMake会寻找SRTP库、OpenSSL库,并定义对应的宏。 - 编译器根据宏包含头文件、链接静态库或动态库,最终生成可执行文件。
理解这个流程很重要,因为很多人一遇到报错就盲目改代码或者删文件,其实大部分问题都出在CMake找不到库、或者找错了库版本。
比如CMake会先找
srtp2/srtp.h
这个头文件,再找
srtp2
这个库。如果你装了libsrtp,但没把它所在目录加入搜索路径,CMake就会报
Could NOT find SRTP
。这时候你不需要改ZLMediaKit源码,只需要确保vcpkg安装正确,并且CMake能通过toolchain文件找到vcpkg里安装的库。
2.2 用vcpkg管理依赖的理由
在Windows下编译C++项目,最痛苦的就是第三方库。OpenSSL、libsrtp、zlib这些库如果全部从源码手动编译,每个都够写一篇长文,而且版本之间还有兼容性要求。vcpkg的价值在于把依赖的获取、编译、安装统一到一个环境里,还能通过
vcpkg integrate install
让Visual Studio自动识别库路径。
我选择vcpkg而不是手动编译依赖,核心原因有三个:
第一,版本一致性有保障。ZLMediaKit在CI脚本里本身就用vcpkg,所以vcpkg里的库版本组合大概率是经过验证的。你去GitHub上看ZLMediaKit项目的
windows_build.bat
,里面安装的就是openssl、libsrtp、zlib这些。
第二,支持triplet机制。vcpkg可以用
x64-windows
表示64位动态库版本,也可以换成
x64-windows-static
表示64位静态库版本。对于需要离线部署的场景,静态库会更方便。
第三,后续清理成本低。手动编译的库散落在不同目录,时间一长就忘了谁是谁。vcpkg把库统一管理,卸载和升级都是命令行操作。
当然vcpkg也不是没有缺点。我第一次编译的时候,OpenSSL从源码编译了很久,中间还遇到网络超时。这种情况可以用
VCPKG_BINARY_SOURCES
设置二进制缓存,或者直接在GitHub Releases里下载预编译的vcpkg包,官方有
vcpkg export
和
artifact
机制,但新手不用强求。
2.3 方案对比:vcpkg还是手动编译
我把两种方式的优缺点放在一起对比一下,方便你根据实际情况选择。
| 方案 | 优点 | 缺点 |
|---|---|---|
| vcpkg管理 | 自动处理依赖链,版本可控,和Visual Studio集成方便 | 首次编译OpenSSL很慢,网络不稳定可能失败 |
| 手动编译依赖 | 每个库的配置都清楚,可以按需裁剪 | 耗时长,默认参数容易踩坑,库之间容易冲突 |
| 使用别人预编译的库 | 适合快速验证,省去编译时间 | 不一定匹配你的编译器和架构,排查问题难 |
我自己的建议:如果是正式项目,优先vcpkg;如果只是临时编一个测试版,可以看看ZLMediaKit官方有没有对应的Windows Release归档。但你自己还是要会vcpkg这条路,因为后续要定制编译参数时避不开。
3. 核心细节解析:WebRTC依赖与CMake配置
3.1 WebRTC模块到底依赖了哪些库
很多人以为只要在CMake里打开
ENABLE_WEBRTC
就能成功,结果编译时冒出一堆
fatal error C1083
,原因就是把依赖想简单了。ZLMediaKit的WebRTC模块主要依赖下面几个东西:
- OpenSSL:提供DTLS握手和AES-GCM加解密能力。WebRTC的媒体加密用了SRTP,SRTP的密钥协商又依赖DTLS,而DTLS本质上是TLS在UDP上的变体,OpenSSL是最常用的基础库。
- libsrtp:Cisco开源的SRTP实现,负责把RTP包加密成SRTP包,以及解密。ZLMediaKit在实现WebRTC媒体面转发时,会直接把SRTP层的逻辑封装到内部。
- zlib:用于WebRTC统计信息里sdes支持,也可能被其他模块使用。虽然不装可能也能编过,但为了稳定还是装上。
- usrsctp:如果开启数据通道(DataChannel),还需要SCTP协议栈。不过ZLMediaKit核心的WebRTC媒体传输并不强制依赖usrsctp,所以我这次没装。
看到这里你就明白了:WebRTC不是只靠一个库就能跑起来的,而是一整套加密、传输、信令的组合。CMake的
ENABLE_WEBRTC
开关更像是一个总闸,背后还要保证所有子依赖就位。
3.2 CMake关键参数说明
ZLMediaKit的CMake参数非常多,这里只挑和WebRTC编译强相关的说明。
ENABLE_WEBRTC
是最核心的开关,必须设置为
ON
。如果你不打开,后面的WebRTC代码根本不会参与编译,即使你装了所有依赖也白搭。
ENABLE_OPENSSL
控制是否启用OpenSSL相关功能。WebRTC依赖OpenSSL,所以这个也要设为
ON
。在某些精简场景下,ZLMediaKit可以不用OpenSSL跑普通协议,但一旦开启WebRTC,OpenSSL就变成了硬依赖。
CMAKE_TOOLCHAIN_FILE
指向vcpkg的toolchain文件。这个参数至关重要,它告诉CMake去哪里找vcpkg安装的第三方库头文件和库文件。忘了设置它的话,CMake会退回系统默认搜索路径,在Windows上大概率找不到库。
举一个实际命令,假设vcpkg在
D:/vcpkg
,在PowerShell里执行:
cmake -B build -G "Visual Studio 17 2022" -A x64 `
-DCMAKE_TOOLCHAIN_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake `
-DENABLE_WEBRTC=ON `
-DENABLE_OPENSSL=ON `
-DCMAKE_BUILD_TYPE=Release
-A x64
是Visual Studio生成器下指定目标平台为64位的方式。如果你漏掉这个参数,VS生成器有时会默认生成Win32工程,然后你会发现vcpkg里装的x64库根本链接不上。
3.3 编译选项里的常见误区
第一个误区是只开
ENABLE_WEBRTC
,不装依赖。CMake即使找不到库也不会立刻报错,而是在生成时打出警告,最后很多源文件被排除,编译出来的可执行文件不带WebRTC功能。等你运行时看到日志里没有WebRTC传输层,才反应过来。
第二个误区是混淆Debug和Release依赖。vcpkg默认安装的是Release版本库,但你在Visual Studio里选了Debug配置,链接时就会出现库不匹配的警告,甚至直接链接失败。建议直接都编Release,或者额外安装debug版本的依赖,但新手没必要折腾。
第三个误区是不看CMakeCache。当你修改了参数重新生成时,CMakeCache里可能还残留旧值。最干净的办法是删掉
build
目录重新生成。我见过有人反复修改但没有删缓存,导致始终没编出WebRTC,最后才发现缓存问题。
还有一个小技巧:CMake输出日志里会打印每个开关的值和依赖库的路径,比如
OpenSSL_DIR
、
SRTP_INCLUDE_DIR
。生成完毕后,可以先搜索一下这些关键字确认路径都正确,再进入编译。
4. 实操过程:在Windows 64位下完整编译
4.1 获取ZLMediaKit源码和子模块
首先把ZLMediaKit源码拉下来。要注意这个项目不是单仓库,它依赖
media-server
和
zltoolkit
等子模块,所以拉取时必须初始化子模块。
我建议直接用这条命令:
git clone --recurse-submodules https://github.com/ZLMediaKit/ZLMediaKit.git
这样会一次性拉完主仓库和所有子模块。如果你已经用普通方式clone了,也可以进入仓库目录后执行:
git submodule update --init --recursive
子模块没有拉全的话,编译时会报找不到
zltoolkit
或
media-server
头文件。这个坑很隐蔽,因为CMake配置阶段不一定报错,等到编译阶段才突然冒出来一长串头文件找不到的错误。
拉完代码后,建议先检查一下目录结构。正常情况下会看到
server
、
src
、
tests
、
webrtc
等目录。其中
webrtc
目录主要存放WebRTC相关源文件,有它存在,说明源码完整。
4.2 安装vcpkg依赖
先确认vcpkg已经就绪。如果你还没拉vcpkg,执行:
git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat
bootstrap过程会下载vcpkg.exe,时间不长。然后安装依赖:
.\vcpkg install "libsrtp[openssl]" openssl zlib --triplet x64-windows
注意这里我用了
--triplet x64-windows
,明确指定64位动态库。如果你希望最终生成的可执行文件不依赖一堆DLL,可以换成
x64-windows-static
,但那样链接时间会更长,ZLMediaKit和其它库都要跟着用静态运行时,配置上多一层复杂度。我这次先用动态库,跑通再说。
安装过程里,OpenSSL源码编译会花掉比较长的时间,可能10到20分钟,取决于机器的CPU和网络。如果中途失败,常见原因是从GitHub下载依赖源码超时。建议给git设置代理,或者挂一个稳定的下载源,但这块涉及具体网络环境,我就不展开了。最常见的解决办法是重跑一次
vcpkg install
,它支持断点续装。
装完之后,可以通过
vcpkg list
查看已安装的库列表,确认libsrtp、openssl、zlib都在列表里。
这里有一个小经验:如果你之前安装过32位的库,务必确认当前是x64-windows。vcpkg会把不同triplet的库放在不同目录下,但CMake如果不指定,可能扫到不该扫的路径。遇到莫名其妙的问题时,可以直接在CMakeCache里搜
SRTP
、
OPENSSL
,看它指向的路径是否正确。
4.3 配置CMake并生成Visual Studio工程
依赖装好后,进入ZLMediaKit目录执行cmake命令。我习惯单独建一个
build
目录,所有构建产物都集中在这里,方便清理。
在PowerShell里,命令如下:
cmake -B build -G "Visual Studio 17 2022" -A x64 `
-DCMAKE_TOOLCHAIN_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake `
-DENABLE_WEBRTC=ON `
-DENABLE_OPENSSL=ON `
-DCMAKE_BUILD_TYPE=Release
如果你是VS2019,把生成器改成
Visual Studio 16 2019
即可。
执行成功后,输出末尾会有一段摘要,包含
WebRTC
的状态。我这次编译时,能看到类似这样的一行:
-- WebRTC support enabled
-- SRTP library found: srtp2
-- OpenSSL library found: libssl.lib;libcrypto.lib
看到这两行基本可以放心。如果没看到,先把
ENABLE_WEBRTC
、
ENABLE_OPENSSL
确认一下,再看vcpkg依赖是否真的装好了。
生成器会把ZLMediaKit编成Visual Studio的解决方案文件,位置在
build/ZLMediaKit.sln
。当然你不需要手动打开IDE,直接用命令构建更省事。
4.4 编译项目并检查产出
接下来执行构建:
cmake --build build --config Release --parallel
--parallel
会自动启用多核编译。ZLMediaKit的源码量不小,但绝大多数机器上几分钟内就能完成。
如果编译成功,
build/bin
目录下会出现
MediaServer.exe
。VS生成器通常会增加一层配置目录,所以你可能需要到
build/bin/Release
下找。如果没找到,可以搜索
MediaServer.exe
,确认具体路径。
除了MediaServer.exe,还会生成一堆测试可执行文件,比如
test_rtp
、
test_webRtc
之类的。这些测试程序会依赖DLL,运行时可能需要把vcpkg安装目录下的DLL拷过来。
最简单的办法是直接用vcpkg自带的
applocal
工具,它会在构建后自动把依赖DLL复制到可执行文件目录。不过我没细配,直接手动从
D:/vcpkg/installed/x64-windows/bin
下把
libssl-3-x64.dll
、
libcrypto-3-x64.dll
、
libsrtp2.dll
、
zlib1.dll
复制到了
Release
目录。
运行
MediaServer.exe
前,建议先确认工作目录。ZLMediaKit默认会从当前目录加载
config.ini
,如果找不到就使用内置默认配置。为了不污染源码目录,我通常在
build/bin/Release
下直接执行,然后把日志打开。
4.5 验证WebRTC是否真的编译进去了
编出来了不代表WebRTC已经生效,还要做一次运行时验证。
先启动MediaServer:
.\MediaServer.exe -l 7
-l 7
是设置日志级别为debug,能看到更详细的WebRTC传输日志。启动后控制台会打印监听的端口,比如
HTTP默认端口80
、
RTSP端口554
等。如果WebRTC模块初始化成功,日志里通常会有WebRTC相关端口监听的记录。
然后打开浏览器,访问ZLMediaKit自带的WebRTC测试页面。如果你没有额外部署前端,可以直接用GitHub仓库里的
www
目录下的页面,启动后访问
http://127.0.0.1/webrtc
即可看到推流页面。
在页面上使用摄像头推流,如果页面显示连接成功、视频画面正常出来,说明WebRTC媒体通道已经走通了。此时控制台日志里会出现ICE、DTLS、SRTP等关键词,比如
dtls transport completed
或者
ice channel opened
。
这一步验证很有必要。我遇到过编译成功但WebRTC功能没开启的情况,就是因为CMake缓存里没有真正打开
ENABLE_WEBRTC
。所以不管编译阶段多顺利,最后都要用浏览器实际推流一次,才算大功告成。
顺带一提,ZLMediaKit的WebRTC实现默认支持WHEP和WHIP,这意味着你也可以用现成的OBS插件或者其他WebRTC推拉流工具来测试,不一定要用浏览器页面。
5. 常见问题与排查技巧
5.1 编译错误速查表
为了节省你翻日志的时间,我把这次编译过程中遇到的和一些常见的错误整理成了表格。
| 错误现象 | 可能原因 | 解决办法 |
|---|---|---|
Could NOT find SRTP
| libsrtp未安装,或triplet不对 |
执行
vcpkg install libsrtp[openssl] --triplet x64-windows
|
fatal error C1083: 无法打开包括文件: "srtp2/srtp.h"
| 头文件路径没被CMake搜索到 |
检查
CMAKE_TOOLCHAIN_FILE
是否指向vcpkg;检查CMakeCache里的
SRTP_INCLUDE_DIR
|
LNK1181: 无法打开输入文件 "libssl.lib"
| OpenSSL库路径错误,或只安装了32位 |
执行
vcpkg install openssl --triplet x64-windows
,确认生成器为
-A x64
|
| 编译产物中没有MediaServer.exe | 构建配置生成到了其它目录 |
在
build
目录里搜索
MediaServer.exe
,部分VS生成器会放到
bin/Release
|
运行时提示缺少
libcrypto-3-x64.dll
| 依赖DLL没有复制到exe目录 |
从
vcpkg/installed/x64-windows/bin
复制相关DLL到exe同目录
|
| 运行后日志无WebRTC监听 |
编译时
ENABLE_WEBRTC
未真正打开
|
删除
build
目录重新生成,确认CMake输出中WebRTC support enabled
|
| 页面推流失败但普通RTMP正常 | WebRTC底层加密握手失败,通常是OpenSSL版本有问题 | 检查vcpkg中openssl版本,重新安装并重新编译;确认本机没混入其它路径的OpenSSL |
| 构建速度极慢 | 一次性编译依赖库加上主项目 |
使用
--parallel
,或只编MediaServer目标而非ALL_BUILD
|
5.2 几个容易踩的坑
第一个坑是CMake缓存污染。ZLMediaKit依赖的路径一旦被记录进
CMakeCache.txt
,不会因为你修改环境变量就自动更新。我试过从32位切到64位时,忘了删build目录,导致几个小时都在排查库不匹配。后来的操作习惯是:改架构、改依赖、改关键开关时,先
rm -rf build
再从零生成。
第二个坑是vcpkg安装的版本和ZLMediaKit期望的版本不兼容。比如libsrtp有两个大版本,vcpkg默认可能装的2.x,但ZLMediaKit某些版本要求3.x。遇到这类问题,最好去GitHub上看该版本对应的
win_deps.bat
里锁定的vcpkg版本,必要时手动指定
vcpkg install libsrtp@3.0.0
之类。我这次用的ZLMediaKit master分支,libsrtp2可以直接用,但网络上有朋友反馈特定旧版本分支会碰到不兼容。
第三个坑是PATH环境变量干扰。Windows上如果你之前装过独立版的OpenSSL,它的DLL可能在
C:\Windows\System32
或者某个安装目录。当
MediaServer.exe
启动时,Windows会优先从PATH里找DLL,导致你的exe加载了错误版本的libcrypto,运行到DTLS握手阶段崩溃。排查方法是把vcpkg的bin目录放在PATH最前面,或者干脆复制DLL到exe目录并删掉系统PATH里的冲突项。
5.3 验证WebRTC功能是不是“真通了”
编译通过和WebRTC功能验证通过是两码事。建议你按下面的步骤逐步检查:
-
启动MediaServer,观察启动日志里是否有
webrtc相关监听端口和协议栈初始化。 - 用浏览器打开WebRTC推流页面,看能否成功推流并拉到画面。这个环节能验证DTLS、SRTP、ICE链路是否完整。
-
如果推流失败,打开浏览器的开发者工具,看WebRTC内部报错。常见的有
ICE failed、DTLS ice role conflict、SRTP decrypt failed等。 -
用
MediaServer的HTTP API检查流列表。比如访问http://127.0.0.1/index/api/getMediaList,看是否出现WebRTC协议的流。
我还发现一个比较实用的定位方式:在ZLMediaKit日志级别开到
-l 7
后,WebRTC传输层会打印ICE候选地址、DTLS指纹、SRTP密钥状态。如果你的WebRTC推流一直卡在“连接中”,多半是UDP端口没有放通。Windows防火墙对UDP端口的拦截很隐蔽,普通HTTP能通但UDP不通的情况特别多。记得在Windows防火墙里放行MediaServer.exe的所有进出UDP端口。
5.4 提高编译效率的小技巧
如果你需要反复修改源码和测试,每次全量编译确实浪费时间。我这边有两个经验:
一是在CMake时启用Ninja生成器。Ninja在Windows下比VS生成器快不少,特别是增量编译时。命令类似:
cmake -B build-ninja -G Ninja -A x64 `
-DCMAKE_TOOLCHAIN_FILE=D:/vcpkg/scripts/buildsystems/vcpkg.cmake `
-DENABLE_WEBRTC=ON `
-DENABLE_OPENSSL=ON
使用Ninja前要确保
ninja
在PATH里,Visual Studio安装时自带的Ninja通常可以用
vcvars64.bat
启用环境变量。
二是只编译需要的目标。ZLMediaKit的
ALL_BUILD
会编所有测试程序,很费时间。如果你只需要服务端,可以编译
MediaServer
目标:
cmake --build build --config Release --target MediaServer --parallel
如果后面想跑单元测试,再单独编译对应测试目标即可。
写在最后
我实际把Windows下这套流程完整跑过几遍之后,最深的感受是:ZLMediaKit本身的代码非常良心,CMake脚本写得清楚,真正让人头疼的是Windows生态里的依赖库管理。只要把vcpkg和CMake的配合关系理顺,后面基本就是一条直线走到底。
最后再分享一个小技巧:如果你在Windows下编译时遇到了诡异问题,第一件事别去改源码,先删掉
build
目录,关掉多余终端,重新执行一次从
cmake -B build
开始的完整流程。这个简单的操作能消灭至少一半以上的问题。真不行再去GitHub翻issue,搜索框里直接打
ENABLE_WEBRTC Windows
,通常能找到同路人。希望这篇东西能帮你在Windows上顺利跑起带WebRTC的ZLMediaKit。
更多推荐
所有评论(0)