GB28181 录像查询返回空,UTC、时区和录像计划怎么对齐
录像列表空的时候,现场最容易先怀疑设备没有录像。这个判断经常来得太快。设备可能确实录了,平台也确实发出了 RecordInfo,只是查询时间落在了录像区间之外;还有一类是设备号和通道号填反,设备在线,查询也有响应,结果仍然是 SumNum=0。
本文按 GB/T 28181-2016 的文件检索流程整理,产品界面和接口示例来自我们自研的 UVP。录像查询返回空,通常按下面的顺序查,先确认时间基准,再确认通道,最后才看设备有没有真的保存文件。

先把空结果和黑屏分开
这两个现象在页面上很接近,排查路径不一样。
| 现象 | 已经证明的事情 | 接下来查什么 |
|---|---|---|
查询完成,列表为空,SumNum=0 | MESSAGE 往返完成,设备给了空目录 | 时间窗口、通道编码、录像条件 |
| 查询完成,列表有片段,点击后黑屏 | RecordInfo 已经有结果 | 回放 INVITE、SDP、RTP、编码格式 |
| 查询一直转圈或超时 | 平台没有拿到有效应答 | 设备在线状态、网络、MESSAGE 报文 |
| 只有某些日期为空 | 链路大概率正常 | 设备时间、录像计划、存储保留周期 |
文章后面只处理第一行。查询已经返回空目录时,播放器还没有参与进来,先去调 RTP 只会把问题带远。
第一步,确认平台和设备的时间基准
GB28181 的录像检索请求包含 StartTime 和 EndTime。规范把它们定义为日期时间字段,实际设备对时区标记的处理并不完全一样。平台界面可能显示北京时间,设备保存文件时可能用本地时钟,平台发出的检索窗口还可能按 UTC 语义计算。三个时间只要有一个没有对齐,结果就会偏移。
下面用假设数据说明。设备按北京时间保存了 10 点到 10 点半的录像,平台却发送不带时区的 02:00 到 02:30,设备仍按北京时间解释,就会查到早八小时的区间。先核实双方的解释方式,不能见到 GB28181 就一律减八小时。XML 的日期时间字段与回放 SDP 的 t= 时间要分别检查。
平台端可先查这三个值。下面是接口返回形状示例,24 仅为示意,现场值以实际接口为准。
{
"timezone": "Asia/Shanghai",
"serverNow": "2026-11-10T10:32:00+08:00",
"maxRangeHours": 24
}timezone 说明平台用哪一个时区解释检索窗口,serverNow 让你知道平台当前时间,maxRangeHours 则告诉你一次首查允许跨多长时间。UVP 的录像参数接口会把这三个字段一起返回,通道离线时也能读到,适合在页面发起查询前先做一次检查。
设备侧要做两件事。第一,看系统时区和 NTP 是否正常。第二,把设备当前时间和平台的 serverNow 放在同一张纸上对照,别只看电脑右下角的时钟。华为的 GB/T 28181 配置文档也把 NTP 校时列为前置条件,并提醒双平台注册时不要让多个平台同时给设备同步时间。

第二步,确认查的是通道,不是设备
RecordInfo 请求里的 DeviceID 既可能指向设备,也可能指向具体通道,取决于平台和设备的实现。现场最稳的做法,是先从 Catalog 响应里拿到通道编码,再把这个编码原样带进查询请求。
设备编码和通道编码通常都是 20 位数字,看起来很像,复制时却不能凭长度猜。目录树里设备是父节点,通道是子节点;录像一般挂在通道上。拿父节点去查,设备可能正常响应,只是返回空目录。
可以按下面的顺序核对。
- 在目录响应里找到真正产生视频的通道节点。
- 记录它的
DeviceID、名称和所属设备。 - 在平台的录像查询页重新选择这个通道,不要手工改编码。
- 把查询范围缩到确定存在录像的 30 分钟以内。
如果平台同时展示设备在线和通道在线,要区分录像存在哪个设备上。摄像头当前离线时,在线的 NVR 仍可能保存该通道的历史录像,不能只凭通道离线就判定没有录像。
第三步,把时间范围缩小到一段已知录像
时间范围太大时,设备端可能返回很多片段,也可能触发平台的首查跨度限制。先用小窗口做验证,能够把两个变量同时压下来。
我建议第一次只查 30 分钟,并选设备刚刚写入的一段录像。查询条件只保留这几项。
| 条件 | 建议值 | 目的 |
|---|---|---|
| 通道 | 从 Catalog 复制 | 排除设备号和通道号混用 |
| 开始时间 | 录像开始前 1 到 2 分钟 | 给设备留出边界 |
| 结束时间 | 录像结束后 1 到 2 分钟 | 避免刚好卡在结束点 |
| 类型 | all 或设备实际类型 | 排除 time、alarm、manual 过滤差异 |
设备端录像查询通常按区间重叠匹配。录像从 10 点 05 分开始,查询 10 点 00 分到 10 点 10 分,应该能够命中;查询 9 点到 10 点 04 分,则可能因为没有重叠而返回空。
第四步,确认设备真的在录
“支持录像回放”和“当前有录像”是两回事。设备支持 RecordInfo,只表示它能处理查询命令。设备没有存储介质、录像计划没覆盖当前时段,或者文件已经过了保留周期,结果都会是空。
桌面模拟器的录像中心和录像计划页可以把这一步拆开看。录像中心负责已有文件,录像计划负责什么时候写文件。先确认已有文件,再检查录像计划是否启用。手动录像或报警录像也可能在没有定时计划的情况下存在。

设备侧可以检查这几项。
- 存储卡或硬盘是否在线,剩余空间是否足够。
- 录像计划是否启用,计划时段是否覆盖查询范围。
- 录像类型是否和请求中的
Type一致。 - 文件是否仍在保留周期内,是否被循环覆盖。
- 设备上是否有多个通道,录像是否写在另一个通道。
如果这些条件都满足,仍然返回空,再回到抓包检查 RecordInfo 的请求和响应。
抓包先核请求,再核分批响应
录像查询的消息可能很长,真正决定结果的字段不多。先看请求里的 DeviceID、StartTime、EndTime 和 Type,再看响应里的 SumNum 与 RecordList。
查询请求使用 Query 根节点,通过 SIP MESSAGE 携带 MANSCDP XML。检查时间字段时,保留原始字符串及双方约定的时区,避免日志显示时二次换算。
响应里 SumNum 是 0,表示设备按自己的条件完成了查询,但没有找到符合条件的片段。这个结果和 MESSAGE 丢包不同。后者通常表现为请求发出以后迟迟没有响应,或者平台只收到半截报文。
把请求和响应放在一起对照时,可以按下面的表走。
| 抓包结果 | 判断 | 动作 |
|---|---|---|
SumNum=0,时间明显偏移 | 时间基准不一致 | 重新核对时区、NTP、serverNow |
SumNum=0,通道号不在 Catalog | 目标错了 | 从目录响应复制通道编码 |
SumNum=0,Type 与已有录像类型不符 | 可能被类型过滤 | 临时改成 all 再查 |
SumNum>0,已收到所需片段但回放失败 | 该片段已检索到 | 转查 INVITE、SDP、RTP 和编码 |
| 请求无响应 | 设备或链路问题 | 查在线状态、网络和 MESSAGE |
SIP 200 OK 只能证明对应 MESSAGE 被接收。业务结果要看 RecordInfo 响应。按 SN 关联请求和响应,结合 SumNum、RecordList 的 Num 与实际条数检查收集情况;文件检索可能分多条 MESSAGE 返回,SumNum 大于零还不能证明所有片段收齐。去重、超时和缺包处理需要平台自行约定。
回放黑屏要另开一条线
查询有记录以后,平台通常会发起回放 INVITE。这个阶段才会出现 SDP 时间、媒体地址、RTP 端口和 PS 封装问题。录像查询为空和回放黑屏是两个相邻的故障,不能用同一套判断。
如果列表有片段,点击回放后没有画面,按这个顺序查。
- 回放 INVITE 的通道编码和查询结果中的通道编码是否相同。
- SDP 的起止时间是否落在返回片段内。
- 设备发送的媒体地址是否能被平台访问。
- RTP 是否到达媒体节点,PS 封装和编码是否匹配。
- H.265 回放异常时,先用 H.264 主码流做一次对照。
做到这里,录像查询这条线已经完成。播放器是否黑屏,属于下一篇文章的范围。
建议的检查顺序
需要快速缩小范围时,可以按下面的顺序检查。
- 在平台读取录像检索参数,记下
timezone、serverNow和maxRangeHours。 - 从 Catalog 找到真实通道编码,确认负责保存录像的设备可达。
- 在设备上确认存储、录像计划和最近一段文件。
- 选一段 30 分钟以内的已知录像,核实双方对查询时间的解释。
- 核对请求条件,再按 SN 关联响应,检查 SumNum 和实际记录数。
- 有片段以后再测回放,别把两个问题混在一起。
这套顺序的好处是每一步都有结果可看。时间错了,改时间;通道错了,换编码;设备没有文件,先修录像计划。等这些条件都成立,才有必要继续看媒体链路。