go2rtc 的 RTMP / FLV 流接入、推流与转发实战指南
【免费下载链接】go2rtcUltimate camera streaming application项目地址: https://gitcode.com/GitHub_Trending/go/go2rtc
go2rtc 内置了完整的 RTMP(Real-Time Messaging Protocol)支持模块,既能以客户端身份从 RTMP 服务器拉流,也能以服务器身份对外提供 RTMP 输出、接收 RTMP 推流,同时还提供基于 HTTP 的 FLV 流输出与接入能力。读完本文,你将掌握 go2rtc 中 RTMP 客户端、RTMP 服务器与 FLV 服务器的完整配置方法与实测用法,并能理解其底层协议实现(握手、Chunk、AMF 命令)在源码中的落点。
模块能力总览
根据 internal/rtmp/README.md,该模块围绕 RTMP 协议提供三大能力:
| 能力 | 方向 | 格式 | 说明 |
|---|---|---|---|
| RTMP Client | 拉流(输入) | rtmp | 从外部 RTMP 服务器获取流,例如 Nginx + nginx-rtmp-module 搭建的服务器 |
| RTMP Server | 输出 / 接入 | rtmp | 对外提供 RTMP 地址,支持播放输出与推流接入 |
| FLV Server | 输出 / 接入 | flv | 基于 HTTP 的stream.flv接口,输出与接入 FLV 流 |
在 main.go 中,rtmp.Init()作为独立模块被注册;真正的事件入口位于 internal/rtmp/rtmp.go,它完成三件事:
- 注册
rtmp、rtmps、rtmpx三种 scheme 的拉流处理器(streams.HandleFunc); - 注册
rtmp、rtmps、rtmpx三种 scheme 的推流(消费者)处理器(streams.HandleConsumerFunc); - 注册
api/stream.flvHTTP 接口(api.HandleFunc)。
RTMP 客户端:从 RTMP 服务器拉流
RTMP 客户端用于从外部 RTMP 服务器读取直播流,例如 Nginx 配合 nginx-rtmp-module 模块搭建的推流服务器。
客户端配置
在go2rtc.yaml的streams段中,将流的源地址写成rtmp://即可:
streams: rtmp_stream: rtmp://192.168.1.123/live/camera1URL 的路径解析规则可从源码确认:在 pkg/rtmp/client.go 中,URL 路径被拆分为App(第一段)与Stream(第二段,且会拼接上原始查询参数):
if args := strings.Split(u.Path, "/"); len(args) >= 2 { c.App = args[1] if len(args) >= 3 { c.Stream = args[2] if u.RawQuery != "" { c.Stream += "?" + u.RawQuery } } }因此形如rtmp://host/live/camera1?token=abc的地址中,live是 App、camera1?token=abc是 Stream 名,查询参数会完整保留,可用于带认证信息的推流地址。
客户端实现链路
拉流入口streamsHandle直接调用rtmp.DialPlay(url)(见 internal/rtmp/rtmp.go)。DialPlay的实现位于 pkg/rtmp/client.go:先解析 URL 并建立 TCP 连接,随后NewClient完成握手与SetPacketSize协商,再依次执行writeConnect→writeCreateStream→writePlay三个 AMF 命令(对应connect、createStream、play),最终返回一个flv.Producer。也就是说,RTMP 拉流在 go2rtc 内部会被统一解封装为 FLV 数据流,再进入统一的 streams 管理框架,从而可以再以任意协议(WebRTC、HLS、MJPEG 等)转发出去。
值得注意的兼容性细节:writePlay的响应等待逻辑针对不同厂商做了适配——注释明确写到 "Reolink response with ID=0, other software respose with ID=5"(pkg/rtmp/conn.go),即不同服务器对onStatus响应的事务 ID 不同,代码对此做了容错。
RTMP 服务器:输出与推流接入
RTMP 服务器功能自 v1.8.0 起加入。默认情况下该服务器是禁用的,需要显式配置监听地址。
服务器配置
rtmp: listen: ":1935" # 默认关闭(disabled)!当listen为空时,Init会直接返回、不启动任何监听(见 internal/rtmp/rtmp.go);配置后则通过net.Listen("tcp", address)监听,并为每个连接启动一个 goroutine 处理。
输出:以 rtmp 格式播放流
任何已存在的流(来自streams配置、WebRTC 发布或其他来源)都可以通过 RTMP 地址播放:
ffplay rtmp://localhost:1935/camera1这里camera1是 go2rtc 中已注册的流名。服务端收到play命令后,tcpHandle会走到CommandPlay分支(internal/rtmp/rtmp.go):通过streams.Get(rtmpConn.App)按 App 名(即流名)找到流,创建一个flv.NewConsumer()订阅该流,然后向客户端回写NetStream.Play.Start状态(WriteStart,见 pkg/rtmp/server.go),最后把 FLV 数据通过 RTMP 连接写出。
接入:接收 RTMP 推流
将任意 RTMP 推流源(FFmpeg、OBS 等)推到 go2rtc:
ffmpeg -re -i BigBuckBunny.mp4 -c copy -f flv rtmp://localhost:1935/camera1服务端收到publish命令后,tcpHandle走到CommandPublish分支(internal/rtmp/rtmp.go):同样按 App 名找到目标流(可以是streams里预先定义的空流,如后文tmp:配置),回写NetStream.Publish.Start,然后将rtmpConn.Producer()作为生产者挂接到该流上并启动。
服务端命令处理
服务端在握手后调用ReadCommands循环读取消息(pkg/rtmp/server.go),依次响应connect、releaseStream、FCPublish、createStream、publish/play等 AMF 命令(acceptCommand,pkg/rtmp/server.go)。其中connect会校验并返回NetConnection.Connect.Success,publish/play会记录Intent后交由上层tcpHandle分发——这是理解 RTMP 服务器"拉流播放"与"推流接入"两条路径分工的关键。
FLV 服务器:基于 HTTP 的输出与接入
FLV 服务器依托 HTTP 接口实现,无需额外配置独立的监听端口(复用 Web 服务的默认端口,如示例中的 1984),是向浏览器等 HTTP 客户端分发 FLV 流的最简单方式。
输出:HTTP FLV 拉流
ffplay http://localhost:1984/stream.flv?src=camera1src参数指定要读取的流名。对应实现outputFLV(internal/rtmp/rtmp.go):取src找到流、创建flv.NewConsumer()订阅,设置响应头Content-Type: video/x-flv,随后把 FLV 数据持续写入 HTTP 响应。请求方式为 GET(非 POST)。
接入:HTTP FLV 推流
ffmpeg -re -i BigBuckBunny.mp4 -c copy -f flv http://localhost:1984/api/stream.flv?dst=camera1dst参数指定接收流的名称,且必须使用 POST 方式。对应实现inputFLV(internal/rtmp/rtmp.go):通过flv.Open(r.Body)将 HTTP 请求体解析为 FLV 生产者,再挂接到目标流上启动。接口的路由分发逻辑在apiHandle中按请求方法区分:POST 走接入(input),否则走输出(output)(internal/rtmp/rtmp.go)。
FLV 编解码实现
FLV 方向的底层实现在 pkg/flv 包中:
- 输出方向:pkg/flv/muxer.go 负责生成 FLV 头、
onMetaData元数据标签,以及 H.264(AVC sequence header)与 AAC(AudioSpecificConfig)的初始化标签;GetPayloader将 RTP 包重新封装为 FLV Tag,并处理关键帧标记(AVC keyframe/composition time)。 - 接入方向:pkg/flv/producer.go 的
probe会对输入流做探测,兼容不同厂商的非标准行为——注释中明确列出 Reolink(音视频 flag 为空、AAC 缺 stereo 键)、OpenIPC 旧固件(无 MetaData、视频包 3 秒后才到)与 Dahua(不发videocodecid)等特殊情形,这正是该模块实测兼容性广泛的原因。
实测兼容性与完整配置
已测客户端(go2rtc 作为 RTMP 客户端拉流)
| 来源 | 目标 | 备注 |
|---|---|---|
| go2rtc | Reolink RLC-520A fw. v3.1.0.801 | OK |
对应的go2rtc.yaml(注意 Reolink 地址可携带?channel/stream/user/password查询参数):
streams: rtmp-reolink1: rtmp://192.168.10.92/bcs/channel0_main.bcs?channel=0&stream=0&user=admin&password=password rtmp-reolink2: rtmp://192.168.10.92/bcs/channel0_sub.bcs?channel=0&stream=1&user=admin&password=password rtmp-reolink3: rtmp://192.168.10.92/bcs/channel0_ext.bcs?channel=0&stream=1&user=admin&password=password已测服务器(向 go2rtc 推流接入)
| 来源 | 目标 | 备注 |
|---|---|---|
| OBS 31.0.2 | go2rtc | OK |
| OpenIPC 2.5.03.02-lite | go2rtc | OK |
| FFmpeg 6.1 | go2rtc | OK |
| GoPro Black 12 | go2rtc | OK,1080p,5000kbps |
接入测试的基础配置:先定义一个空流tmp作为推流目标,并开启 RTMP 监听:
rtmp: listen: :1935 streams: tmp:OBS 推流设置(Settings > Stream):
- Service:Custom
- Server:
rtmp://192.168.10.101/tmp - Stream Key:
<empty>(留空) - Use auth:
<disabled>(关闭)
OpenIPC 推流设置(WebUI > Majestic > Settings > Outgoing):
- Enable 开启
- Address:
rtmp://192.168.10.101/tmp - Save 保存
- Restart 重启设备
FFmpeg 推流命令:
ffmpeg -re -i bbb.mp4 -c copy -f flv rtmp://192.168.10.101/tmpGoPro:在 GoPro Quik 应用中,通过 Camera > Translation > Other 路径将画面推送到 go2rtc。
从 pkg/rtmp/conn.go 的消息类型常量可以看到实现覆盖了完整的 RTMP 消息体系:TypeAudio(8)、TypeVideo(9)、TypeData(18)、TypeCommand(20) 以及带宽/包大小协商(TypeSetPacketSize、TypeServerBandwidth、TypeClientBandwidth)。握手方面,客户端采用简化握手(clienHandshake,pkg/rtmp/client.go),服务端则实现了完整的 C0/C1/S0/S1/S2/C2 四次交换并设置握手超时(serverHandshake,pkg/rtmp/server.go),为上述多种推流端设备的兼容性提供了底层保障。
小结
go2rtc 的 RTMP 模块在协议层面同时覆盖"拉流客户端、RTMP 服务器、HTTP FLV 服务器"三种角色:streams配置中的rtmp://地址用于拉流;rtmp.listen配置开启 RTMP 输出与接入;stream.flv/api/stream.flvHTTP 接口用于 FLV 输出与接入。所有路径最终都汇入统一的 streams 流管理框架,因此拉进来的 RTMP/FLV 流可以无缝转发为 WebRTC、HLS、MJPEG 等其他输出格式,是搭建多协议视频汇聚网关时非常实用的组成部分。
【免费下载链接】go2rtcUltimate camera streaming application项目地址: https://gitcode.com/GitHub_Trending/go/go2rtc
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考