ZLMediaKit 在Window上本地模拟预览报错排查教程
场景:按
start_sim.bat在 Windows 本地用 FFmpeg + MediaMTX + ZLMediaKit 模拟摄像头预览时,ZLMediaKit 侧出现的各类报错、原因与解决办法。本文按"启动 → 建流 API → FFmpeg/MediaMTX → 前端播放 → 释放"五个阶段归类,最后一节给"快速定位决策树 + 配置核对清单"。
摄像头视频预览实现教程:从原理到落地(ZLMediaKit+ flv.js+ Spring Boot):
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/163018250
先看清 ZLMediaKit 返回的错误码
调用 ZLMediaKit 的 HTTP API(如 addStreamProxy/getServerConfig)时,返回 JSON 里带 code 字段,code=0 表示成功,非 0 表示失败。常用语义(不同版本数值可能略有差异,以官方为准):
| code | 含义 | 典型触发 |
|---|---|---|
0 |
成功 | 正常 |
-1 |
失败(通用) | 内部错误、流已存在等 |
-2 |
不支持 | 操作/协议不支持 |
-3 |
无权限(鉴权失败) | secret 与 config.ini [api].secret 不一致 |
-4 |
未找到(源不存在) | 关流时 streamKey 写错、流已不在 |
| 其他负数 | 参数/资源等具体错误 | 缺少必填参数、资源冲突等 |
⚠️ 最重要的一条认知 :
addStreamProxy返回code=0只代表"代理已创建",并不代表 RTSP 源真的连上了 。真正的拉流是异步进行的------源连不上时,建流接口照样返回 0,但前端播放会黑屏。判断"源是否真连上"要看 ZLM 日志 或/index/api/getMediaList。
一、阶段一:ZLMediaKit 启动报错
1.1 端口被占用:Bind 0.0.0.0:80 failed / 程序闪退
-
现象 :启动
MediaServer.exe后控制台刷Bind 0.0.0.0:80 failed ... Address already in use,随后程序退出。 -
原因 :Windows 上 80 端口常被 IIS / World Wide Web Publishing / 系统进程(SVCHOST) 占用;也可能是 554/1935 被别的流媒体占用。
-
解决:
-
查占用:
netstat -ano | findstr :80→ 看 PID,任务管理器结束对应进程(IIS 可iisreset /stop)。 -
更稳妥 :改
config.ini端口,避开 80:ini[http] port=8080 # 【本项实际值】本地模拟即用 8080并同步 改项目
application.yml的zlm.http-port=8080,以及前端播放地址端口。 -
防火墙放行新端口:
netsh advfirewall firewall add rule name="ZLM-HTTP" dir=in action=allow protocol=TCP localport=8080。
-
1.2 找不到配置文件 / Load config failed
-
现象 :启动报找不到
config.ini,或用了默认空配置。 -
原因 :没带
-c参数,或工作目录不在config.ini所在目录。 -
解决:启动时显式指定:
batcd /d D:\tools\ZLMediaKit MediaServer.exe -c config.ini(脚本
start_sim.bat已用cd /d %ZLM_DIR% && MediaServer.exe,注意它实际未带-c也能跑,因为同目录默认识别config.ini。)
1.3 缺少运行库:0xc000007b / 缺少 VCRUNTIME / MSVCP 等 DLL
- 现象 :双击
MediaServer.exe报应用程序错误、缺 DLL。 - 原因:系统缺少 Visual C++ 运行库,或下了"源码版"而非预编译包。
- 解决 :安装 Visual C++ Redistributable(2015--2022) ;务必从 GitHub Release 下载
windows.zip/ZLMediaKit_win64预编译包,而非源码压缩包。
1.4 启动后无监听 / 立即退出(无任何日志)
- 原因 :多半是端口冲突(见 1.1)或
config.ini有非法段导致解析中断。 - 解决 :先看控制台第一行日志定位;用
netstat -ano | findstr :8080确认是否在监听;临时把config.ini换成官方默认文件排除配置问题。
二、阶段二:调用 API 建流报错(addStreamProxy / getServerConfig)
2.1 getServerConfig 返回鉴权失败 / 空白 / 403
- 现象 :浏览器打开
http://127.0.0.1:8080/index/api/getServerConfig?secret=xxx返回错误 JSON 或无数据。 - 原因 :URL 里的
secret与config.ini [api].secret不一致 (最常见);或忘记带secret参数。 - 解决 :
- 确认两端完全一致;改了
config.ini的 secret 必须重启 ZLM 才生效(不是热加载)。 - 本项目实际:
secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc,且application.yml的zlm.secret必须与之相同。
- 确认两端完全一致;改了
2.2 addStreamProxy 返回 code=-3(无权限)
- 现象 :后端日志/接口返回
{"code":-3,...}。 - 原因 :后端
ZlmProperties.secret与 ZLM 的secret不一致,或调用时secret参数拼错。 - 解决 :核对
application.yml的zlm.secret=config.ini [api].secret,重启两端。
2.3 addStreamProxy 返回 code=-1 / 其他非 0
- 现象:建流接口返回失败,但非鉴权类错误。
- 原因 :
- 流已存在 (幂等场景):同一
app/stream已建过,ZLM 报资源冲突。本项目后端已做 try-catch 忽略异常、照常返回播放地址,可忽略。 - 缺少必填参数(
vhost/app/stream/url之一缺失)。 rtp_type取值非法。
- 流已存在 (幂等场景):同一
- 解决 :确认请求参数齐全;流已存在时无需处理(前端照常播放);用
getMediaList确认该流状态。
2.4 addStreamProxy 返回 0,但播放黑屏(高频坑)
- 现象 :接口
code=0,前端却一直黑屏/转圈,*.flv请求 200 但没有画面,或播放器报"源未找到"。 - 原因 :异步拉流 ------代理建好了,但底层 RTSP 源没连上。常见根因:
- FFmpeg 还没开始推流(cam1 尚不存在);
- MediaMTX 没启动 / 8554 未监听;
- RTSP 地址写错(本项目应为
rtsp://127.0.0.1:8554/cam1); - 源视频封装
-c copy不兼容 RTSP(见第四节)。
- 解决 :
- 确认模拟三件套启动顺序:mediamtx → ZLMediaKit → ffmpeg 推流;
- 看 ZLM 日志里是否有
Failed to connect rtsp之类; - 调
/index/api/getMediaList?secret=xxx看是否出现live/dev_1且readerCount>0; - 用
ffprobe -rtsp_transport tcp rtsp://127.0.0.1:8554/cam1验证源有h264轨。
2.5 前端播放报 CORS / Access-Control-Allow-Origin 错误
-
现象:浏览器控制台红色 CORS 报错,flv 请求被拦。
-
原因 :前端页面与 ZLMediaKit 不同源(域名/端口/协议不同),而 ZLM 未开启跨域。
-
解决 :在
config.ini打开跨域(http 与 api 两段都要):ini[http] allow_cross_domains=1 # 允许 HTTP-FLV 跨域 [api] allow_cross_domains=1 # 允许 API 跨域保存后重启 ZLM。本项目本地同源(都是 127.0.0.1)一般不触发,但部署到不同端口/域名时一定要开。
2.6 delStreamProxy 返回 code=-4(未找到)
- 现象 :关流接口报
-4 资源不存在。 - 原因 :
streamKey格式写错。正确格式为app/stream(如live/dev_1),不含.live后缀 ;且 ZLM 文档有时写key、本项目后端用streamKey,要统一。 - 解决 :
- 本项目后端封装:
streamKey = zlm.getApp() + "/" + streamId→live/dev_1; - 直接调 ZLM 也可写
key=__defaultVhost__/live/dev_1(带 vhost 前缀); - 关流前确认该流确实存在(没建过自然找不到,可忽略)。
- 本项目后端封装:
三、阶段三:FFmpeg / MediaMTX 报错(源侧)
这些虽不是 ZLM 直接报错,但会表现为 ZLM 拉不到源 → 2.4 黑屏,所以一并列出。
3.1 FFmpeg:Unknown output format 'rtsp' / Protocol not found
- 现象:ffmpeg 推流命令直接报错退出。
- 原因 :下载的 ffmpeg 构建不含 RTSP muxer(某些精简版)。
- 解决 :换 gyan.dev 或 BtbN 的
full_build完整构建,解压后ffmpeg -version正常、ffmpeg -formats | findstr rtsp能看到 rtsp。
3.2 FFmpeg:Connection refused / Could not find an AVPacket
- 现象:ffmpeg 连不上目标地址。
- 原因:MediaMTX 没启动、或 8554 没监听、或推流 URL 端口写错。
- 解决 :先启动
mediamtx.exe(RTSP server listening on :8554);netstat -ano | findstr :8554确认监听;核对RTSP_URL=rtsp://127.0.0.1:8554/cam1。
3.3 推流进程退出 / MediaMTX 里没有 cam1
- 现象 :ffmpeg 窗口闪退或停止,
ffprobe探测cam1失败。 - 原因 :
test.mp4路径不对 / 文件损坏;- 源编码 ffmpeg 无法解码;
- 漏了
-re(瞬间推完导致"假死")。
- 解决 :确认
TEST_VIDEO=D:\tools\test.mp4存在且可播;用ffplay test.mp4自测;保留-re -stream_loop -1。
3.4 -c copy 失败(封装不兼容 RTSP)
-
现象 :ffmpeg 报
Could not find tag ...或不兼容封装错误。 -
原因:源文件封装(如某些 MP4 的音频轨)不能直接用 RTSP 封装。
-
解决 :去掉
-c copy,改为转码:batffmpeg -re -stream_loop -1 -i test.mp4 -c:v libx264 -c:a aac -f rtsp rtsp://127.0.0.1:8554/cam1
3.5 画面不循环 / 播一会儿就停
- 现象:推流只播一遍就停。
- 原因 :漏了
-stream_loop -1(无限循环)。 - 解决 :确认命令含
-stream_loop -1。
四、阶段四:前端 flv.js 播放报错
4.1 黑屏一直转圈(请求 200 无画面)
- 现象 :F12 看
*.flv返回 200,但<video>黑屏。 - 原因 :见 2.4------ZLM 建流成功但 RTSP 源没连上(FFmpeg/MediaMTX 没就绪)。
- 解决 :回到第三节确认源;用
getMediaList看流是否真有数据。
4.2 flv.js 报错 Unsupported MediaDataSource / Not supported
- 现象:播放器直接报错,不发起请求。
- 原因 :传入的
url不是http(s)://...flv格式(如少了.flv后缀、或写成了 RTSP 地址)。 - 解决 :播放地址必须是
http://<play-host>:<http-port>/<app>/<stream>.flv,如http://127.0.0.1:8080/live/dev_1.flv。本项目buildFlvUrl已拼好,不要手改后缀。
4.3 混合内容被拦:blocked:mixed-content
- 现象:HTTPS 页面下 flv 请求被浏览器拦截(红字 mixed content)。
- 原因 :页面是
https,但 ZLM 播放地址是http,浏览器禁止混合内容。 - 解决 :
- 开发期:页面也用
http访问; - 生产:给 ZLM 配 SSL(
config.ini [http].sslport+ 证书),或前面挂 Nginx 反代 + HTTPS ,flv 走https。
- 开发期:页面也用
4.4 自动播放被浏览器拦截
- 现象:画面不自动起播,需手动点。
- 原因 :浏览器自动播放策略要求静音才能自动播。
- 解决 :
<video>加muted(本项目VideoPreview已加muted autoplay playsinline)。
4.5 播放卡顿 / 延迟 >3s
- 现象:画面能播但卡、延迟高。
- 原因 :
stashBuffer缓冲、源是主码流、UDP 拉流丢包。 - 解决 :前端关闭 flv.js 大缓冲;后端
rtp_type=0(TCP 拉流);源用子码流;仍不够再考虑升级 WebRTC。
五、阶段五:释放 / 关闭报错
5.1 关流无效果 / 流仍在
- 现象 :关闭弹窗后,
getMediaList里流还在。 - 原因 :
delStreamProxy的streamKey写错(见 2.6);- 依赖
streamNoneReaderDelayMS兜底时,要等 20s 才自动断(本项目配 20000ms)。
- 解决 :确认
streamKey=live/dev_1;或等待自动断流;或把streamNoneReaderDelayMS调小便于调试。
5.2 stop_sim.bat 关不干净
- 现象:脚本跑完仍有进程。
- 原因 :
taskkill按窗口标题匹配,窗口标题被改过就匹配不到。 - 解决 :任务管理器手动结束
mediamtx.exe/MediaServer.exe/ffmpeg.exe;或taskkill /f /im mediamtx.exe /im MediaServer.exe /im ffmpeg.exe。
六、快速定位决策树(拿到问题先问这 5 个)
播放黑屏/无画面?
├─ ZLM 进程在跑吗? netstat -ano | findstr :8080
│ └ 否 → 回"一、启动报错"修端口/配置
├─ getServerConfig 返回 JSON 吗? (带 secret)
│ └ 否/-3 → secret 不一致 (2.1/2.2)
├─ ffprobe rtsp://127.0.0.1:8554/cam1 有 h264 轨吗?
│ └ 否 → FFmpeg/MediaMTX 问题 (第三节)
├─ getMediaList 里有 live/dev_1 且 readerCount>0 吗?
│ └ 否 → 源未连上 (2.4),看 ZLM 日志
└─ 浏览器 F12 看 *.flv 请求状态?
├ 200 无画面 → 源问题(2.4/4.1)
├ CORS 报错 → 开 allow_cross_domains (2.5)
└ mixed-content → https/http 冲突 (4.3)
七、配置核对清单(每次模拟前过一遍)
-
config.ini [api].secret与application.yml zlm.secret完全一致(改后重启 ZLM) -
config.ini [http].port与application.yml zlm.http-port一致 (本地用 8080 避 IIS) -
config.ini [http] allow_cross_domains=1(跨域时必须) -
start_sim.bat里MEDIAMTX_EXE / ZLM_DIR / FFMPEG_EXE / TEST_VIDEO / RTSP_URL路径正确 - 启动顺序:mediamtx → 等 3s → ZLMediaKit → 等 3s → ffmpeg 推流
- 设备"视频地址"填
rtsp://127.0.0.1:8554/cam1(与 FFmpeg 推流 URL 一致) - 防火墙放行 8080(或 80)/ 554 / 1935
- 验证:
getServerConfig返回 JSON →ffprobe cam1有 h264 → 前端预览出循环画面