ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

萤石开放平台RTMP直播推流全攻略:从签名鉴权到播放排错

萤石开放平台RTMP直播推流全攻略:从签名鉴权到播放排错 之前做过一个农场直播的项目客户要求把几十路监控画面对外开放还要支持手机端随时观看。最开始我想着自己搭一套 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 streamNamelive_farm_01 validTime3600 time当前毫秒时间戳 sign签名串注意这里我加了 sign 参数。很多新版接口要求在请求参数外额外生成一个签名用来校验请求确实来自你且参数没有被篡改。3.3 签名算法说来简单错起来很隐蔽签名的生成逻辑绝大多数情况下是这套流程把除签名外的所有请求参数按参数名的 ASCII 码升序排序。把排序后的参数拼接成key1value1key2value2...的形式不插任何分隔符。在拼接串末尾追加上 appSecret。对整个拼接后的字符串做 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, dataparams, timeout10, ) 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_keyxxxxxexpire1710000000把它拆开看其实就四部分协议rtmp://推流服务器域名push.example.com应用路径/live/流名称live_farm_01后面跟的?auth_key...expire...是鉴权参数是实现“只有拿到地址的人才能推流”的关键。有效期这个概念一定要重视。pushUrl 不是永久的validTime 过期后地址作废你必须重新获取。我建议有效期的设置策略是“直播计划时长 30 分钟冗余”比如一场 2 小时的直播validTime 填 9000 秒左右。不要图省事直接填一个月地址一旦泄露别人拿着你的 pushUrl 也能往你频道推流这在公网直播里是个安全隐患。4. 真正的推流实操OBS、FFmpeg、嵌入式设备、自研App4.1 第一轮验证用OBS和FFmpeg快速确认链路在写任何业务代码之前先用 OBS 或者 FFmpeg 把整个链路验证通效率最高。用 OBS 的话设置里选“自定义服务”服务器填 pushUrl 里rtmp://到/live/之间的部分也就是rtmp://push.example.com/live串流密钥填流名称和后面的鉴权参数也就是live_farm_01?auth_keyxxxxxexpire1710000000OBS 会自动把服务器和串流密钥拼成完整 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_keyxxxxxexpire1710000000这里的-re表示按视频原始帧率读取-g 50是关键帧间隔。之所以设成 50是因为大多数视频是 25 帧每秒50 帧就相当于每 2 秒一个关键帧。这个参数对直播起播速度影响很大后面我会单独解释。4.2 嵌入式设备、RTMP摄像头、编码器的接入方式接硬件设备的时候配置方式五花八门但核心思路只有一个让设备最终发出的 RTMP URL 等于你刚才拿到的 pushUrl。有些设备管理页只有一个“RTMP推流地址”输入框那就直接把完整 pushUrl 填进去。有些设备分成“服务器地址”和“流名称”两个框这时候要注意服务器地址填rtmp://push.example.com/live流名称填live_farm_01?auth_keyxxxxxexpire1710000000很多硬件设备里面问号、 这类字符都允许出现在流名称里但也有些设备界面会限制字符。如果遇到限制优先选那种支持完整 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而是改用HLShttp://.../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 协议网络抖动或者服务端重启都会导致推流断开而平台侧的推流会话可能在断开的瞬间仍然占用配额直到会话超时释放。我在实际项目里用的是这样一套策略推流断线后立刻用原 URL 重推重试间隔 1 秒、2 秒、4 秒递增最多 5 次。如果 5 次都失败重新调用流管理接口获取新的 pushUrl因为旧的 URL 可能已经过期或者被服务端判为异常。重新拿地址时流名称保持不变避免播放端地址频繁变更导致观众断流。每次获取新地址后主动刷新一次播放端的连接确保服务端重新建立会话。这套逻辑跑下来几十路设备长期推流的稳定性算是比较令人放心的。6.5 多路推流时的配额监控最后提醒一句流管理服务的并发配额是硬限制。如果业务里有动态创建直播会话的逻辑务必要在代码里做好“释放”动作直播结束后按平台要求的方式关闭会话而不是只把推流客户端一关了事。否则会话不释放配额被占满后面新设备再申请推流地址就会失败。我在一个项目里就是忘了处理会话释放导致运营第三天突然有一半设备推不上流查了半天才发现并发量已经打满。后来加了个定时任务扫描“创建超过 2 小时且没有活跃推送”的会话并主动关闭问题才彻底解决。我个人的体会是萤石开放平台的 RTMP 直播推流本身不是一个特别复杂的接入真正的复杂度都在细节里签名、时间戳、地址有效期、编码参数、断线重连、会话释放每一个环节单拎出来都不难但串在一起就能拉开差距。如果你正在做类似的直播接入建议先把链路验证做扎实——用 OBS 或 FFmpeg 确认平台侧畅通再往下接设备或写 App 逻辑这样错误定位会快非常多。希望这篇能帮你少碰几次 401。
返回列表