ONVIF 按「在系统里干什么」把设备分成四类:NVT 发流、NVD 显示、NVS 存流、NVA 分析。 分类不看外形,看 Types 字段和它有哪些 service——所以一台设备可以同时是几种。
上一节拿到的是「地址」,这一节讲「拿到地址之后怎么判断它是什么」。 这一节把「设备类型」和「Profile」彻底分开——这两件事经常被搅在一起,结论就会虚。
一、四个缩写
| 缩写 | 全称 | 是什么 | 典型产品 |
|---|---|---|---|
| NVT | Network Video Transmitter | 发流的一端 | 摄像机 |
| NVD | Network Video Display | 收流并显示的一端 | 解码器、大屏 |
| NVS | Network Video Storage | 存流的一端 | NVR |
| NVA | Network Video Analytics | 分析流的一端 | 分析服务器 |
第一行和第三行最常被搞混: 摄像机(NVT)发流,NVR(NVS)存流—— 但一台设备可以同时是两者(带 SD 卡的摄像机就同时是 NVT 和 NVS)。 所以「这台是 NVT 还是 NVS」这种问法本身不严谨,正确的问法是「它支持哪些 Types」。 Types 是一个集合,不是一个枚举—— 这一点在 WS-Discovery 的 Probe 里就体现出来了:你可以一次问好几种。
二、判类型看 service,判 Profile 看参数
两件事的判据完全不同,混用就会得出半对的结论:
| 要回答的问题 | 看什么 | 性质 |
|---|---|---|
| 它是什么类型 | 有没有对应的 service | 绝对的,有就是有 |
| 它符不符合 Profile S | 编码/分辨率/传输的具体参数 | 有条件的,逐条可查 |
「这是 NVT」是绝对的:有 media service 且能 GetStreamUri,它就是 NVT,没有争议。
「符合 Profile S」是有条件的:H.264、≥720p、RTP over RTSP、WS-Discovery,四条都得满足。
混淆这两件事的典型后果是:看到「1080p、H.264」就说「符合 Profile S」——前两条对了,
但传输和发现根本没验。要把话说实,就得四条逐条查,而不是看着参数表点头。
三、一台设备可以同时是几种类型
判据就是「有没有那组 service」,本机模拟设备四样都有:
| 类型 | 必须有的 service | 本机有吗 |
|---|---|---|
| NVT | media(能 GetStreamUri) |
有 |
| NVS | recording(能 GetRecordings) |
有(简化版) |
| NVD | display(能 GetDisplayOptions) |
有(简化版) |
| NVA | analytics(能 GetSupportedRules) |
有(简化版) |
所以这台模拟设备「同时是四种设备」。
这在真设备上不现实——真摄像机一般只有 media(可能加 recording),
display 在解码器上,analytics 在分析服务器上。
但这正好说明一件事:类型是能力集合,不是身份。
设备不会「声明自己是 NVR」,它只是「恰好有 recording 这组接口」。
理解这一点,就不会再去找「设备类型字段」这种东西了——它根本不存在,
你得自己从 service 列表推。
四、Types 在发现报文里,也在推断里
Types 有两个出现场合,用途不同:
| 场合 | 谁写 | 用途 |
|---|---|---|
| Probe 请求 | 客户端写 | 「我要找哪一类」 |
| ProbeMatch 的 Scopes | 设备写 | 「我是哪一类」 |
第一行是「筛选条件」,第二行是「自我介绍」。
很多客户端只做第一行——发一个 Probe 找 NVT,收到回包就直接连,
从来不核 Scopes 里写的是什么。
这会带来一个实际风险:有的设备(尤其是国产的低价设备)不管你要什么类型,一律回包,
于是你会「发现」一堆其实不是摄像机的东西——比如某个也开了 3702 端口的网关。
所以稳妥的做法是「收到回包后再用 GetServices 核一遍」,看它到底有没有 media。
五、动手 Demo:四种设备类型,靠 Types 和 Profile 认
Demo 从这台模拟设备的响应里推断它的类型,再逐条验「符不符合 Profile S」。 两件事分开做,结论才不虚。
# ① 判类型:有没有对应的 service
_a, b, _n = S.call(port, "device", "GetServices")
ns = []
for svc in ET.fromstring(b).iter("{%s}Service" % S.NS_TDS):
ns.append(svc.find("{%s}Namespace" % S.NS_TDS).text)
KIND = {"media": "NVT", "recording": "NVS",
"display": "NVD", "analytics": "NVA"}
for key, name in KIND.items():
print(name, any(key in x for x in ns))
# ② 验 Profile S 的四条
_a, b2, _n = S.call(port, "media", "GetProfiles")
enc = ET.fromstring(b2).find(".//{%s}Encoding" % S.NS_TT)
w = ET.fromstring(b2).find(".//{%s}Width" % S.NS_TT)
h = ET.fromstring(b2).find(".//{%s}Height" % S.NS_TT)
print(enc.text, w.text, h.text, int(w.text) >= 1280)
实跑输出:
--------------------------------------------------------------------
四种设备类型,靠 Types 和 Profile 认
--------------------------------------------------------------------
**ONVIF 把设备按「在系统里干什么」分成四类。**
分类不看外形,看 **Types 字段**和**它支持哪些 Profile**。
**四种类型(NVT/NVD/NVS/NVA):**
缩写 全称 是什么 典型产品
--------------------------------------------------------------------------------------------
NVT **N**etwork **V**ideo **T**ransmitter **发流的一端** **摄像机**
NVD **N**etwork **V**ideo **D**isplay 收流并显示的一端 解码器、大屏
NVS **N**etwork **V**ideo **S**torage **存流的一端** **NVR**
NVA **N**etwork **V**ideo **A**nalytics 分析流的一端 分析服务器
**第一行和第三行最常被搞混**:
**摄像机(NVT)发流,NVR(NVS)存流**——
**一台设备可以同时是两者**(带 SD 卡的摄像机就同时是 NVT 和 NVS)。
**所以「这台是 NVT 还是 NVS」这种问法本身不严谨**, **正确的问法是「它支持哪些 Types」。**
**Types 在发现报文里,也在这台设备的 Profile 里:**
**按这台设备的响应推断它的类型:**
证据 值 指向
----------------------------------------------------------------------------
有 `media` service **4 个 service** **能发流 → NVT**
编码格式 H264 **H.264 → 符合 Profile S**
分辨率 1920×1080 1080p ≥ 720p → **符合 S**
帧率上限 25 fps ≥ 25 算正常
码率上限 4096 kbps **4 Mbps,1080p 的常态**
**第一行是决定性的**: **有 `media` service 且能 `GetStreamUri`,就是 NVT。**
**第二到五行是在验「符不符合 Profile S」**,
**不是判类型**—— **判类型只看有没有那组能力,判 Profile 才看具体参数。**
**这两件事经常被搅在一起,结论就会虚**:
**「这是 NVT」是绝对的,「符合 Profile S」是有具体条件可查的。**
**一台设备能是什么类型,看它有没有对应的 service:**
类型 必须有的 service 本机有吗
----------------------------------------------------------------------
NVT `media`(能 `GetStreamUri`) **有**
NVS `recording`(能 `GetRecordings`) **有(简化版)**
NVD `display`(能 `GetDisplayOptions`) **有(简化版)**
NVA `analytics`(能 `GetSupportedRules`) **有(简化版)**
**这台模拟设备四样都有,所以它「同时是四种设备」**——
**这在真设备上不现实,但正好说明「类型是能力集合,不是身份」。**
**真摄像机一般只有 `media`(+ 可能 `recording`)**,
**`display` 在解码器上,`analytics` 在分析服务器上。**
第一段那个 any(key in x for x in ns) 是「子串匹配」,
所以 ver10/media/wsdl 能被 media 匹配到。
这种写法在演示里够用,但工程里应该精确匹配尾段——否则 recording 和 recording2 会撞。
第二段只验了四条里的两条(编码和分辨率),
因为另外两条(RTP over RTSP、WS-Discovery)本机验不了:前者要真发 RTP,后者要组播。
所以这里只给「一半的结论」,不假装验全了。
「≥720p」我用的是宽度 ≥1280,这对应 720p 的 1280×720。
没写成 h >= 720 是因为「720p」这个叫法按行数命名,而实际上 1280×720 的宽才是那个 1280。
两个判据在这里等价,但写清「我按宽度判」比含糊过去好。
30 秒实验
- 把
KIND里的display换成ptz,看判出来的类型变成什么。 - 把
int(w.text) >= 1280改成int(w.text) >= 1920,看 1080p 还算不算符合。 - 给模拟设备去掉
analytics那一组,看 NVA 那一行变成什么。
常见误区
- 以为设备会「声明自己是 NVR」。 没有这个字段,类型是从 service 列表推出来的, 一台设备可以同时是几种。
- 把「判类型」和「判 Profile」混在一起。 前者看有没有 service,后者看具体参数, 混用会得出半对的结论。
- 以为 Probe 回包一定是你要的类型。 有的设备不管类型一律回包,
要再用
GetServices核一遍。
自测三问(点开对答案)
1. NVT、NVD、NVS、NVA 分别是什么? —— **发流的(摄像机)、显示的(解码器)、存流的(NVR)、分析的(分析服务器)。** 2. 怎么判断一台设备是不是 NVT? —— **看它有没有 `media` service 且能 `GetStreamUri`。** **这是绝对的判据**,和 Profile 无关。 3. 为什么说「这台是 NVT 还是 NVS」这种问法不严谨? —— 因为**类型是能力集合,不是身份**。 **一台设备可以同时有 `media` 和 `recording`,同时是 NVT 和 NVS。**下一节讲设备管理:GetSystemDateAndTime 返回三个时间,
以及为什么「录像时间对不上」多半是时区问题。
- ☐ (本节完,下一节 07.02.06 设备管理)