如何拉取公网RTSP/RTMP流在内网多客户端播放
2026/8/14 12:33:23 网站建设 项目流程

摘要:在监控、直播、物联网等场景中,经常需要将公网摄像头或推流器的 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 协议详解

RTSP(Real Time Streaming Protocol)是一种应用层协议,主要用于控制实时媒体流的传输。它并不直接承载音视频数据,而是充当 “遥控器” 的角色,通过 DESCRIBE、SETUP、PLAY、PAUSE、TEARDOWN 等指令来管理流会话。真正的音视频数据通常由 RTP(Real-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 协议详解

RTMP(Real-Time Messaging Protocol)是 Adobe 公司开发的私有协议,最初用于 Flash 播放器与服务器之间的音视频和数据传输。虽然 Flash 已经逐渐退出历史舞台,但 RTMP 凭借其低延迟、稳定可靠的特点,在直播推流、拉流等场景中依然占据着重要地位。RTMP 默认端口为 1935,它基于 TCP 传输,以消息块的形式传输数据,支持多路复用和分块传输,能够在一条 TCP 连接上同时传输视频、音频和控制消息。

一个典型的 RTMP 握手过程包含三个阶段:简单握手、复杂握手(可选)和连接建立。握手之后,客户端会发送 connect 命令,服务器响应后,客户端再发送 createStream 并 publish 或 play,从而开始推流或拉流。RTMP 的变体还包括 RTMPS(通过 SSL/TLS 加密)、RTMPE(加密版)、RTMPT(HTTP 隧道)等,以适应不同的网络环境。

在公网拉流场景中,RTMP 经常被用作推流协议,主播通过 OBS 等工具将流推送到公网直播服务器,然后内网服务器再从这个公网服务器拉流。由于 RTMP 走 TCP,在公网传输时相对稳定,但高延迟网络下缓冲和重传机制可能会导致播放卡顿,因此需要结合 CDN 和边缘节点来优化。

2.3 内网多客户端播放的挑战

当流被拉入内网后,接下来的挑战是如何高效地分发给多个客户端。如果直接让每个客户端都去拉流服务器建立一个连接,服务器很快就会遇到带宽和 CPU 瓶颈。例如,一个 4Mbps 的流,100 个客户端同时播放就需要 400Mbps 的出口带宽,这对于单台服务器来说压力巨大。而且,每个客户端都独立拉流还会导致源站压力倍增,甚至可能因为过多的 RTSP 连接导致摄像头崩溃。

为了解决这个问题,我们需要引入流媒体分发服务器,它一次拉取源流,然后在内网中通过多播、多路分发或者转码后输出多种协议流,供客户端选择。常见的实现方式有:Nginx-RTMP 模块、SRS(Simple 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 等协议进行播放。

具体的流程如下:

  1. 公网源推流/提供流:摄像头通过 RTSP 提供实时画面,或者主播通过 OBS 推流到公网 RTMP 服务器。
  2. 内网服务器拉流:内网流媒体服务器使用 FFmpeg 或者自带的拉流模块,从公网源拉取 RTSP 或 RTMP 流。
  3. 内网流媒体服务器处理:服务器将拉到的流进行转码(如 H.264 转 H.265、降低分辨率、调整码率),并封装成多种协议供内网客户端访问。
  4. 内网客户端播放:通过 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 是更好的选择;如果已有一套监控系统,需要对接 GB28181,ZLMediaKit 会更合适。

四、环境准备:搭建拉流与分发的基础设施

4.1 操作系统与网络要求

本教程假设使用 Ubuntu 20.04/22.04 或 CentOS 7/8 作为服务器操作系统。推荐使用一台具备公网访问能力(或至少能访问公网源)且内网可达的云主机或物理机。网络配置上,需要确保服务器能够通过公网 IP 或域名访问到 RTSP/RTMP 源,同时内网客户端能够访问服务器的内网 IP。如果公网源位于防火墙后方,请提前做好端口映射(如 TCP 554 用于 RTSP,TCP 1935 用于 RTMP)。

硬件要求取决于流的数量和转码强度。如果只是拉取 1-2 路 1080p 的流并做简单分发,2 核 4G 的服务器即可;如果需要进行多路转码或高并发分发,建议使用 4 核 8G 以上的配置。对于 GPU 转码,需要安装 NVIDIA 驱动和 CUDA 环境。

4.2 安装基础工具:FFmpeg 与 VLC

FFmpeg 是流媒体处理的核心工具,几乎所有拉流、转码、推流操作都离不开它。在 Ubuntu 上安装 FFmpeg 可以使用以下命令(注意,系统自带的版本可能较老,推荐从官方源编译安装或使用静态构建版本):

sudo apt update sudo apt install ffmpeg -y

如果希望使用最新版本,可以从 FFmpeg 官网下载静态编译版本,解压后将其路径加入 PATH 环境变量。验证安装是否成功:

ffmpeg -version

VLC 播放器除了作为客户端播放工具外,还可以在命令行中用于拉流和转流测试。在 Ubuntu 上安装 VLC:

sudo apt install vlc -y

安装完成后,可以使用cvlc命令行工具进行拉流转推等操作,这在调试时非常方便。

4.3 安装 Nginx-RTMP 模块

Nginx 本身并不支持 RTMP,需要编译添加 nginx-rtmp-module。最简单的方式是使用已经集成该模块的发行版,或者通过包管理器安装。Ubuntu 下可以使用如下命令安装 Nginx 并编译 nginx-rtmp-module:

sudo 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 安装 ZLMediaKit

ZLMediaKit 的部署同样简单,推荐使用 Docker:

docker 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] Description=FFmpeg Pull Stream Service After=network.target [Service] Type=simple ExecStart=/usr/bin/ffmpeg -rtsp_transport tcp -i rtsp://公网IP:554/stream1 -c copy -f flv rtmp://127.0.0.1:1935/live/stream1 Restart=always RestartSec=10 User=root [Install] WantedBy=multi-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 相关的配置块。下面是一个典型的配置,实现从公网拉流并输出 HLS:

rtmp { server { listen 1935; # RTMP 监听端口 chunk_size 4096; application live { live on; record off; # 拉流配置:从公网 RTMP 地址拉流,本地应用名为 live pull rtmp://公网直播服务器IP:1935/live/streamkey live=1; } 将上面 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 hlslive流转换为 HLS 切片,并存储在/tmp/hls目录下。最后,HTTP 服务器通过location /hls将 HLS 文件暴露给客户端。

客户端可以通过 VLC 或浏览器(使用 video.js 或 hls.js)访问http://内网服务器IP:8080/hls/streamkey.m3u8来播放。注意,HLS 延迟通常较高(10-30 秒),如果对延迟敏感,可以调整hls_fragmenthls_playlist_length参数,但最小延迟也只能到 5-6 秒左右。

6.2 配置 RTSP 拉流转 RTMP 再 HLS 分发

Nginx-RTMP 本身不支持直接拉取 RTSP 流,但我们可以结合 FFmpeg 来拉取 RTSP 并推送到 Nginx-RTMP 的live应用,然后由 Nginx 生成 HLS。例如,先用 FFmpeg 拉 RTSP 推 RTMP:

ffmpeg -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-FLV

SRS 同样支持拉取 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/WebRTC

8.1 ZLMediaKit 配置文件详解

ZLMediaKit 的默认配置文件为config.ini,包含了丰富的配置项。下面我们配置一个同时支持 RTSP 拉流、RTMP 拉流,并输出 HTTP-FLV、WebSocket-FLV、HLS、WebRTC 的服务器:

[general] mediaServerId=your_server_id [api] apiDebug=1 defaultSnap=./www/logo.png secret=035c73f7-bb6b-4889-a715-d9eb2d1925cc [rtmp] port=1935 enableVhost=1 [rtsp] port=554 timeoutSec=15 [http] port=80 charSet=utf-8 rootPath=./www sslport=443 [multicast] addrMax=239.255.255.255 addrMin=239.0.0.0 udpTTL=64 [hls] broadcastRecordTs=1 deleteDelaySec=10 fastRegister=1 fileBufSize=65536 segDelay=3 segDuration=5 segKeep=0 segNum=3 segRetain=5 [hook] enable=1 on_flow_report=https://your_api_server/on_flow_report on_play=https://your_api_server/on_play on_publish=https://your_api_server/on_publish on_record_mp4=https://your_api_server/on_record_mp4 on_rtsp_auth=https://your_api_server/on_rtsp_auth on_rtsp_realm=https://your_api_server/on_rtsp_realm on_server_started=https://your_api_server/on_server_started on_shell_login=https://your_api_server/on_shell_login on_stream_changed=https://your_api_server/on_stream_changed on_stream_none_reader=https://your_api_server/on_stream_none_reader on_stream_not_found=https://your_api_server/on_stream_not_found [rtc] preferredCodecA=PCMU preferredCodecV=H264 timeoutSec=15 externIP=内网服务器公网IP(如果有) port=10000 rembBitRate=1000000 [rtp_proxy] checkSource=0 dumpDir= port=10000 port_range=30000-30500 timeoutSec=15 [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_sec=0 snap=%s -i %s -y -f mjpeg -frames:v 1 %s

ZLMediaKit 的一大特色是支持 “拉流代理”,即可以配置从远程 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__&app=live&stream=test&url=rtsp://admin:password@公网IP:554/stream1"

添加成功后,流就会在本地生成,并可以通过以下多种协议访问:

  • RTSP:rtsp://内网服务器IP:554/live/test
  • RTMP:rtmp://内网服务器IP:1935/live/test
  • HTTP-FLV:http://内网服务器IP:80/live/test.flv
  • WebSocket-FLV:ws://内网服务器IP:80/live/test.flv
  • HLS:http://内网服务器IP:80/live/test/hls.m3u8
  • WebRTC:通过 WHIP 或 WHEP 协议推拉流,延迟极低。

这种动态拉流的方式非常适合在业务系统中集成,比如用户在前端添加一个摄像头,后端调用 ZLMediaKit 的 API 开始拉流,然后返回播放地址。类似地,也可以使用delStreamProxy接口来停止拉流。

8.3 实现 WebRTC 低延迟播放

WebRTC 是目前延迟最低的浏览器端播放方案,通常可以达到 1 秒以内。ZLMediaKit 支持 WebRTC 播放,可以通过以下步骤实现:

  1. 确保服务器配置了[rtc]部分,并正确设置了externIP(如果服务器在内网,则设为内网 IP,因为客户端在同一个内网)。
  2. 通过 API 或者使用默认流,客户端使用 SDP 交换来建立连接。
  3. 在前端,使用浏览器原生 WebRTC API 或者第三方库(如 webrtc-streamer)来播放。

例如,使用 webrtc-streamer 的简单前端代码:

<html> <head> <script src="webrtcstreamer.js"></script> </head> <body> <video id="video" 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 id="videoElement" controls></video> <script src="flv.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:全平台兼容的分发方案

HLS(HTTP Live Streaming)是苹果公司提出的协议,几乎所有现代浏览器和移动设备都原生支持,兼容性极好。它的工作原理是将视频流切片成一个个小的 TS 文件,并通过 m3u8 索引文件组织起来。延迟较高(通常 10 秒以上),但可以通过减少切片时长和数量来优化,受限于协议本身,最低也只能到 5 秒左右。

在服务器端,SRS 和 ZLMediaKit 都可以自动生成 HLS 切片。客户端播放非常简单,只需在 HTML 中使用 video 标签即可:

<video controls width="800"> <source src="http://内网服务器IP:80/live/test/hls.m3u8" type="application/x-mpegURL"> </video>

HLS 的另一个优势是可以利用 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 id="video" autoplay controls></video> <script src="https://ossrs.net/srs.sdk.js"></script> <script> var srs = new SrsRtcWhipWhepAsync(); srs.play(new URL('http://内网服务器IP:1985/rtc/v1/whip-play/?app=live&stream=test')).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; } }

这样,观众就可以根据网络情况选择播放livestreamlivestream_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 fps=1参数实现定时截图,并将图片发送到 AI 分析服务。例如,每秒截一帧:

ffmpeg -rtsp_transport tcp -i rtsp://摄像头IP:554/stream -vf fps=1 -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,其他作为 Edge,Edge 从 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 554nc -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 内存泄漏与资源占用过高

流媒体服务器长时间运行可能出现内存泄漏,导致进程崩溃。定期监控服务器资源,使用tophtopvalgrind等工具检查。如果是使用 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、边缘计算等技术,将流媒体分发推向更高的水平。希望本文能成为你搭建可靠内网流媒体播放体系的得力助手,如果你有更多问题,欢迎在评论区交流探讨。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询