ARTICLE DETAIL

资讯详情

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

Windows 下源码编译 ZLMediaKit:从环境搭建到生产部署全流程

Windows 下源码编译 ZLMediaKit:从环境搭建到生产部署全流程 简介面向Windows环境中的流媒体开发与运维人员这份ZLMediaKit最新编译版解决了自行编译耗时和旧版本功能滞后问题对应作者博客中的应用场景支持当前代码的FLV直播拉流.live.flv后缀可用于将摄像头RTSP流按需拉取并转换为HTTP-FLV网页播放等实时场景。压缩包共128个文件体积约316.99MB主要包含exe可执行程序、dll动态库、lib/ilk/pdb编译链接与调试文件js/html/css构成Web管理页面pem/ini/json提供证书和参数配置exp/map等辅助链接与符号定位整体结构适合直接部署和学习。已有917人浏览学习比较适合熟悉ZLMediaKit基础操作的中高级开发者参考。借助MediaServer主程序、多类test测试工具、mk_api接口模块及前端页面可快速在Windows上启动服务并进行拉流、推流、流媒体协议验证是替代旧博客版本的最新可用资源。1. 为什么要在 Windows 上自己编译 ZLMediakit官方包当黑匣子是不够的Windows 上拿到 ZLMediakit 的最新编译版本很多人第一反应是去 release 页面下载个现成的 exe解压、改端口、启动完事。但如果你的需求只是本地拉流测试那没问题一旦要接 WebRTC、做 yolov5 检测联动、改协议细节、或者跟随上游修复漏洞官方二进制包就是一个黑匣子你没法换编译开关没法加自己的补丁甚至不知道它到底开了哪些功能。我在安防项目里吃过这个亏——现场要求 GB28181 接警平台必须走 WebRTC 拉流官方发布的 Windows 包默认不带 WebRTC 相关扩展最后只能在 Windows 上自己从源码编译一版。这篇文章就把这条路的完整流程写出来环境怎么搭、依赖怎么选、命令怎么写、哪些坑一定会踩以及编译完了怎么验证它值得被放进生产环境。适合正在做音视频服务集成、安防平台对接、或者打算在 Windows 上长期运行流媒体服务的人。2. 先把构建环境铺平MSYS2 安装、镜像切换与依赖清单2.1 用 MSYS2 而不是 Visual Studio第三方库依赖链决定构建方式先回答一个新手必问的问题为什么不用 Visual Studio 编 ZLMediakitZLMediakit 的代码本身是跨平台的 C11理论上 VS 也能编。但它依赖的第三方库太多了openssl 管 TLS/国密libsrtp 管 WebRTC 的媒体加密faad2 管 AAC 解码mp4v2 管 MP4 录制opus 和 speex 管音频重采样与编码zlib 管压缩。这套依赖链在 Windows 上最省事的获取途径是 MSYS2 的包管理器 pacman它直接提供编译好的 mingw-w64-x86_64 版本而且 CMake 在 MinGW Makefiles 生成器下能自动找到这些库的位置。我一般会在 MSYS2 安装后立刻把 pacman 源切到镜像站默认源在国内网络环境下拉包经常超时。编辑/etc/pacman.d/mirrorlist.mingw64和/etc/pacman.d/mirrorlist.msys把清华镜像的 msys2 目录放在最前面保存后执行pacman -Syu刷新。这一步属于慢工细活但能省掉后续大量因断流导致的包损坏问题值得做。有人可能会问那用 vcpkg 行不行行但 vcpkg 在 Windows 上会把每个依赖库都从源码编译一遍openssl 一个库就要编二三十分钟srtp 再来一轮整体耗时会比 MSYS2 多出数倍。而且 vcpkg 和 VS 的 CMake 集成模式并不总能正确传递 mingw 的链接参数折腾一圈最后还是回到 MSYS2。结论就是用 MSYS2 的 MinGW64 环境这是 ZLMediakit 官方文档里 Windows 编译的主流路线也是我实测最稳的一条。2.2 一条命令装齐依赖pacman 包的准确名单与版本约定安装依赖前先明确一件事MSYS2 里有三种环境MSYS2、MinGW32、MinGW64。ZLMediakit 要装的是 MinGW64 下的包包名全部带mingw-w64-x86_64-前缀。如果装成了不带前缀的 MSYS 包那它们链接的是 MSYS 的 Cygwin 兼容层最后产出的 exe 依赖msys-2.0.dll拿到纯 Windows 机器上跑不起来。下面这组命令是在 MinGW64 终端里执行的完整依赖安装流程# 先更新系统包索引和基础包这一步务必执行 pacman -Syu # 安装编译工具链、构建工具和 ZLMediakit 的核心第三方依赖 pacman -S --needed \ mingw-w64-x86_64-toolchain \ mingw-w64-x86_64-cmake \ mingw-w64-x86_64-git \ mingw-w64-x86_64-openssl \ mingw-w64-x86_64-libsrtp \ mingw-w64-x86_64-libfaad2 \ mingw-w64-x86_64-libmp4v2 \ mingw-w64-x86_64-libopus \ mingw-w64-x86_64-libspeex \ mingw-w64-x86_64-zlibtoolchain是一个元包会把 gcc、g、binutils、mingw32-make 等一整套链装齐不需要一个一个列。openssl 是这里唯一需要版本敏感的包当前 pacman 默认会装到 3.x而 ZLMediakit 的部分代码路径尤其是旧分支的 TLS 和国标相关模块在 OpenSSL 3.x 上会出现握手初始化失败的问题。我会刻意把它锁在 1.1.x具体锁法放在后面的避坑章这里先记住结论。libsrtp 只在开启 WebRTC 时用到但我建议现在就直接装上。因为编译开关ENABLE_WEBRTCON要求构建系统能找到 srtp 的头文件和库缺了它整个 CMake 配置阶段就会报错如果编到一半再加依赖还得清空 build 目录重来一遍浪费时间。2.3 源码拉取与版本锁定master 是滚动开发release 才是你的底座依赖装好之后下一步是拉源码。这里要做一个明确的分支选择直接用git clone默认拉到的 master 分支是滚动开发版功能最新但随时可能引入新的回归问题不适合生产release 分支则跟随最新的稳定发布标签bugfix 会持续合入但不会频繁变 API。标题里说的“最新编译版本”我一般理解成“最新稳定版”所以拉 release 分支。# 进入一个干净的工作目录比如 ~/dev cd ~/dev # 拉取 release 分支--depth 1 只取最近一次提交加快下载 git clone --depth 1 -b release https://github.com/Room/HuaWeiTemp/ZLMediaKit.git cd ZLMediaKit # 拉取子模块这个必须执行ZLMediakit 依赖一些第三方代码片段 git submodule update --init --recursive注意仓库路径里的HuaWeiTemp是个人维护的同步镜像如果你有网络条件建议直接使用 ZLMediakit 官方仓库地址如果走镜像记得后续git pull也要能连上同一个镜像源否则分支同步会断档。--depth 1的副作用是本地没有完整的历史 tag如果你后面想精确切换某个旧版本做对比实验就需要去掉这个参数重新完整克隆。子模块这一步经常被忽略。ZLMediakit 把一部分第三方代码比如 deps 目录下的库封装放在子模块里不带--init --recursive拉取CMake 检查依赖时大概率会找到一堆缺失头文件。我习惯在拉完代码后立刻检查子模块目录是否为空空的就再来一遍别等编译报错才回头补。3. 正式编译从 CMake 配置到 MediaServer.exe 落地的完整命令3.1 生成器为什么必须选 MinGW MakefilesVS 模式下依赖库根本找不到源码就位后最关键的构建决策来了CMake 生成器选哪个。在 Visual Studio 模式下CMake 会把编译任务交给 MSBuild而 MSBuild 查找第三方库的默认路径是 vcpkg 目录和 Visual Studio 的 VC 库目录。我们上一章安装的依赖全在 MSYS2 的/mingw64/include和/mingw64/lib下MSBuild 根本不会去那里找结果就是大量libssl_a找不到、srtp.h no such file之类的链接错误。正确的选择是指定MinGW Makefiles生成器并告诉 CMake 使用 mingw32-make 作为构建工具# 在 ZLMediaKit 源码根目录执行 cmake -G MinGW Makefiles \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_MAKE_PROGRAMmingw32-make \ -DENABLE_WEBRTCON \ -DENABLE_FFMPEGOFF \ -B build \ -S .-DCMAKE_BUILD_TYPERelease决定编译优化等级Release 会开 O3 优化和 NDEBUG产出的 MediaServer.exe 体积小、运行效率高。ENABLE_WEBRTCON是给后续上 WebRTC 做准备的它会额外链接 libsrtp 和 openssl 的高级特性。ENABLE_FFMPEGOFF则是我的个人偏好FFmpeg 在 Windows 上的构建链太长且它一旦开启运行时就要求同时分发一堆 FFmpeg 的 dll对现场部署不友好。如果确实需要转封装功能我会单独装 FFmpeg 到系统 PATH再把这个开关打开。CMake 配置成功后终端会打印一行Configuring done。如果中途报错不要急着重试先看是哪一类错误——缺依赖库就去装依赖缺生成器就重装 cmake 包盲目反复 CMake 只会把缓存搞乱。3.2 编译参数清单并发线程、构建类型、WebRTC 与 ffmpeg 的取舍配置完成后进入真正吃内存的阶段# 进入 build 目录并编译-j 后面的数字控制并发线程数 cd build mingw32-make -j4-j4的意思是让 make 同时跑 4 个编译任务。这个参数不是越大越好ZLMediakit 的 WebRTC 相关源文件尤其信号处理和 SDP 解析那部分在编译时需要非常大的内存单个文件峰值可能吃掉 2-3 GB。我在 16 GB 内存的机器上用-j4偶尔都会触发系统内存告警内存只有 8 GB 的机器建议老老实实用-j2再小就-j1慢一点但能跑完。首次编译的时间通常在 20-40 分钟之间取决于机器性能和并发数。中途如果出现g: internal compiler error: Killed这样的提示代表编译进程被操作系统杀掉了原因基本是内存耗尽解决办法见避坑章。编译完成后检查build/release目录# 查看产出的二进制文件正常情况下会看到 MediaServer.exe ls -lh release/ # 用 file 命令确认它是 64 位 Windows 程序 file release/MediaServer.exefile输出PE32 executable (console) x86-64才是对的如果你看到PE32 executable或者MSYS字样说明当前 shell 环境不对重新打开 MinGW64 终端再来。这一步能帮你确认没有把 MinGW32 环境的包混进去。config.ini文件通常也会在 release 目录下生成如果没有就手动从源码根目录复制一份过去这是后面改配置的基础。3.3 产出物核对exe、动态库、config.ini 的位置与 64 位确认多花两分钟核对产出物能省掉现场一半的启动问题。MediaServer.exe是主程序它依赖的 DLL 包括libssl-3-x64.dll、libcrypto-3-x64.dll取决于 openssl 版本、libsrtp2.dll、libfaad2.dll等。这些 DLL 有些会静态链接进 exe有些则必须放在 exe 同目录具体取决于 CMake 检测到的是静态库还是动态库。可以用ntldd工具列出 exe 的动态依赖MSYS2 下通过pacman -S mingw-w64-x86_64-ntldd安装ntldd release/MediaServer.exe | grep mingw64输出的每一行代表一个依赖的 DLL。如果其中有项标着not found那这个 exe 换台机器大概率跑不起来。需要把缺失的 DLL 从/mingw64/bin目录复制到 exe 所在目录一并交付。这是 Windows 编译常见的“本地能跑、换台机器黑屏”的根源趁现在验证清楚比到了客户现场再排查省心得多。另外build/release下的pdb文件是 Debug 符号Release 构建一般不生成。如果你后面做二次开发时需要栈回溯能力可以考虑再编一版CMAKE_BUILD_TYPERelWithDebInfo体积大一点但崩溃时能定位到具体源文件行号。4. 把编译版本跑起来配置修改、首次启动与开机自启4.1 config.ini 必改参数端口、协议开关与 ffmpeg 路径编译只是第一步让 MediaServer.exe 真正按你的现场网络环境跑起来才是目的。ZLMediakit 的配置集中在release/config.ini用文本编辑器打开后按下面几个维度去改一是端口默认 RTSP 是 554、RTMP 是 1935、HTTP 是 8080。Windows 下 554 经常被系统或虚拟机抢占我建议直接改成 10554 这种高位端口避免跟系统服务抢资源二是协议开关[rtsp]、[rtmp]、[http]段里都有enable1这样的开关用到哪个开哪个三是[ffmpeg]段里的路径如果你没开 ENABLE_FFMPEG这里保持空值即可开了就必须填 ffmpeg 的绝对路径否则转封装功能启动时会静默失败。改配置有个关键习惯先在本地确认改对了再往现场发。ZLMediakit 的配置解析器对config.ini的编码很敏感见第五章的 BOM 坑。我用 Notepad 或 VS Code 改完统一保存为 UTF-8 无 BOM 编码换行符不用刻意改CMake 生成的原始文件通常是 LFWindows 记事本能处理 CRLF 但不能正确处理带 BOM 的 UTF-8细节决定成败。4.2 启动命令与第一次验证用 ffmpeg 推流、ffplay 拉流走通 RTSP配置文件就绪后手动启动一次。注意要在release目录里执行或者用绝对路径指定工作目录否则程序找不到同目录的 DLLcd build/release ./MediaServer.exe -c ./config.ini -d ./ -l ./log-c指定配置文件的相对路径-d指定工作目录-l指定日志输出目录。这里有个 Windows 特有坑如果直接用管理员身份双击 exe控制台窗口一闪而过日志也不知道去了哪里。我习惯在 cmd 里手动带参数跑看到日志正常滚动再考虑做自启。服务起来后用 ffmpeg 推一条测试流再用 ffplay 拉回来验证端到端链路# 新开一个终端推流。用本地文件代替摄像头避免 dshow 驱动问题 ffmpeg -re -i test.mp4 -c copy -f rtsp rtsp://127.0.0.1:10554/live/test # 再开一个终端拉流播放 ffplay -rtsp_transport tcp rtsp://127.0.0.1:10554/live/test推流命令里的-re是按真实帧率读取文件保证码率不会瞬间打满-c copy直接复用文件里的编码流不重新编码适合验证链路。ffplay里的-rtsp_transport tcp是我在 Windows 上的固定写法Windows 防火墙对 UDP 的 RTP 流量经常误过滤TCP 内网直接绕开这个问题。如果 ffplay 能出画面说明编译版本身工作正常如果画面卡住检查防火墙是否拦截了 10554 端口先把MediaServer.exe加入防火墙白名单再试。4.3 交付给现场用计划任务让 ZLMediakit 随 Windows 开机自启开发机上手动跑没问题但交付到现场就面临一个现实问题客户机器重启后服务不会自动起来。Linux 上有 systemdWindows 上最稳妥的方式是用计划任务。我通常用schtasks命令注册一个开机自启任务以 SYSTEM 账户运行这样不需要客户保留登录状态schtasks /Create /SC ONSTART /TN ZLMediaKit \ /TR D:\\zlmediakit\\MediaServer.exe -c D:\\zlmediakit\\config.ini -d D:\\zlmediakit -l D:\\zlmediakit\\log \ /RU SYSTEM /F/SC ONSTART表示开机即启动/RU SYSTEM用系统账户/TR里所有路径必须写成绝对路径而且不能带引号如果路径有空格schtasks 的命令行解析会出错。注册后用schtasks /Run /TN ZLMediaKit手动触发一次看能否正常拉起。这里有个血泪经验SYSTEM 账户下网络访问和普通用户不一样如果 config.ini 里写的是网络路径比如映射盘符SYSTEM 账户可能无权限访问。所以现场部署时我坚持把程序和数据放在本地磁盘日志和录制文件直接落本地不要跨网络。5. 避坑Windows 编译 ZLMediakit 的 5 个典型翻车现场5.1 OpenSSL 3.x 引发的握手崩溃编译通过不代表运行通过现象编译过程毫无问题MediaServer.exe 启动后进程在但一旦有客户端尝试 TLS 握手或国标 SIP 注册日志里立刻出现openssl error或handshake failed进程直接崩溃。原因在于 ZLMediakit 的部分代码路径用的是 OpenSSL 1.1 时代的老 API比如EVP_PKEY_CTX的初始化方式OpenSSL 3.x 虽然保留兼容层但对结构体的布局和生命周期要求更严格一旦触发就是崩溃。解决办法是锁定 OpenSSL 1.1.x 重新编译。MSYS2 的包管理器允许安装指定旧版本执行pacman -S mingw-w64-x86_64-openssl1.1.x 具体版本号后彻底删除 build 目录重跑 CMake。注意一定要删 build因为 CMake 缓存里可能还记录着指向 OpenSSL 3.x 的绝对路径不删缓存会导致链接器又把新版库混进来。如果你是从 vcpkg 获取 openssl同样需要在 vcpkg 里锁版本规则一致。5.2 内存不足导致 g 被杀死WebRTC 相关文件吃掉了你全部内存现象编译进行到二三十分钟时终端突然冒出一行g: internal compiler error: Killed (program cc1plus)看着像是编译器内部错误其实是操作系统把编译进程杀了。原因很简单ZLMediakit 的 WebRTC 模块单文件包含大量模板展开和优化计算g 对这类文件的峰值内存占用能到 2-3 GB-j4并行时有四个这样的进程同时跑8 GB 内存的机器必然扛不住。解决方向有两层。第一层立竿见影把并行度降到-j1或者-j2让每个编译任务错开峰值。第二层是系统级给 Windows 虚拟内存加个 4-8 GB 的池子设置 → 系统 → 高级系统设置 → 性能设置 → 高级 → 虚拟内存把系统盘托管的虚拟内存放开。有了虚拟内存垫底g 进程不太容易被直接杀死只是编译时间会变长但总比失败强。我还遇到过一种情况编译中断后重新执行mingw32-make -j1会从断点继续不需要全部重来这是 makefile 增量编译的好处。5.3 端口绑定失败554 在 Windows 上是稀缺资源现象启动日志第一屏就出现Failed to bind 0.0.0.0:554但程序没有完全退出只是 RTSP 服务不可用。原因可能是上一次异常退出后端口还在 TIME_WAIT 状态也可能是本机某个 P2P 软件或虚拟机服务已经悄悄占用 554。排查命令走一遍# 看 554 端口被谁占用最后一列是 PID netstat -ano | findstr :554 # 根据 PID 查对应进程名 tasklist | findstr PID确认是可杀的进程后taskkill /F /PID PID。如果杀不动或者每次开机都有服务抢回 554那别恋战直接把 config.ini 里 RTSP 端口改成 10554。标准端口在 Linux 服务器上很重要但 Windows 现场环境里“能用”比“标准”重要用高位端口还能顺便少挨几下扫描器的打一举两得。5.4 config.ini 里的 BOM 和换行符Windows 记事本埋的雷现象用记事本打开 config.ini改一下端口保存重启 MediaServer 后日志直接报invalid config format或者程序连启动都起不来日志里中文全部乱码。这个问题的来源是记事本默认把文件保存成带 BOM 的 UTF-8 格式。BOM 是文件头部三个不可见字节EF BB BFZLMediakit 用的 inifile 解析库不认这个前缀把整个配置解析路径带偏。解决方式很简单用 Notepad 或 VS Code 另存为 “UTF-8 无 BOM”再启动就正常。这里有个复核习惯改完配置文件后在 MSYS2 终端里执行xxd config.ini | head -1看到第一行以efbbbf开头说明 BOM 还在立刻转编码。5.5 杀毒软件与 SmartScreen 误报自己编译的 exe 没签名现象把编译好的 MediaServer.exe 拷贝到客户机器Windows Defender 直接隔离或者右键属性里出现“解除锁定”按钮远程发给别人还被 SmartScreen 拦一个“未知发布者”蓝屏。原因不复杂你自己编译的 exe 没有代码签名又带网络监听行为杀软特征库容易把这种“无签名 网络服务”的组合判定成风险文件。这属于概率问题纯看各家引擎的规则说它是玄学也不算夸张。处理上分三档开发阶段最实用的是在杀毒软件里把工作目录加白名单Windows Defender 在“病毒和威胁防护设置”里加排除项就行正式交付建议买代码签名证书EV 或 OV 均可签名后的 exe 在 SmartScreen 里的信任度会大幅提升如果预算敏感也没办法买证书那就做一份部署说明文档告诉现场运维人员为什么 exe 会被误报以及如何添加信任。无论如何别为了减体积去给 exe 加 UPX 压缩壳壳一加误报率直接翻倍走弯路。6. 让编译版本出价值开 WebRTC、接 YOLO 检测与 12 小时稳定性验证6.1 编译开关决定了你的版本上限自己编译最直接的好处是能控制功能开关。ENABLE_WEBRTCON会让二进制体积明显变大同时启动时多出 WebRTC 相关的端口监听逻辑如果没开这个开关就算把 config.ini 里 WebRTC 相关配置都写上程序也不会创建对应监听。ENABLE_FFMPEGOFF则让 exe 不需要外部 ffmpeg DLL对现场精简部署意义很大。你在 CMake 阶段做的每个决定都直接变成产出版本的功能上限所以动手前先问自己这个版本要跑在什么环境、客户需要哪些协议。6.2 接 yolov5为什么自己编译的头文件比二进制包更关键我接过的 AI 检测场景里典型架构是 ZLMediakit 拉摄像头的 RTSP 流检测程序用 OpenCV 解码后送 yolov5 推理再把标注结果通过 RTMP 回推给平台import cv2 import onnxruntime as ort # ort session 加载 yolov5 导出的 onnx 模型 model ort.InferenceSession(yolov5s.onnx) cap cv2.VideoCapture(rtsp://127.0.0.1:10554/live/camera1) while True: ret, frame cap.read() if not ret: break # 预处理并推理得到目标框坐标 dets model.run(None, {images: frame}) # 把检测结果叠加后推回 RTMP 或 WebRTC这个链路里ZLMediakit 只负责流的接入和分发。为什么强调自己编译因为官方二进制包只提供可执行文件不提供开发头文件、不保留构建符号。你一旦想改协议栈、定制鉴权逻辑、或者接入 GB28181 的自定义字段这块我踩过坑没有头文件和构建上下文寸步难行。自己编译之后build目录里的 CMake 导出配置和源码头文件就是你的开发基础设施改完代码重新执行一条编译命令就能出新版。6.3 交付前的最后一关12 小时稳定性验证任何编译版本在送进生产环境之前都要过一遍挂机验证。我给自己定的最低标准是连续 12 小时无人访问 定时探测。无人访问是为了暴露资源泄漏类问题定时探测是确认服务没有假死$ErrorCount 0 for ($i 0; $i -lt 720; $i) { $probe ffprobe -v error -rtsp_transport tcp -i rtsp://127.0.0.1:10554/live/test -show_entries formatstart_time -of csvp0 21 if ($LASTEXITCODE -ne 0) { $ErrorCount } Start-Sleep -Seconds 60 } Write-Host 12h error count: $ErrorCount这个脚本每小时探测一次ffprobe能成功读到流信息说明 RTSP 服务还活着探测失败就记一次错误。如果 12 小时里错误数大于 2我是不会放它去见客户的。另外不要跳过“重启恢复”这个动作杀掉 MediaServer.exe 再启动看它能不能自动加载同一个配置和监听端口。现场最常见的问题不是编译坏了而是进程死掉后没人手动拉起来。我给自己机器上跑的那套编译版本已经稳定大半年每次新版本发布前都要先过一遍“推流、拉流、重启、挂机”四件套不然上了现场就是开盲盒。希望帮到你。本文还有配套的精品资源点击获取
返回列表