开发心得:VSS 流播放—
本文是 2.4.1.0 VSS流播放详解 的配套开发笔记。
1. 明确三个要点
POST /api/video/stream只有一套StreamResp外壳,内里走哪路完全由Device.AccessProtocol决定。- 流媒体是否拉起来,不都是
StartRelyPull的成功:协议 4(GB28181) 在 Invite 成功后就返回,不会再走 文件末尾的StartRelyPull;没画面需要去查 SIP + MS Pub。 streamName是全局会话键:回放带PlaybackCount后缀、QuerystreamName可覆盖默认值;StopMultiMSStream / Invite 防重入 / 快照 都围着他的规则,改命名规则要谨慎。
2. 时间参数:直播 / 回放
// 回放
if req.EndAt > 0 && req.StartAt > 0 {
playType = stream.PlayTypePlayback
autoStopPullAfterNoOutMs = 10000
}
- 回放判定是
StartAt > 0 && EndAt > 0(毫秒时间戳),少一个则仍是 直播,流名与autoStopPullAfterNoOutMs(60s vs 10s)都不一致。 - 前端只传
endAt、或把秒当毫秒传,表现为「以为是回放,实际一直 live」,Invite/拉流行为全错。联调先 打印时间戳数量级。
3. MS 节点:VoteNode 与 PlayAddress
MSIds投不出节点 → 直接 「未设置流媒体源」,与设备是否在线无关。IsDef分支:非默认要GetMSConf拉端口再PlayAddress;默认节点用已有msNode。MS HTTP 管理端口不通时,地址数组全空,客户端报「没地址」,先检测curlhttp://{msAddress}的配置接口。httpsquery:通过ms.New(...).WithHttps(req.Https)影响投票与播放侧 HTTPS 能力,与 SIP 无关;和网关 TLS 终止混用时容易出错。
4. 协议表
| 协议 | streamUrl | 是否StartRelyPull | 排障 |
|---|---|---|---|
| 1 流媒体源 | 设备 StreamUrl | streamUrl != "" 会 | MS 拉流参数、RTSP TCP/UDP(MediaProtocolMode→rtspMode) |
| 2 RTMP 推 | 不设(等设备推) | 一般不进 StartRelyPull | on_pub_start 收到了没、流名与 MS 是否一致 |
| 3 ONVIF | 通道 StreamUrl | 同左 | 通道 URL 是否过期、认证、rtsp_mode |
| 4 GB28181 | Invite 链路透传 | 本接口不调 StartRelyPull | Catalog/Invite/200 SDP/MS RTPPub,见下节 |
rtspMode 注释在源码里写的是 0 tcp 1 udp;MediaProtocolMode == 0 时置 rtspMode = 1(UDP)需要和 MS 文档对照核对,别凭直觉写反了。
5. GB28181:stream_play
case devices.AccessProtocol_4: // GB28181协议
if playType == stream.PlayTypePlayback {
if err := ms.New(l.ctx, l.svcCtx).StopMultiMSStream(/* 流名前缀+playback */); err != nil {
// ...
} else {
time.Sleep(1 * time.Second)
}
}
if res := gbs.InviteLogic.New(...).Invite(&gbs.InviteParams{ ... }); res != nil && res.Err != nil {
return res
}
go l.saveChannelSnapshot(streamName, res.Data)
return &types.HttpResponse{Data: data}
- 回放先
StopMultiMSStream+ Sleep 1s,为的是少抢流;前缀拆法依赖streamName与playType字符串,改Produce规则时要连同这里一起测。 - 成功路径:
Invite→ 立刻 HTTP 返回StreamResp;媒体建立是 异步 的。通常「接口通了没画面」,多半还在 SIP/MS。请参考 [5.1 信令与 SDP]、[2.4.1.1 SDP]。
6. streamName 覆盖 Query:对齐现有会话
if l.c != nil {
if v := l.c.Query("streamName"); v != "" {
streamName = v
}
}
前端随便传 streamName,与 Invite 里实际用的名不一致,会导致 Stop 停错流、快照存错键、前端播放器 404。应对:约定覆盖仅用于重连同一会话,与 video_live_invite 同源。
7. StartRelyPull 失败即整体失败
在非 GB 分支在 streamUrl != "" 时调用 MS /api/ctrl/start_relay_pull,任一错误直接 HTTP 错误响应。
- MS 离线、超时、URL 不可达、鉴权失败——现象都是 业务层 4xx/5xx,注意排查。
8. 快照与播放解耦
go saveChannelSnapshot:流截图、FFmpeg、目录配置;失败不影响 播放接口返回成功。- 当看到没有缩略图就认定播放失败,需要先分两条线查:拉流 URL 能否播 vs
SaveVideoSnapshotDir/ FFMpeg 配置。
9. 并发与防抖
- 2.4.1.0 第六节已讲解,
stream_play高频重入要考虑dt节流或前端防抖,否则 GB 路径尤易出现 「第二次 Invite 被拒」。
10. 联调清单
- 回放:
StartAt/EndAt正整数、毫秒、时区是否一致。 - 拉流协议:
MediaProtocolMode需与现场 RTSP TCP/UDP 一致。 - 改
stream.New().Produce规则:同步测 StopMultiMSStream 前缀、快照路径、前端流名。 - RTMP(2):确认 推流已上 再播,别只看 HTTP 返回。
11. 相关文档
| 文档 | 内容 |
|---|---|
| 2.4.1.0 VSS流播放详解 | 主流程与源码索引 |
| 2.4.1.2 信令发送流水线 | Catalog / SendLogic |
| 5.1 开发心得-信令字段与 SDP | INVITE 头与 SDP 身份 |