☰
萤石开放平台RTMP直播推流全攻略:从签名鉴权到播放排错
2026/10/6 3:05:07 网站建设 项目流程

之前做过一个农场直播的项目,客户要求把几十路监控画面对外开放,还要支持手机端随时观看。最开始我想着自己搭一套 nginx-rtmp 推流服务器,结果从带宽、安全组端口到播放端的延迟控制,每个环节都在耗人。后来切到萤石开放平台的音视频能力,用流管理里的 RTMP 直播推流把视频源推到平台侧,再由平台负责收流、转码和分发,整个链路一下子清爽了很多。

这篇东西,就是围绕萤石开放平台“流管理(RTMP):直播推流”这个方向写的。下面会完整走一遍从账号准备、签名规则、获取推流地址,到 OBS/FFmpeg/嵌入式设备/自研 App 实际推流,再到拉流验证和排错的整个闭环。适合三种人看:想把自有摄像头画面接进萤石云的非嵌入式开发者、负责服务端接口对接的后端工程师,以及正在评估“自建推流服务器 vs 平台流服务”的团队负责人。

1. 先搞清楚RTMP推流在萤石平台里的位置

1.1 萤石开放平台的音视频能力版图

萤石开放平台不是一个简单提供云台控制的接口集合,它的音视频能力大致可以分成三块:

  • 设备接入层:拿萤石的摄像头、NVR、门铃等设备,通过 SDK 或云平台 API 做预览、回放、云存储。
  • 流服务层:也就是本文要讲的“流管理”,核心是帮你把一路视频流收进来、存起来、再分发给任意终端。流管理支持多种协议,包括 RTMP 推流、HLS 拉流、FLV 拉流等。
  • 应用能力层:类似 AI 识别、人脸聚类、语音对讲这些附加服务。

这里要特别注意:我们常说的“萤石云”App 里的实时预览,走的是萤石自有的私有协议链路,开发者直接调接口拿到的预览流,跟你自己用 FFmpeg 往某个 RTMP 地址推流,是两条不同的技术路线。本文讲的“RTMP 直播推流”,是把你自己手里的视频源(手机摄像头、编码器、RTMP 摄像头、甚至一个 MP4 文件循环推流)通过标准 RTMP 协议推到萤石平台的流管理服务,再由平台出播放地址。

1.2 RTMP推流适合什么业务

我在实际对接中发现,下面几类场景最适合走这条路:

  • 自有采集类 App:比如做户外直播、车载直播、巡检采集,App 里采集到画面,不想自己搭流媒体服务器,直接把流推到平台。
  • 没有萤石 SDK 的硬件设备:很多 RTMP 摄像头、HDMI 编码器、直播盒子,只认标准的 RTMP 推流协议,你没法往里面塞一个萤石 SDK,这时候直接配置 RTMP 推流地址是最省事的。
  • 临时性直播事件:像展会、发布会、工地安全巡查,几台设备临时架起来推流,结束后就不需要了,用平台的动态流会话很合适。
  • 源站信号向多端分发:比如一个导播台输出 RTMP,推到平台后,由平台的 HLS/FLV 能力分发给大量 Web 端用户,省去自己搭建分发集群。

至于为什么选 RTMP 而不是别的协议,很简单:RTMP 是直播推流事实上的“通用语言”。OBS、FFmpeg、几乎所有编码器和推流软件都支持。它基于 TCP,传输稳定,生态成熟,社区里能查到的资料也最多。相比 RTSP 适合局域网内预览、SRT 适合复杂网络下的可靠传输,RTMP 在“把流送上公网平台”这个场景里兼容性最好。

1.3 自建推流服务器和平台流管理的取舍

我知道很多人一听到 RTMP,第一反应是自己在服务器上装 nginx-rtmp 模块。我早期也这么干过,但踩了一圈后总结下来:

  • 自建方案:好处是可控性强,爱怎么配怎么配。代价是你要自己处理带宽瓶颈、存储策略、转码切片、鉴权防拉、可用性监控。一台 4 核 8G 的云主机,能稳定支撑的同时推流路数其实很有限,一旦并发上来,CPU 和带宽双双告警。
  • 平台流管理:相当于推流、转码、分发、播放地址生成这一整套都有人替你扛了。你只需要按规则拿到推流地址,把流推上去,然后拿播放地址去分发给观众。

不是吹平台多好,但如果你团队里没有专门的流媒体运维,生产级直播业务直接用平台流服务,性价比确实更高。费用上也不是简单的“服务器价钱”对比,而是你把人力、带宽、故障处理的隐形成本都算进去,再用一个月度账单换掉一整条维护链路。

2. 账号侧准备:最容易卡壳的前置步骤

2.1 注册开发者账号并创建应用

先到萤石开放平台注册账号,做开发者实名认证。这一步通常很快,过了以后进入开发者控制台,创建一个应用。

创建应用成功后会拿到两个关键字符串:

  • appKey:应用的公钥标识,相当于你的应用 ID,可以明文出现在请求里。
  • appSecret:应用的密钥,相当于你的密码,绝对不能泄露到客户端或者前端代码里。

我在项目里见到最多的低级错误,就是把 appSecret 直接写死在 Android 或 iOS 的 App 里。要知道 appSecret 一旦被拿到,别人就能冒充你的应用去请求接口,盗用服务。正确做法是:appSecret 只保存在你的服务端,客户端需要签名的时候,由服务端代理请求并返回结果。

2.2 获取调接口用的accessToken

萤石开放平台的 OpenAPI 调用,除了部分接口直接用签名之外,很多业务接口(包括流管理)都需要一个 accessToken。这个 token 相当于“当前操作者”的临时凭证,获取方式通常是调用 token 接口。

一个典型的 token 请求可以这样理解:

POST https://open.ys7.com/api/lapp/token/get Content-Type: application/x-www-form-urlencoded appKey=你的appKey appSecret=你的appSecret time=当前毫秒时间戳

返回的 JSON 里,如果 code 是 200,就能在 data.accessToken 字段拿到 token。不同版本的 OpenAPI 在 token 生成的细节上可能有差异,比如有的版本引入了 sign 签名参数,有的还要求对 appSecret 做加密传递,所以接入时一定要先对照你实际开通的接口文档版本。

2.3 开通流管理服务并确认购买/试用配额

拿到账号和应用之后,还需要在控制台开通“流管理”相关的服务。这一步很多人会忽略,以为创建完应用就能调流管理接口。实际上流服务通常需要在服务市场或控制台里单独开通,有的还涉及套餐选择。

开通的时候认真看一下两个参数:

  • 并发路数:同时可以推流的会话数量。如果做测试,1-2 路足够;如果做几十路监控直播,要按峰值算。
  • 有效期:套餐是按天/月/年计费还是按调用量计费,避免压测时不小心把几百路并发全部跑起来,产生意料之外的费用。

我自己就犯过这个错,压测脚本里写了个循环自动建流,跑了一晚上,第二天看到账单吓了一跳。正规做法是先开试用配额,压测前和服务方确认计费规则。

2.4 确认设备/流标识的管理方式

你要推流,总得有个“身份标识”让平台知道这是哪个应用、哪个会话在推。这个标识可能是设备序列号 + 通道号(如果你用的是萤石设备),也可能是自定义流名称(如果你推的是自有视频源)。

如果用的是自有视频源,一般需要提前规划流名称的命名规则,比如live_farm_01、meeting_f415。别小看这个命名,后期做多路管理的时候,一个好的命名规则能让你少写一堆代码。我习惯用“业务前缀_场景_序号”的结构,方便统计和排错。

3. 获取推流地址的完整链路:接口、参数、签名规则

3.1 推流地址与播放地址:先分清再动手

这是新手最容易犯浑的地方。一次 RTMP 直播推流会话,平台通常会返回两类地址:

  • pushUrl:推流地址,用来把视频流推上去。地址开头一般是rtmp://push.xxx.com/live/...。
  • playUrl:播放地址,用来给观众拉流观看。可能是rtmp://开头,也可能是http://...m3u8或者http://...flv。

很多人拿到一长串 URL,不分青红皂白塞进播放器,结果自然是连不上。这两类地址长得有点像,但用途完全不一样。我在下文的示例里会把返回字段分开写,你自己对接时也要在文档里认准。

3.2 流管理接口的调用方式

要拿到推流地址,需要调用流管理的相关接口。不同的接口版本命名可能不同,但逻辑是一致的:你告诉平台“我要创建一个推流会话,会话时长是多久,流名称是什么”,平台返回给你一个对应的 pushUrl。

一个典型的请求是这样的:

POST https://open.ys7.com/api/lapp/stream/rtmp/publish Content-Type: application/x-www-form-urlencoded appKey=你的appKey accessToken=你的accessToken streamName=live_farm_01 validTime=3600 time=当前毫秒时间戳 sign=签名串

注意这里我加了 sign 参数。很多新版接口要求在请求参数外额外生成一个签名,用来校验请求确实来自你,且参数没有被篡改。

3.3 签名算法:说来简单,错起来很隐蔽

签名的生成逻辑,绝大多数情况下是这套流程:

  1. 把除签名外的所有请求参数,按参数名的 ASCII 码升序排序。
  2. 把排序后的参数拼接成key1value1key2value2...的形式,不插任何分隔符。
  3. 在拼接串末尾追加上 appSecret。
  4. 对整个拼接后的字符串做 MD5,得到签名串。

给你一个可以直接跑通流程的 Python 示例,别的语言写法同理:

import hashlib import time import requests def gen_sign(params: dict, secret: str) -> str: # 1. 按 key 的 ASCII 升序排序 sorted_keys = sorted(params.keys()) # 2. 拼接 key 和 value raw = "".join(f"{k}{params[k]}" for k in sorted_keys) # 3. 末尾追加 secret raw += secret # 4. 做 MD5,注意大小写要和文档一致 return hashlib.md5(raw.encode("utf-8")).hexdigest().upper() def get_push_url(app_key: str, app_secret: str, access_token: str, stream_name: str, valid_time: int = 3600): params = { "appKey": app_key, "accessToken": access_token, "streamName": stream_name, "validTime": valid_time, "time": str(int(time.time() * 1000)), } sign = gen_sign(params, app_secret) params["sign"] = sign resp = requests.post( "https://open.ys7.com/api/lapp/stream/rtmp/publish", data=params, timeout=10, ) data = resp.json() if data.get("code") == 200: return data["data"] raise RuntimeError(f"创建推流会话失败: {data}")

几个容易踩的细节我提前说明:

  • 拼接顺序必须是“先拼 key 再拼 value”,不是把所有 value 拼一串。
  • 排序是 ASCII 升序,注意accessToken里如果有大写字母,排序结果和你直觉不一样是正常的。
  • 签名转大写还是保持小写,以你使用的文档示例为准。不同接口版本差异很大,有的强制大写,有的小写。这个我后面在踩坑部分还会细说。

3.4 推流地址的结构拆解与有效期管理

拿到返回结果后,pushUrl 的样子大体是这样的:

rtmp://push.example.com/live/live_farm_01?auth_key=xxxxx&expire=1710000000

把它拆开看,其实就四部分:

  • 协议:rtmp://
  • 推流服务器域名:push.example.com
  • 应用路径:/live/
  • 流名称:live_farm_01,后面跟的?auth_key=...&expire=...是鉴权参数,是实现“只有拿到地址的人才能推流”的关键。

有效期这个概念一定要重视。pushUrl 不是永久的,validTime 过期后地址作废,你必须重新获取。我建议有效期的设置策略是“直播计划时长 + 30 分钟冗余”,比如一场 2 小时的直播,validTime 填 9000 秒左右。不要图省事直接填一个月,地址一旦泄露,别人拿着你的 pushUrl 也能往你频道推流,这在公网直播里是个安全隐患。

4. 真正的推流实操:OBS、FFmpeg、嵌入式设备、自研App

4.1 第一轮验证:用OBS和FFmpeg快速确认链路

在写任何业务代码之前,先用 OBS 或者 FFmpeg 把整个链路验证通,效率最高。

用 OBS 的话,设置里选“自定义服务”:

  • 服务器:填 pushUrl 里rtmp://到/live/之间的部分,也就是rtmp://push.example.com/live
  • 串流密钥:填流名称和后面的鉴权参数,也就是live_farm_01?auth_key=xxxxx&expire=1710000000

OBS 会自动把服务器和串流密钥拼成完整 URL。点开始推流,如果平台侧创建会话成功,几秒后状态就会变成“流已连接”。

如果你想做自动化测试,用 FFmpeg 更方便。下面这条命令可以把一个本地 MP4 循环推上去:

ffmpeg -re -stream_loop -1 -i test.mp4 \ -c:v libx264 -preset veryfast -b:v 2500k -maxrate 2500k -bufsize 5000k -g 50 \ -c:a aac -b:a 128k -f flv \ "rtmp://push.example.com/live/live_farm_01?auth_key=xxxxx&expire=1710000000"

这里的-re表示按视频原始帧率读取,-g 50是关键帧间隔。之所以设成 50,是因为大多数视频是 25 帧每秒,50 帧就相当于每 2 秒一个关键帧。这个参数对直播起播速度影响很大,后面我会单独解释。

4.2 嵌入式设备、RTMP摄像头、编码器的接入方式

接硬件设备的时候配置方式五花八门,但核心思路只有一个:让设备最终发出的 RTMP URL 等于你刚才拿到的 pushUrl。

有些设备管理页只有一个“RTMP推流地址”输入框,那就直接把完整 pushUrl 填进去。有些设备分成“服务器地址”和“流名称”两个框,这时候要注意:

  • 服务器地址填rtmp://push.example.com/live
  • 流名称填live_farm_01?auth_key=xxxxx&expire=1710000000

很多硬件设备里面问号、& 这类字符都允许出现在流名称里,但也有些设备界面会限制字符。如果遇到限制,优先选那种支持完整 URL 填写的设备固件,否则只能找设备厂商确认是否支持自定义鉴权头。

另外,一些老设备推流时还会要求填“用户名”和“密码”。如果平台侧鉴权已经通过 URL 参数完成,用户名密码一般留空就行。千万别自作主张在用户名密码里再塞一遍鉴权参数,我遇到过一个客户这么干,结果 RTMP 握手阶段直接失败,日志里明明白白写着 401 未授权。

4.3 自研App内嵌推流SDK:选型与参数注意

如果你要在自己的 Android/iOS App 里做推流,可选方案大致有三类:

  • 直接用开源库:比如 librtmp、FFmpeg 命令行封装,适合只需要把裸流推上平台的简单需求。
  • 用商业直播 SDK:这类 SDK 一般带采集、美颜、硬编码、弱网对抗等能力,适合做面向 C 端用户的直播产品。
  • 系统原生能力 + 自定义封装:比如 Android 的 MediaCodec 硬编码 + 自定义 RTMP 打包,iOS 的 VideoToolbox + 自定义推流,适合有音视频开发经验的团队。

不管选哪种,有一点必须提醒:推流地址里的参数要正确做 URL 编码,特别是当 pushUrl 里的鉴权参数带&时,不能把 URL 直接当普通字符串拼接进推流库的配置里,否则客户端会把&后面的内容当成新的参数解析,导致鉴权失败。正确做法是对 query 部分做 percent-encoding 后再拼接。

4.4 编码参数推荐与“起播慢”的根源

推流之前,最好先想清楚编码参数。下面这组推荐值是我在直播项目里反复试过的,普遍适用:

场景分辨率码率帧率关键帧间隔
手机直播/讲解720p2-3 Mbps25fps2s
监控画面/静态场景1080p2-4 Mbps15-25fps2s
户外运动/快速画面1080p4-6 Mbps30fps1-2s
低带宽保证480p0.8-1.2 Mbps20fps2s

关键帧间隔(GOP)这个参数经常被忽略。H.264 编码的视频,解码器每次都要等一个关键帧才能开始出画面,如果关键帧间隔设成 10 秒,观众端拉流后平均要等好几秒才能看到画面,表现就是“起播慢”。很多直播项目一上来骂平台延迟高,结果查了半天,是自己推流端 GOP 设得太大了,平台再优化也救不回来。

音频方面,用 AAC 编码,采样率 44.1kHz 或 48kHz,码率 96-128kbps 足够。注意别把音频采样率设成 8kHz 之类的古董参数,部分播放器兼容性会出问题。

5. 拉流播放验证与常见问题排查

5.1 用VLC验证推流是否真的成功

推流上去之后,第一件事是拉流验证。随手可用的工具就是 VLC:媒体 -> 打开网络串流,粘贴返回的 playUrl,几秒后出画面就说明整条链路通了。

这里有个很重要的排错分层思路:如果 VLC 能出画面,但你的业务播放器不行,问题大概率出在你的播放器实现,而不是推流链路。反过来,如果 VLC 都拉不出来,那就要回头查拿地址、推流参数、编码格式这三件事。

5.2 Web播放器的现实:HTML5不能直接播RTMP

很多人搜“vue 的 rtmp 播放器”,本质上是在找一个能在网页里直接播 RTMP 流的方案。现实是:现代浏览器已经不支持 RTMP 协议,网页端播放 RTMP 流的插件方案也基本被废弃了。正确的做法是拉流端不要用 RTMP,而是改用:

  • HLS:http://.../xxx.m3u8这种地址,兼容性最好,iOS/Android/桌面 Web 通吃,缺点是延迟偏高。
  • HTTP-FLV:配 flv.js 在 Web 端播放,延迟比 HLS 低不少,适合需要更低延迟的互动直播场景。
  • WebRTC:如果平台支持,可以做到极低延迟,但一般需要额外配置,这个先不展开。

所以一个典型的 Web 直播系统是:推流端用 RTMP,播放端用 HLS/HTTP-FLV。pushUrl 是给推流用的,playUrl 是给播放器用的,两边各管各的。

5.3 常见问题排查:现象、原因、动作

把我在项目中遇到最多的问题整理成一张表,直接照着排查:

现象可能原因排查动作
推流端一直 401推流地址过期 / 鉴权参数被截断重新获取 pushUrl,检查地址里问号和 & 是否完整
能推流但播放黑屏编码格式不在支持范围改用 H.264 + AAC,关闭 MPEG4 编码选项
播放起播慢关键帧间隔太长推流端把 GOP 调到 2 秒以内
播放卡顿、花屏上行带宽不足 / 码率过高降低编码码率,检查推流端网络质量
推流中途频繁断开弱网丢包严重 / 断线无重连推流端实现指数退避重连,重连前重新获取地址
Web 端播不了用了 RTMP 地址给浏览器换成 HLS 或 HTTP-FLV 播放地址

这些问题的共同点在于:大多数看起来像是平台的问题,根子都在推流端配置。所以做直播业务,第一优先是把推流端参数标准化,再谈平台怎么样。

6. 我在实际项目中踩过的坑

6.1 签名大小写不一致:一个401排查了两小时

有一回调试流管理接口,请求发出去死活报鉴权失败。代码逻辑翻来覆去看了好几遍,参数排序、拼接顺序都没错,最后把请求里的 sign 和文档示例里的 sign 打出来对比,才发现文档示例是大写 32 位 MD5,我生成的却是小写。平台校验的时候按大写解析,自然不通过。

这种问题排查起来特别隐蔽,因为没有报错细节,只有一行“签名错误”。我的建议是:第一步永远先把签名打印出来,和服务端返回提示里给出的签名做肉眼对比,再考虑其他可能性。另外,同一个项目里不同接口的签名规则可能存在细微差异,接入新接口时不要照搬旧代码,先看文档。

6.2 设备时间不准导致token请求被拒

还有一次,token 接口请求提示请求时间过期。我第一反应是平台问题,后来测了一下服务器时间,发现那台测试服的系统时间快了整整五分钟。时间戳校验是防重放的重要手段,本地时间不准,所有带 time 参数的请求都会不正常。

解决办法很直接:保证服务器时间同步(NTP 校准);如果业务端拿到“时间戳偏差”类报错,优先查本地时钟,不要一上来就怀疑密钥。

6.3 把pushUrl当成playUrl填进VLC

听着很初级,但实际遇到的时候真的会懵。一个客户发了张截图,VLC 打不开直播地址,仔细一看,他填的是推流地址。在初期排查时,先确认自己拿到的地址是 push 还是 play,可以省掉很多无用功。平台返回的数据里,pushUrl 和 playUrl 可能同时在同一个结构里,接口对接时养成好习惯,把这两个字段分开处理,不要笼统地存成一个 URL。

6.4 长期直播场景下的断线重连设计

如果是做监控巡检这类需要长时间推流的业务,一定要提前设计好重连机制。RTMP 是 TCP 协议,网络抖动或者服务端重启都会导致推流断开,而平台侧的推流会话可能在断开的瞬间仍然占用配额,直到会话超时释放。

我在实际项目里用的是这样一套策略:

  1. 推流断线后,立刻用原 URL 重推,重试间隔 1 秒、2 秒、4 秒递增,最多 5 次。
  2. 如果 5 次都失败,重新调用流管理接口获取新的 pushUrl,因为旧的 URL 可能已经过期或者被服务端判为异常。
  3. 重新拿地址时,流名称保持不变,避免播放端地址频繁变更导致观众断流。
  4. 每次获取新地址后,主动刷新一次播放端的连接,确保服务端重新建立会话。

这套逻辑跑下来,几十路设备长期推流的稳定性算是比较令人放心的。

6.5 多路推流时的配额监控

最后提醒一句,流管理服务的并发配额是硬限制。如果业务里有动态创建直播会话的逻辑,务必要在代码里做好“释放”动作:直播结束后,按平台要求的方式关闭会话,而不是只把推流客户端一关了事。否则会话不释放,配额被占满,后面新设备再申请推流地址就会失败。

我在一个项目里就是忘了处理会话释放,导致运营第三天突然有一半设备推不上流,查了半天才发现并发量已经打满。后来加了个定时任务扫描“创建超过 2 小时且没有活跃推送”的会话并主动关闭,问题才彻底解决。


我个人的体会是,萤石开放平台的 RTMP 直播推流,本身不是一个特别复杂的接入,真正的复杂度都在细节里:签名、时间戳、地址有效期、编码参数、断线重连、会话释放,每一个环节单拎出来都不难,但串在一起就能拉开差距。如果你正在做类似的直播接入,建议先把链路验证做扎实——用 OBS 或 FFmpeg 确认平台侧畅通,再往下接设备或写 App 逻辑,这样错误定位会快非常多。希望这篇能帮你少碰几次 401。

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

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

立即咨询