go2rtc 的 RTMP / FLV 流接入、推流与转发实战指南
2026/9/14 19:03:51 网站建设 项目流程

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,它完成三件事:

  1. 注册rtmprtmpsrtmpx三种 scheme 的拉流处理器(streams.HandleFunc);
  2. 注册rtmprtmpsrtmpx三种 scheme 的推流(消费者)处理器(streams.HandleConsumerFunc);
  3. 注册api/stream.flvHTTP 接口(api.HandleFunc)。

RTMP 客户端:从 RTMP 服务器拉流

RTMP 客户端用于从外部 RTMP 服务器读取直播流,例如 Nginx 配合 nginx-rtmp-module 模块搭建的推流服务器。

客户端配置

go2rtc.yamlstreams段中,将流的源地址写成rtmp://即可:

streams: rtmp_stream: rtmp://192.168.1.123/live/camera1

URL 的路径解析规则可从源码确认:在 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协商,再依次执行writeConnectwriteCreateStreamwritePlay三个 AMF 命令(对应connectcreateStreamplay),最终返回一个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),依次响应connectreleaseStreamFCPublishcreateStreampublish/play等 AMF 命令(acceptCommand,pkg/rtmp/server.go)。其中connect会校验并返回NetConnection.Connect.Successpublish/play会记录Intent后交由上层tcpHandle分发——这是理解 RTMP 服务器"拉流播放"与"推流接入"两条路径分工的关键。

FLV 服务器:基于 HTTP 的输出与接入

FLV 服务器依托 HTTP 接口实现,无需额外配置独立的监听端口(复用 Web 服务的默认端口,如示例中的 1984),是向浏览器等 HTTP 客户端分发 FLV 流的最简单方式。

输出:HTTP FLV 拉流

ffplay http://localhost:1984/stream.flv?src=camera1

src参数指定要读取的流名。对应实现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=camera1

dst参数指定接收流的名称,且必须使用 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 客户端拉流)

来源目标备注
go2rtcReolink RLC-520A fw. v3.1.0.801OK

对应的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.2go2rtcOK
OpenIPC 2.5.03.02-litego2rtcOK
FFmpeg 6.1go2rtcOK
GoPro Black 12go2rtcOK,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/tmp

GoPro:在 GoPro Quik 应用中,通过 Camera > Translation > Other 路径将画面推送到 go2rtc。

从 pkg/rtmp/conn.go 的消息类型常量可以看到实现覆盖了完整的 RTMP 消息体系:TypeAudio(8)、TypeVideo(9)、TypeData(18)、TypeCommand(20) 以及带宽/包大小协商(TypeSetPacketSizeTypeServerBandwidthTypeClientBandwidth)。握手方面,客户端采用简化握手(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),仅供参考

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

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

立即咨询