前几天有朋友问我,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++项目构建流程:

  1. CMake读取 CMakeLists.txt ,判断当前系统、编译器、可用依赖。
  2. 如果开启 ENABLE_WEBRTC ,CMake会寻找SRTP库、OpenSSL库,并定义对应的宏。
  3. 编译器根据宏包含头文件、链接静态库或动态库,最终生成可执行文件。

理解这个流程很重要,因为很多人一遇到报错就盲目改代码或者删文件,其实大部分问题都出在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功能验证通过是两码事。建议你按下面的步骤逐步检查:

  1. 启动MediaServer,观察启动日志里是否有 webrtc 相关监听端口和协议栈初始化。
  2. 用浏览器打开WebRTC推流页面,看能否成功推流并拉到画面。这个环节能验证DTLS、SRTP、ICE链路是否完整。
  3. 如果推流失败,打开浏览器的开发者工具,看WebRTC内部报错。常见的有 ICE failed 、 DTLS ice role conflict 、 SRTP decrypt failed 等。
  4. 用 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。

Logo

邀请您加入社区

更多推荐