如何拉取公网RTSP/RTMP流在内网多客户端播放
摘要在监控、直播、物联网等场景中经常需要将公网摄像头或推流器的 RTSP/RTMP 流引入内网并分发给多个客户端同时播放。本文从协议分析、架构选型、流媒体服务器搭建、转码拉流、多协议分发、性能优化到排错指南提供了完整的 2 万字实战攻略覆盖 Nginx-RTMP、SRS、ZLMediaKit、FFmpeg、VLC、WebRTC、HLS 等主流技术栈帮助读者构建稳定、低延迟、高并发的内网流媒体播放体系。一、为什么需要公网拉流与内网多客户端播放在现代视频应用场景中摄像头或流媒体源通常位于公网或不同的网络区域而观看端往往集中在内网环境中。例如一家连锁超市需要将各个门店的公网监控画面统一汇总到总部的监控中心供多个保安在内部电脑上同时观看一个直播平台需要将主播的推流信号从公网收进来再通过内网转码、鉴权后分发给成千上万的观众。这些需求都涉及一个核心问题如何有效、稳定地将公网流 “拉” 到内网并让内网中多个客户端顺畅播放。如果让每个客户端直接去连接公网源会带来带宽浪费、公网 IP 暴露、并发能力不足、网络抖动不可控等问题。更好的做法是设立一个内网中转节点由它负责拉取公网流然后在内网进行分发。这样既节省了公网带宽又提高了内网播放的稳定性和可控性还能方便地接入转码、录制、鉴权等附加功能。本文将围绕 “如何拉取公网 RTSP/RTMP 流在内网多客户端播放” 这一主题从基础概念到最后落地给出超过 2 万字的深度讲解。内容覆盖了 RTSP 与 RTMP 协议的工作原理、常见的拉流转码工具、主流流媒体服务器的搭建与配置、多协议分发的实战方案、WebRTC 与 HTTP-FLV 技术的应用以及大量代码示例和排错经验。无论你是刚刚接触流媒体开发的新手还是正在优化现有架构的工程师都能从中找到可落地的方案。二、核心概念扫盲RTSP、RTMP 与内网分发的基石2.1 RTSP 协议详解RTSPReal Time Streaming Protocol是一种应用层协议主要用于控制实时媒体流的传输。它并不直接承载音视频数据而是充当 “遥控器” 的角色通过 DESCRIBE、SETUP、PLAY、PAUSE、TEARDOWN 等指令来管理流会话。真正的音视频数据通常由 RTPReal-time Transport Protocol协议承载RTCP 则负责质量控制。RTSP 默认端口为 554常见于监控摄像头、视频服务器等场景。RTSP 的交互过程大致如下客户端先发送 OPTIONS 探测服务器能力然后 DESCRIBE 请求获取媒体描述SDP 信息接着 SETUP 建立 RTP 传输通道再 PLAY 开始播放最后 TEARDOWN 结束会话。由于 RTSP 支持 TCP 和 UDP 两种传输模式而且在网络环境复杂的情况下使用 TCP 传输往往能获得更好的穿透能力但也会增加一些延迟。在拉取公网 RTSP 流时我们经常会遇到 NAT 穿透问题。如果摄像头在防火墙后面需要做端口映射或者使用 VPN 等方案才能让内网服务器直接访问。幸运的是本文介绍的方案中拉流服务器往往部署在内网与公网的交界处如 DMZ 区可以通过配置防火墙规则来获取公网 RTSP 流。2.2 RTMP 协议详解RTMPReal-Time Messaging Protocol是 Adobe 公司开发的私有协议最初用于 Flash 播放器与服务器之间的音视频和数据传输。虽然 Flash 已经逐渐退出历史舞台但 RTMP 凭借其低延迟、稳定可靠的特点在直播推流、拉流等场景中依然占据着重要地位。RTMP 默认端口为 1935它基于 TCP 传输以消息块的形式传输数据支持多路复用和分块传输能够在一条 TCP 连接上同时传输视频、音频和控制消息。一个典型的 RTMP 握手过程包含三个阶段简单握手、复杂握手可选和连接建立。握手之后客户端会发送 connect 命令服务器响应后客户端再发送 createStream 并 publish 或 play从而开始推流或拉流。RTMP 的变体还包括 RTMPS通过 SSL/TLS 加密、RTMPE加密版、RTMPTHTTP 隧道等以适应不同的网络环境。在公网拉流场景中RTMP 经常被用作推流协议主播通过 OBS 等工具将流推送到公网直播服务器然后内网服务器再从这个公网服务器拉流。由于 RTMP 走 TCP在公网传输时相对稳定但高延迟网络下缓冲和重传机制可能会导致播放卡顿因此需要结合 CDN 和边缘节点来优化。2.3 内网多客户端播放的挑战当流被拉入内网后接下来的挑战是如何高效地分发给多个客户端。如果直接让每个客户端都去拉流服务器建立一个连接服务器很快就会遇到带宽和 CPU 瓶颈。例如一个 4Mbps 的流100 个客户端同时播放就需要 400Mbps 的出口带宽这对于单台服务器来说压力巨大。而且每个客户端都独立拉流还会导致源站压力倍增甚至可能因为过多的 RTSP 连接导致摄像头崩溃。为了解决这个问题我们需要引入流媒体分发服务器它一次拉取源流然后在内网中通过多播、多路分发或者转码后输出多种协议流供客户端选择。常见的实现方式有Nginx-RTMP 模块、SRSSimple Realtime Server、ZLMediaKit 等。这些服务器能够将 RTMP 或 RTSP 流转换为 HLS、HTTP-FLV、WebRTC 等协议而这些协议天生支持多客户端且能利用 CDN 或边缘缓存大幅降低源站压力。另外内网环境通常带宽充足但网络拓扑复杂可能存在 VLAN 隔离、防火墙规则等限制。因此在选择分发协议时还需要考虑内网穿透能力、对浏览器原生播放的支持程度以及延迟要求。例如HTTP-FLV 延迟较低但不支持浏览器原生播放需要借助 flv.js 等 JS 库HLS 兼容性极好但延迟通常在 10 秒以上WebRTC 延迟最低但部署复杂度较高。我们将在后续章节中详细介绍这些方案。三、方案架构总览从公网到内网的全链路设计3.1 典型架构图文字描述一个典型的公网拉流并在内网多客户端播放的架构分为三层公网源层、内网中转层、客户端播放层。公网源可以是 RTSP 摄像头、RTMP 推流器或者其他流媒体服务器输出的流。内网中转层部署一台或多台流媒体服务器负责拉取公网流并进行转码、协议转换、缓存等操作。客户端播放层则通过内网网络访问流媒体服务器使用 HTTP-FLV、HLS、WebRTC、RTSP 等协议进行播放。具体的流程如下公网源推流/提供流摄像头通过 RTSP 提供实时画面或者主播通过 OBS 推流到公网 RTMP 服务器。内网服务器拉流内网流媒体服务器使用 FFmpeg 或者自带的拉流模块从公网源拉取 RTSP 或 RTMP 流。内网流媒体服务器处理服务器将拉到的流进行转码如 H.264 转 H.265、降低分辨率、调整码率并封装成多种协议供内网客户端访问。内网客户端播放通过 VLC 播放器、浏览器、移动 App 等连接内网服务器根据对延迟、兼容性的要求选择合适的协议播放。这种架构的优点在于公网出口带宽仅需一份内网客户端共享服务器转发的流服务器可以做缓存和预处理提高整体播放体验。同时该架构也便于后续扩展比如加入录制、截图、AI 分析等功能。3.2 主要技术选型对比在内网中转层目前主流的流媒体服务器有 Nginx-RTMP、SRS 和 ZLMediaKit。它们各有优缺点适合不同的场景。Nginx-RTMP基于 Nginx 的 RTMP 模块轻量、稳定适合简单的 RTMP 直播和点播。默认支持 RTMP 推拉流以及将 RTMP 转换为 HLS 输出。但功能相对单一并发能力和扩展性一般不支持 WebRTC需要额外插件才能实现 HTTP-FLV。SRS (Simple Realtime Server)国产开源流媒体服务器功能强大支持 RTMP、HLS、HTTP-FLV、WebRTC 等多种协议内置转码、录制、DVR 等功能并发性能优异社区活跃。非常适合需要多协议分发和高并发的场景。ZLMediaKit另一款优秀的国产流媒体服务器基于 C 开发性能极高支持 RTSP、RTMP、HLS、HTTP-FLV、WebSocket-FLV、RTC 等多种协议还支持 GB28181 国标非常适合监控领域的拉流和分发。其 API 丰富易于集成到自己的业务系统中。在拉流客户端方面FFmpeg 是最通用的选择它支持几乎所有格式的拉流、转码和推流可以灵活地作为命令行工具或被集成到服务器代码中。此外SRS 和 ZLMediaKit 自身也具备拉流功能可以配置为从指定的 RTSP/RTMP 地址拉流从而简化架构。在实际项目中建议根据自身需求选择如果只是简单的 RTMP 拉流和 HLS 分发Nginx-RTMP 足够了如果需要支持 HTTP-FLV 和 WebRTC且对性能要求高SRS 或 ZLMediaKit 是更好的选择如果已有一套监控系统需要对接 GB28181ZLMediaKit 会更合适。四、环境准备搭建拉流与分发的基础设施4.1 操作系统与网络要求本教程假设使用 Ubuntu 20.04/22.04 或 CentOS 7/8 作为服务器操作系统。推荐使用一台具备公网访问能力或至少能访问公网源且内网可达的云主机或物理机。网络配置上需要确保服务器能够通过公网 IP 或域名访问到 RTSP/RTMP 源同时内网客户端能够访问服务器的内网 IP。如果公网源位于防火墙后方请提前做好端口映射如 TCP 554 用于 RTSPTCP 1935 用于 RTMP。硬件要求取决于流的数量和转码强度。如果只是拉取 1-2 路 1080p 的流并做简单分发2 核 4G 的服务器即可如果需要进行多路转码或高并发分发建议使用 4 核 8G 以上的配置。对于 GPU 转码需要安装 NVIDIA 驱动和 CUDA 环境。4.2 安装基础工具FFmpeg 与 VLCFFmpeg 是流媒体处理的核心工具几乎所有拉流、转码、推流操作都离不开它。在 Ubuntu 上安装 FFmpeg 可以使用以下命令注意系统自带的版本可能较老推荐从官方源编译安装或使用静态构建版本sudo apt update sudo apt install ffmpeg -y如果希望使用最新版本可以从 FFmpeg 官网下载静态编译版本解压后将其路径加入 PATH 环境变量。验证安装是否成功ffmpeg -versionVLC 播放器除了作为客户端播放工具外还可以在命令行中用于拉流和转流测试。在 Ubuntu 上安装 VLCsudo apt install vlc -y安装完成后可以使用cvlc命令行工具进行拉流转推等操作这在调试时非常方便。4.3 安装 Nginx-RTMP 模块Nginx 本身并不支持 RTMP需要编译添加 nginx-rtmp-module。最简单的方式是使用已经集成该模块的发行版或者通过包管理器安装。Ubuntu 下可以使用如下命令安装 Nginx 并编译 nginx-rtmp-modulesudo apt install build-essential libpcre3 libpcre3-dev libssl-dev zlib1g-dev -y wget http://nginx.org/download/nginx-1.24.0.tar.gz tar -zxvf nginx-1.24.0.tar.gz git clone https://github.com/arut/nginx-rtmp-module.git cd nginx-1.24.0 ./configure --add-module../nginx-rtmp-module make sudo make install编译完成后配置文件通常位于/usr/local/nginx/conf/nginx.conf。我们将在后续章节中详细配置 RTMP 拉流与 HLS 输出。4.4 安装 SRS 流媒体服务器SRS 的安装非常简单官方提供了 Docker 镜像和源码包。推荐使用 Docker 快速部署docker run -d --name srs -p 1935:1935 -p 1985:1985 -p 8080:8080 \ -v /path/to/srs.conf:/usr/local/srs/conf/srs.conf \ ossrs/srs:5如果没有 Docker 环境也可以直接下载二进制文件或源码编译。SRS 的配置文件十分丰富支持拉流、转码、录制、HTTP 回调等。一个最简配置即可实现从公网拉 RTMP 流并转换为 HTTP-FLV 和 HLS 分发。4.5 安装 ZLMediaKitZLMediaKit 的部署同样简单推荐使用 Dockerdocker run -d --name zlmediakit \ -p 1935:1935 -p 554:554 -p 80:80 -p 443:443 -p 10000:10000/udp \ -v /path/to/config.ini:/opt/media/conf/config.ini \ zlmediakit/zlmediakit:master或者从源码编译安装官方提供了详细的编译脚本。ZLMediaKit 的配置文件为config.ini其中可以配置拉流代理、转协议开关等。它天然支持 RTSP、RTMP 拉流并可以输出 HTTP-FLV、WebSocket-FLV、HLS、WebRTC 等多种协议非常适合监控流的汇聚和分发。五、实战一使用 FFmpeg 拉流并转推内网服务器5.1 FFmpeg 拉取公网 RTSP 流FFmpeg 拉取 RTSP 流非常简单例如从公网摄像头拉取高清流ffmpeg -rtsp_transport tcp -i rtsp://admin:password公网IP:554/stream1 -c copy -f rtsp rtsp://内网服务器IP:8554/mystream参数说明-rtsp_transport tcp强制使用 TCP 传输避免 UDP 丢包-i指定输入源-c copy表示不转码直接复制音视频流可以降低 CPU 占用-f rtsp指定输出格式为 RTSP并推送到内网 RTSP 服务器如 ZLMediaKit 或 Mediamtx。如果内网没有 RTSP 服务器也可以直接推送到 Nginx-RTMP 或 SRS 的 RTMP 端口命令如下ffmpeg -rtsp_transport tcp -i rtsp://公网IP:554/stream1 -c copy -f flv rtmp://内网服务器IP:1935/live/stream1这种方式会将 RTSP 流直接封装为 RTMP 推送到内网服务器然后内网服务器再将其转换为其他协议分发给客户端。5.2 FFmpeg 拉取公网 RTMP 流拉取公网 RTMP 流同样简单ffmpeg -i rtmp://公网直播服务器IP:1935/live/streamkey -c copy -f flv rtmp://内网服务器IP:1935/live/streamkey这种方式相当于将公网流作为一个中继原样转发到内网服务器。如果需要转码比如降低分辨率或码率以适应内网带宽可以去掉-c copy并添加编码参数ffmpeg -i rtmp://公网IP:1935/live/hd -c:v libx264 -b:v 1000k -s 1280x720 -c:a aac -b:a 128k -f flv rtmp://内网IP:1935/live/sd上述命令将输入的高清流转码为 720p、1Mbps 的标清流再推送到内网 RTMP 服务器。转码非常消耗 CPU 资源如果有多路流需要处理建议使用 GPU 加速如 NVENC。5.3 使用 Systemd 或 Supervisor 守护 FFmpeg 进程在生产环境中FFmpeg 进程不能通过手动启动需要确保它能够开机自启并且在异常退出后自动重启。可以使用 systemd 服务来实现。创建一个服务文件/etc/systemd/system/live-pull.service[Unit] DescriptionFFmpeg Pull Stream Service Afternetwork.target [Service] Typesimple ExecStart/usr/bin/ffmpeg -rtsp_transport tcp -i rtsp://公网IP:554/stream1 -c copy -f flv rtmp://127.0.0.1:1935/live/stream1 Restartalways RestartSec10 Userroot [Install] WantedBymulti-user.target然后启用服务sudo systemctl enable live-pull.service sudo systemctl start live-pull.service这样FFmpeg 拉流进程就会在后台稳定运行。类似的也可以使用 Supervisor 来管理通过配置文件定义命令和重启策略。六、实战二Nginx-RTMP 配置详解实现 RTMP 拉流与 HLS 分发6.1 Nginx-RTMP 基本配置Nginx-RTMP 的配置文件通常位于/usr/local/nginx/conf/nginx.conf。我们需要在配置文件中添加 RTMP 相关的配置块。下面是一个典型的配置实现从公网拉流并输出 HLSrtmp { server { listen 1935; # RTMP 监听端口 chunk_size 4096; application live { live on; record off; # 拉流配置从公网 RTMP 地址拉流本地应用名为 live pull rtmp://公网直播服务器IP:1935/live/streamkey live1; } 将上面 live 应用中的流转换为 HLS application hls { live on; hls on; hls_path /tmp/hls; hls_fragment 3s; hls_playlist_length 60s; # 这里的 hls 流来自 live 应用通过拉流或推流产生 # 也可以通过 pull 指令从其他源拉取 } } } http { server { listen 8080; location /hls { 开启 HLS 访问 types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } alias /tmp/hls; add_header Cache-Control no-cache; } } }在上述配置中application live是一个直播应用它通过pull指令从公网 RTMP 服务器拉取流这样本地就产生了一个live流。然后application hls将live流转换为 HLS 切片并存储在/tmp/hls目录下。最后HTTP 服务器通过location /hls将 HLS 文件暴露给客户端。客户端可以通过 VLC 或浏览器使用 video.js 或 hls.js访问http://内网服务器IP:8080/hls/streamkey.m3u8来播放。注意HLS 延迟通常较高10-30 秒如果对延迟敏感可以调整hls_fragment和hls_playlist_length参数但最小延迟也只能到 5-6 秒左右。6.2 配置 RTSP 拉流转 RTMP 再 HLS 分发Nginx-RTMP 本身不支持直接拉取 RTSP 流但我们可以结合 FFmpeg 来拉取 RTSP 并推送到 Nginx-RTMP 的live应用然后由 Nginx 生成 HLS。例如先用 FFmpeg 拉 RTSP 推 RTMPffmpeg -rtsp_transport tcp -i rtsp://摄像头IP:554/stream -c copy -f flv rtmp://127.0.0.1:1935/live/cam1然后 Nginx 配置中application live不需要pull指令因为流是通过推流进来的。接着可以使用exec_publish等方式自动触发 HLS 生成或者另外配置一个application hls并拉取 live 流或者使用 on_publish 回调。更简单的做法是在 SRS 或 ZLMediaKit 中它们可以直接配置拉取 RTSP 流无需借助 FFmpeg。6.3 多客户端播放与并发优化HLS 是基于 HTTP 的所以天然支持多客户端并发Nginx 作为 HTTP 服务器可以轻松处理数百个并发连接。但需要注意HLS 切片文件会不断生成和清理磁盘 I/O 可能成为瓶颈。建议将hls_path放在内存文件系统如 tmpfs上或者使用 SSD 存储。同时可以配置 Nginx 的缓存和限速防止单个客户端占用过多带宽。对于 RTMP 直播Nginx-RTMP 可以配置多个 worker 进程并启用max_connections来限制连接数。但总体来说Nginx-RTMP 在处理高并发 RTMP 播放时性能不如 SRS 或 ZLMediaKit如果并发量较大建议采用后两者。七、实战三SRS 流媒体服务器从拉流到多协议分发7.1 SRS 配置文件详解SRS 的配置文件通常为srs.conf。下面是一个典型的配置实现从公网拉取 RTMP 流并输出 RTMP、HTTP-FLV、HLS 三种协议listen 1935; max_connections 1000; daemon off; srs_log_tank console; http_api { enabled on; listen 1985; } http_server { enabled on; listen 8080; dir ./objs/nginx/html; } vhost defaultVhost { # 拉流配置从公网 RTMP 地址拉取流本地产生流名称为 live/livestream ingest livestream { enabled on; input { type file; url rtmp://公网RTMP服务器IP:1935/live/streamkey; } ffmpeg ./objs/ffmpeg/bin/ffmpeg; engine { enabled on; output rtmp://127.0.0.1:[port]/live/livestream; } } # HTTP-FLV 分发 http_remux { enabled on; mount [vhost]/[app]/[stream].flv; } HLS 分发 hls { enabled on; hls_path ./objs/nginx/html; hls_fragment 10; hls_window 60; } }在这个配置中我们使用ingest模块来拉取公网流SRS 会调用 FFmpeg 从指定 URL 拉流然后推送到自身的 RTMP 端口从而产生一个本地流。这样SRS 内部就拥有了该流后续可以基于它进行各种协议分发。配置中的http_remux开启了 HTTP-FLV 功能客户端可以通过http://服务器IP:8080/live/livestream.flv播放。HTTP-FLV 延迟较低1-3 秒但需要借助 flv.js 才能在浏览器中播放。HLS 的访问地址则是http://服务器IP:8080/live/livestream.m3u8。7.2 拉取 RTSP 流并转换为 HTTP-FLVSRS 同样支持拉取 RTSP 流但需要借助 FFmpeg 或使用第三方插件。一种简单的做法是使用 SRS 的stream_caster模块将 RTSP 协议转换为 RTMP。例如在配置文件中添加stream_caster { enabled on; caster rtsp; output rtmp://127.0.0.1/live/[stream]; listen 554; rtp_port_min 57200; rtp_port_max 57300; }这样SRS 就会监听 554 端口当有 RTSP 客户端连接时自动将 RTSP 流转换为 RTMP 并推送到live应用。然后我们可以通过配置ingest或直接使用 FFmpeg 将公网 RTSP 流推送到这个端口最终实现 RTSP 到 HTTP-FLV 的转换。更常见的做法是直接用 FFmpeg 拉取公网 RTSP 流推送到 SRS 的 RTMP 端口然后 SRS 负责 HTTP-FLV 和 HLS 分发。这种方式简单稳定可控性强。7.3 多客户端播放与性能测试SRS 在性能方面表现出色单机可支持数千路并发播放。我们可以使用srs-bench等工具进行压力测试。例如模拟 500 个客户端同时播放 HTTP-FLV./srs_bench -c 500 -s http://服务器IP:8080/live/livestream.flv在测试过程中可以通过 SRS 的 HTTP API 查看统计信息包括连接数、带宽、丢包等地址为http://服务器IP:1985/api/v1/summary。根据测试结果可以调整max_connections、系统内核参数如 somaxconn、tcp_tw_reuse来优化并发能力。对于内网多客户端场景HTTP-FLV 是性价比最高的选择延迟低且服务器压力小。如果客户端包含移动端 App可以使用 WebRTC 或 HLS 作为补充因为 HTTP-FLV 在移动端浏览器支持有限但可以通过 Native SDK 播放。八、实战四ZLMediaKit 多功能流媒体服务器玩转 RTSP/RTMP/HTTP-FLV/WebRTC8.1 ZLMediaKit 配置文件详解ZLMediaKit 的默认配置文件为config.ini包含了丰富的配置项。下面我们配置一个同时支持 RTSP 拉流、RTMP 拉流并输出 HTTP-FLV、WebSocket-FLV、HLS、WebRTC 的服务器[general] mediaServerIdyour_server_id [api] apiDebug1 defaultSnap./www/logo.png secret035c73f7-bb6b-4889-a715-d9eb2d1925cc [rtmp] port1935 enableVhost1 [rtsp] port554 timeoutSec15 [http] port80 charSetutf-8 rootPath./www sslport443 [multicast] addrMax239.255.255.255 addrMin239.0.0.0 udpTTL64 [hls] broadcastRecordTs1 deleteDelaySec10 fastRegister1 fileBufSize65536 segDelay3 segDuration5 segKeep0 segNum3 segRetain5 [hook] enable1 on_flow_reporthttps://your_api_server/on_flow_report on_playhttps://your_api_server/on_play on_publishhttps://your_api_server/on_publish on_record_mp4https://your_api_server/on_record_mp4 on_rtsp_authhttps://your_api_server/on_rtsp_auth on_rtsp_realmhttps://your_api_server/on_rtsp_realm on_server_startedhttps://your_api_server/on_server_started on_shell_loginhttps://your_api_server/on_shell_login on_stream_changedhttps://your_api_server/on_stream_changed on_stream_none_readerhttps://your_api_server/on_stream_none_reader on_stream_not_foundhttps://your_api_server/on_stream_not_found [rtc] preferredCodecAPCMU preferredCodecVH264 timeoutSec15 externIP内网服务器公网IP如果有 port10000 rembBitRate1000000 [rtp_proxy] checkSource0 dumpDir port10000 port_range30000-30500 timeoutSec15 [ffmpeg] bin/usr/bin/ffmpeg cmd%s -re -i %s -c:a aac -strict -2 -ar 44100 -ab 48k -c:v libx264 -f flv %s log/dev/null restart_sec0 snap%s -i %s -y -f mjpeg -frames:v 1 %sZLMediaKit 的一大特色是支持 “拉流代理”即可以配置从远程 RTSP/RTMP 地址拉流并作为本地流进行分发。拉流代理的配置可以在config.ini中通过[rtp_proxy]部分实现但更常用的是通过 HTTP API 动态添加拉流任务。8.2 动态添加拉流代理ZLMediaKit 提供了丰富的 HTTP API我们可以通过 API 接口动态地添加或删除拉流代理。例如要拉取公网的一个 RTSP 流并让其以live/test的流 ID 在本地分发可以发送如下请求curl -X POST http://内网服务器IP/api/addStreamProxy \ -H secret:035c73f7-bb6b-4889-a715-d9eb2d1925cc \ -d vhost__defaultVhost__applivestreamtesturlrtsp://admin:password公网IP:554/stream1添加成功后流就会在本地生成并可以通过以下多种协议访问RTSPrtsp://内网服务器IP:554/live/testRTMPrtmp://内网服务器IP:1935/live/testHTTP-FLVhttp://内网服务器IP:80/live/test.flvWebSocket-FLVws://内网服务器IP:80/live/test.flvHLShttp://内网服务器IP:80/live/test/hls.m3u8WebRTC通过 WHIP 或 WHEP 协议推拉流延迟极低。这种动态拉流的方式非常适合在业务系统中集成比如用户在前端添加一个摄像头后端调用 ZLMediaKit 的 API 开始拉流然后返回播放地址。类似地也可以使用delStreamProxy接口来停止拉流。8.3 实现 WebRTC 低延迟播放WebRTC 是目前延迟最低的浏览器端播放方案通常可以达到 1 秒以内。ZLMediaKit 支持 WebRTC 播放可以通过以下步骤实现确保服务器配置了[rtc]部分并正确设置了externIP如果服务器在内网则设为内网 IP因为客户端在同一个内网。通过 API 或者使用默认流客户端使用 SDP 交换来建立连接。在前端使用浏览器原生 WebRTC API 或者第三方库如 webrtc-streamer来播放。例如使用 webrtc-streamer 的简单前端代码html head script srcwebrtcstreamer.js/script /head body video idvideo controls/video script var webRtcServer new WebRtcStreamer(video, http://内网服务器IP:8000); webRtcServer.connect(rtsp://内网服务器IP:554/live/test); /script /body /html注意ZLMediaKit 默认的 WebRTC 信令端口是 8000但可以通过配置修改。如果客户端和服务器在同一个内网无需 STUN/TURN 服务器但跨网段或复杂网络环境可能需要配置。8.4 多客户端播放与并发测试ZLMediaKit 的性能非常强悍单机可承载数万并发播放。同样可以使用压测工具进行验证。例如使用flv.js播放 HTTP-FLV 或使用ffplay播放 RTMP 流。由于 ZLMediaKit 内部使用了高效的 IO 多路复用和内存管理即使在大量并发下CPU 和内存占用也相对较低。在实际项目中如果播放客户端数量巨大还可以通过部署多个 ZLMediaKit 节点并利用其自带的 “回源” 或 “级联” 功能实现分布式架构。比如一个主节点拉取公网流多个从节点从主节点拉流然后分发给各自区域的客户端这样可以无限扩展并发能力。九、多协议分发策略与客户端播放实战9.1 HTTP-FLV低延迟的直播分发HTTP-FLV 是目前直播领域最流行的分发协议之一它基于 HTTP 长连接传输 FLV 格式的音视频数据延迟可以控制在 1-3 秒非常适合对延迟有要求的场景。服务器端SRS 和 ZLMediaKit 都原生支持 HTTP-FLV 输出。客户端方面PC 浏览器可以借助 flv.js 库来播放移动端则需要使用原生播放器或者 IJKPlayer 等支持 FLV 的播放器。一个简单的 flv.js 播放示例video idvideoElement controls/video script srcflv.min.js/script script if (flvjs.isSupported()) { var videoElement document.getElementById(videoElement); var flvPlayer flvjs.createPlayer({ type: flv, url: http://内网服务器IP:80/live/test.flv }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); flvPlayer.play(); } /script需要注意的是flv.js 在播放时可能会因为服务器端没有发送 metadata 而卡住这时需要确保服务器配置了http_remux或类似功能并在流开始时发送正确的 FLV header。9.2 HLS全平台兼容的分发方案HLSHTTP Live Streaming是苹果公司提出的协议几乎所有现代浏览器和移动设备都原生支持兼容性极好。它的工作原理是将视频流切片成一个个小的 TS 文件并通过 m3u8 索引文件组织起来。延迟较高通常 10 秒以上但可以通过减少切片时长和数量来优化受限于协议本身最低也只能到 5 秒左右。在服务器端SRS 和 ZLMediaKit 都可以自动生成 HLS 切片。客户端播放非常简单只需在 HTML 中使用 video 标签即可video controls width800 source srchttp://内网服务器IP:80/live/test/hls.m3u8 typeapplication/x-mpegURL /videoHLS 的另一个优势是可以利用 CDN 进行大规模分发但如果在内网中就不需要 CDN 了。不过HLS 的延迟对于实时监控等场景可能无法接受这时候可以考虑 WebRTC 或 HTTP-FLV。9.3 WebRTC超低延迟的终极方案WebRTC 延迟极低通常在 200-500 毫秒非常适合视频会议、远程操控等场景。但是WebRTC 的部署和开发复杂度较高需要处理信令服务器、STUN/TURN 服务器、NAT 穿透等问题。好在 ZLMediaKit 和 SRS 都已经集成了 WebRTC 功能大大降低了使用门槛。在 ZLMediaKit 中WebRTC 播放可以直接通过 WHIP/WHEP 协议实现或者通过 webrtc-streamer 封装。SRS 也提供了 WebRTC 播放功能支持 HTTP API 和 WebSocket 信令。客户端代码可以使用浏览器原生 RTCPeerConnection API或者使用现成的 JS 库如 SRS 提供的 srs.sdk.js。一个基于 SRS 的 WebRTC 播放器示例video idvideo autoplay controls/video script srchttps://ossrs.net/srs.sdk.js/script script var srs new SrsRtcWhipWhepAsync(); srs.play(new URL(http://内网服务器IP:1985/rtc/v1/whip-play/?applivestreamtest)).then(function(session) { document.getElementById(video).srcObject session.stream; }); /script注意WebRTC 播放需要浏览器支持 HTTPS 或者 localhost否则无法获取摄像头和麦克风权限。但在内网中通常可以使用 HTTP 或 IP 地址但浏览器可能会限制需要配置自签名证书或使用 HTTP 的 IP 地址。9.4 RTSP 与 RTMP 客户端播放虽然我们的目标是多客户端播放但有些客户端如 VLC、ffplay可以直接播放 RTSP 或 RTMP 流。特别是在内网环境中RTSP 和 RTMP 的延迟也很低且无需转码直接播放可以减少服务器压力。但 RTSP 和 RTMP 不支持浏览器原生播放需要安装插件或使用 Native 应用。使用 VLC 播放 RTSP 流vlc rtsp://内网服务器IP:554/live/test使用 ffplay 播放 RTMP 流ffplay rtmp://内网服务器IP:1935/live/test对于开发人员这些工具在调试时非常有用。但在生产环境中我们更倾向于使用 HTTP-FLV 或 WebRTC因为可以在网页中集成无需安装额外软件。十、高级主题转码、录制、截图与 AI 分析10.1 实时转码与码率自适应在拉取公网流后有时内网客户端的网络环境或播放设备能力不一致需要进行实时转码输出多个不同分辨率和码率的流。例如一路高清流 1080p 4Mbps转出 720p 2Mbps、480p 1Mbps 等供不同客户端选择。这可以在流媒体服务器中通过 FFmpeg 转码实现。SRS 支持通过 FFmpeg 转码配置如下transcode { enabled on; ffmpeg ./objs/ffmpeg/bin/ffmpeg; engine sd { enabled on; vfilter { vcodec libx264; vbitrate 800; vfps 25; vwidth 720; vheight 480; } acodec aac; abitrate 64; output rtmp://127.0.0.1:[port]/live/livestream_sd; } }这样观众就可以根据网络情况选择播放livestream或livestream_sd。在客户端可以结合自适应码率ABR技术动态切换不同码率的流保证流畅度。10.2 录制与回放很多场景下我们需要将直播流录制下来用于事后回放或证据留存。流媒体服务器通常都支持录制功能。SRS 可以配置 DVR将流录制为 FLV 或 MP4 文件dvr { enabled on; dvr_path ./objs/nginx/html/[app]/[stream]/[timestamp].mp4; dvr_plan session; dvr_duration 30; dvr_wait_keyframe on; }ZLMediaKit 也支持录制可以通过 HTTP API 动态开启录制并支持 MP4、HLS 等格式。录制后可以将文件存储在 NAS 或对象存储中并提供点播服务。10.3 截图与 AI 智能分析对于监控流经常需要定时截图并利用 AI 算法进行人脸识别、车牌识别、运动检测等。可以在流媒体服务器上通过 FFmpeg 的select滤镜或者-vf fps1参数实现定时截图并将图片发送到 AI 分析服务。例如每秒截一帧ffmpeg -rtsp_transport tcp -i rtsp://摄像头IP:554/stream -vf fps1 -f image2 snapshot-%04d.jpg或者使用 ZLMediaKit 的 API 获取实时截图然后通过 HTTP 回调将图片 URL 发送给 AI 分析模块。这样就能在拉流分发的同一套架构上无缝集成智能分析功能。十一、高可用与性能优化11.1 主备拉流与故障转移公网流可能因为网络波动或源站故障而中断为了保证内网播放的连续性需要设计主备拉流方案。例如部署两台拉流服务器一台作为主一台作为备。当主服务器拉流失败时自动切换到备服务器。这可以通过 Keepalived 实现虚拟 IP 漂移或者使用负载均衡器如 Nginx进行健康检查和切换。在 SRS 中可以配置多个ingest源并设置优先级或回源策略。ZLMediaKit 则可以通过 API 动态添加拉流代理并在业务层实现故障转移逻辑。例如当检测到主拉流异常时调用 API 添加备用的拉流代理同时通知客户端切换到新的流地址。11.2 负载均衡与集群化当内网客户端数量非常大时单台流媒体服务器可能无法承载需要搭建集群。一种常见的架构是使用 LVS 或 Nginx 做四层或七层负载均衡将客户端的播放请求分发到后端的多个流媒体服务器节点。每个节点都从同一个源流拉取或通过级联方式从主节点获取流。SRS 支持 Edge 模式可以将一台 SRS 作为 Origin其他作为 EdgeEdge 从 Origin 拉流然后分发给客户端。ZLMediaKit 也支持类似的级联和回源功能。这样整个系统可以水平扩展满足数十万并发的播放需求。11.3 操作系统与网络优化为了提升流媒体服务器的性能需要对操作系统内核参数进行优化。例如调整 TCP 缓冲区大小、最大文件描述符数、TIME_WAIT 快速回收等# 修改 /etc/sysctl.conf net.core.rmem_max 16777216 net.core.wmem_max 16777216 net.ipv4.tcp_rmem 4096 87380 16777216 net.ipv4.tcp_wmem 4096 65536 16777216 net.ipv4.tcp_tw_reuse 1 net.ipv4.tcp_tw_recycle 1 net.core.somaxconn 65535 fs.file-max 1000000修改后执行sysctl -p使其生效。同时还需要修改/etc/security/limits.conf增加打开文件数的限制* soft nofile 1000000 * hard nofile 1000000另外如果使用 UDP 传输如 WebRTC还需要调整 UDP 缓冲区大小。这些优化可以显著提高服务器在高并发下的稳定性。十二、常见问题与排错指南12.1 拉流失败或频繁断开拉流失败通常有以下几个原因网络不通检查防火墙规则确保目标端口可达。使用telnet 公网IP 554或nc -vz 公网IP 1935测试连通性。认证失败RTSP 或 RTMP 地址中携带的用户名密码是否正确有时候摄像头会限制同时连接数超过会导致拒绝。协议选择错误RTSP 可以尝试 TCP 或 UDP 传输有些摄像头仅支持 TCP。在 FFmpeg 中使用-rtsp_transport tcp强制 TCP。源流不稳定公网源本身存在丢包或断流可以尝试增加重连机制在 FFmpeg 命令中添加-reconnect 1 -reconnect_at_eof 1 -reconnect_streamed 1 -reconnect_delay_max 2。12.2 播放卡顿、延迟高播放卡顿可能由以下原因导致服务器性能不足CPU 占用过高导致转码或分发不及时。检查服务器资源使用情况考虑升级硬件或减少转码路数。网络带宽不足内网客户端数量过多导致出口带宽打满。可以使用流量监控工具查看必要时启用组播或升级网络设备。播放器缓冲策略HLS 的延迟可以通过减少切片时长和数量来降低但会导致更频繁的请求。HTTP-FLV 延迟较低如果仍然卡顿检查服务器端是否开启了gop_cache确保关键帧间隔合理。客户端解码能力如果客户端设备性能较差解码高码率视频会卡顿可以尝试降低推流码率或使用硬件解码。12.3 浏览器无法播放的问题浏览器播放 HTTP-FLV 需要 flv.js且需要服务器支持。如果 flv.js 报错可能是跨域问题需要在服务器端设置 CORS 头。例如在 Nginx 中配置add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET, POST, OPTIONS;对于 WebRTC浏览器需要 HTTPS 或 localhost 才能正常运行内网可以使用自签名证书或者通过 HTTP 访问时使用 IP 地址Chrome 对 HTTP 的 IP 地址允许 WebRTC。此外STUN/TURN 服务器配置不正确也会导致连接失败需要确保 ICE 候选能够成功交换。12.4 内存泄漏与资源占用过高流媒体服务器长时间运行可能出现内存泄漏导致进程崩溃。定期监控服务器资源使用top、htop、valgrind等工具检查。如果是使用 FFmpeg 拉流注意 FFmpeg 的-re参数避免拉流速度过快导致瞬间内存暴涨。对于 SRS 和 ZLMediaKit通常比较稳定但也要注意配置文件中的路径和日志大小避免磁盘写满。十三、总结与展望本文从基础协议出发详细讲解了如何将公网的 RTSP/RTMP 流拉取到内网并通过 Nginx-RTMP、SRS、ZLMediaKit 等流媒体服务器进行多协议分发最终实现内网多客户端的同时播放。我们覆盖了 FFmpeg 拉流、系统守护进程配置、各服务器配置详解、HTTP-FLV、HLS、WebRTC 等分发方案以及转码、录制、高可用等进阶话题。在实际项目中选择哪种方案取决于具体的业务需求如果仅需简单的 RTMP 拉流和 HLS 分发Nginx-RTMP 轻量且够用如果需要高性能、多协议支持SRS 和 ZLMediaKit 是更优选择如果对延迟要求极高WebRTC 是终极方案。同时不要忘记对系统进行性能优化并设计好高可用架构以应对生产环境的各种挑战。随着流媒体技术的不断发展新的协议如 SRT、RIST 等也在逐渐普及它们提供了更好的网络适应性和安全性。未来我们还可以结合 5G、边缘计算等技术将流媒体分发推向更高的水平。希望本文能成为你搭建可靠内网流媒体播放体系的得力助手如果你有更多问题欢迎在评论区交流探讨。