设备注册成功后,接下来要做的就是获取设备的信息,尤其是通道信息,根据国标协议,永远只有两个层级,一个是设备,然后就是设备下面多个通道,设备编码在整个系统中唯一,通道编码在一个设备中唯一,如果不唯一,那就可能会产生冲突,其实是程序层面的冲突,硬件层面不冲突,这个不是mac地址这种唯一性,仅仅是软件层面的学号的约定。理论上来说可以重复,但是软件编写者一般不会这么要求,包括国标文档也要求不能重复,一旦重复的话,很多逻辑和操作不好处理。
获取设备信息一般会拿到设备的名称,通道的信息会拿到编码和名称,这些名称可能是中文,需要转码才能正常解析。设备状态用的很少,除非用户主动去获取,设备的配置参数用的也很少,甚至很多国标监控系统不会去做,我也是从国标文档中才找到的对应的指令,一般通过设备参数拿到超时时间和超时次数,然后服务端这边根据这个值来判断是否超时,而不是写死一个超时时间。
在实际应用现场,会发现有些NVR上电后,连接上服务端后传过来的通道信息不全,因为该NVR下面的设备还没有完全上线,尽管已经做了目录订阅功能,但是上线后未必会主动通知,需要定时查询通道信息才能获取到,所以做了个定时查询的机制,一旦查询到有新的设备变动,则发出信号,重新更新设备通道信息。
//获取设备信息:服务端-》设备端
MESSAGE sip:34020000001320000002@192.168.0.64:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.110:15060;branch=z3hG9bK9225da1aa0084d469ebc6f6694bf6dc8
From: <sip:34020000002000000001@192.168.0.110:15060>;tag=1019
To: <sip:34020000001320000002@192.168.0.64:5060>
Call-ID: 35d87369b8b34488867dfbfbea2e91c2
CSeq: 20 MESSAGE
User-Agent: wx_feiyangqingyun
Max-Forwards: 70
Content-Length: 154
Content-Type: application/MANSCDP+xml
Contact: <sip:34020000002000000001@192.168.0.110:15060>
<?xml version="1.0" encoding="GB2312"?>
<Query>
<CmdType>DeviceInfo</CmdType>
<SN>10019</SN>
<DeviceID>34020000001320000002</DeviceID>
</Query>
//设备信息返回:设备端-》服务端
MESSAGE sip:34020000002000000001@3402000000 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.64:5060;rport;branch=z9hG4bK2061567590
From: <sip:34020000001320000002@3402000000>;tag=415404928
To: <sip:34020000002000000001@3402000000>
Call-ID: 541248116
CSeq: 20 MESSAGE
Content-Type: Application/MANSCDP+xml
Max-Forwards: 70
User-Agent: IP Camera
Content-Length: 324
<?xml version="1.0" encoding="GB2312"?>
<Response>
<CmdType>DeviceInfo</CmdType>
<SN>10019</SN>
<DeviceID>34020000001320000002</DeviceID>
<Result>OK</Result>
<DeviceName>IP CAMERA</DeviceName>
<Manufacturer>Hikvision</Manufacturer>
<Model>DS-2CD5024EFWD</Model>
<Firmware>V5.5.85</Firmware>
<Channel>1</Channel>
</Response>
//获取设备状态:服务端-》设备端
MESSAGE sip:34020000001320000002@192.168.0.64:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.110:15060;branch=z3hG9bK326223905abd4c258ab82e726ef93616
From: <sip:34020000002000000001@192.168.0.110:15060>;tag=1018
To: <sip:34020000001320000002@192.168.0.64:5060>
Call-ID: f69573838e564a4c8762a3465544037b
CSeq: 19 MESSAGE
User-Agent: wx_feiyangqingyun
Max-Forwards: 70
Content-Length: 156
Content-Type: application/MANSCDP+xml
Contact: <sip:34020000002000000001@192.168.0.110:15060>
<?xml version="1.0" encoding="GB2312"?>
<Query>
<CmdType>DeviceStatus</CmdType>
<SN>10018</SN>
<DeviceID>34020000001320000002</DeviceID>
</Query>
//设备状态返回:设备端-》服务端
MESSAGE sip:34020000002000000001@3402000000 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.64:5060;rport;branch=z9hG4bK1675009157
From: <sip:34020000001320000002@3402000000>;tag=2077654677
To: <sip:34020000002000000001@3402000000>
Call-ID: 1002341894
CSeq: 20 MESSAGE
Content-Type: Application/MANSCDP+xml
Max-Forwards: 70
User-Agent: IP Camera
Content-Length: 427
<?xml version="1.0" encoding="GB2312"?>
<Response>
<CmdType>DeviceStatus</CmdType>
<SN>10018</SN>
<DeviceID>34020000001320000002</DeviceID>
<Result>OK</Result>
<Online>ONLINE</Online>
<Status>OK</Status>
<DeviceTime>2025-04-22T11:14:23</DeviceTime>
<Alarmstatus Num="1">
<Item>
<DeviceID>34020000001340000001</DeviceID>
<DutyStatus>ONDUTY</DutyStatus>
</Item>
</Alarmstatus>
<Encode>ON</Encode>
<Record>ON</Record>
</Response>
//获取设备参数:服务端-》设备端
MESSAGE sip:34020000001320000002@192.168.0.64:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.110:15060;branch=z3hG9bK8fdd12678d10455faf6141abf099c783
From: <sip:34020000002000000001@192.168.0.110:15060>;tag=1020
To: <sip:34020000001320000002@192.168.0.64:5060>
Call-ID: 207ffb519158414a926275c01512ee0f
CSeq: 21 MESSAGE
User-Agent: wx_feiyangqingyun
Max-Forwards: 70
Content-Length: 197
Content-Type: application/MANSCDP+xml
Contact: <sip:34020000002000000001@192.168.0.110:15060>
<?xml version="1.0" encoding="GB2312"?>
<Query>
<CmdType>ConfigDownload</CmdType>
<SN>10020</SN>
<DeviceID>34020000001320000002</DeviceID>
<ConfigType>BasicParam</ConfigType>
</Query>
//设备参数返回:设备端-》服务端
MESSAGE sip:34020000002000000001@3402000000 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.64:5060;rport;branch=z9hG4bK626480488
From: <sip:34020000001320000002@3402000000>;tag=1196765638
To: <sip:34020000002000000001@3402000000>
Call-ID: 1421185166
CSeq: 20 MESSAGE
Content-Type: Application/MANSCDP+xml
Max-Forwards: 70
User-Agent: IP Camera
Content-Length: 608
<?xml version="1.0" encoding="GB2312"?>
<Response>
<CmdType>ConfigDownload</CmdType>
<SN>10020</SN>
<DeviceID>34020000001320000002</DeviceID>
<Result>OK</Result>
<BasicParam>
<Name>IP CAMERA</Name>
<DeviceID>34020000001320000002</DeviceID>
<SIPServerID>34020000002000000001</SIPServerID>
<SIPServerIP>192.168.0.110</SIPServerIP>
<SIPServerPort>15060</SIPServerPort>
<DomainName>3402000000</DomainName>
<Expiration>3600</Expiration>
<Password>12345678</Password>
<HeartBeatInterval>30</HeartBeatInterval>
<HeartBeatCount>3</HeartBeatCount>
<PositionCapability>0</PositionCapability>
</BasicParam>
</Response>
//获取通道信息:服务端-》设备端
MESSAGE sip:34020000001320000002@192.168.0.64:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.110:15060;branch=z3hG9bKca6cdd79b54b4a898a08a027df9ee74f
From: <sip:34020000002000000001@192.168.0.110:15060>;tag=1021
To: <sip:34020000001320000002@192.168.0.64:5060>
Call-ID: 73a10bfd47944564aebc9f383d8d5dbc
CSeq: 22 MESSAGE
User-Agent: wx_feiyangqingyun
Max-Forwards: 70
Content-Length: 151
Content-Type: application/MANSCDP+xml
Contact: <sip:34020000002000000001@192.168.0.110:15060>
<?xml version="1.0" encoding="GB2312"?>
<Query>
<CmdType>Catalog</CmdType>
<SN>10021</SN>
<DeviceID>34020000001320000002</DeviceID>
</Query>
//通道信息返回:设备端-》服务端
MESSAGE sip:34020000002000000001@3402000000 SIP/2.0
Via: SIP/2.0/UDP 192.168.0.64:5060;rport;branch=z9hG4bK759035473
From: <sip:34020000001320000002@3402000000>;tag=417631013
To: <sip:34020000002000000001@3402000000>
Call-ID: 438658409
CSeq: 20 MESSAGE
Content-Type: Application/MANSCDP+xml
Max-Forwards: 70
User-Agent: IP Camera
Content-Length: 963
<?xml version="1.0" encoding="GB2312"?>
<Response>
<CmdType>Catalog</CmdType>
<SN>10021</SN>
<DeviceID>34020000001320000002</DeviceID>
<SumNum>2</SumNum>
<DeviceList Num="2">
<Item>
<DeviceID>34020000001310000001</DeviceID>
<Name>hikangname</Name>
<Manufacturer>Hikvision</Manufacturer>
<Model>IP Camera</Model>
<Owner>Owner</Owner>
<CivilCode>3402000000</CivilCode>
<Address>Address</Address>
<Parental>0</Parental>
<ParentID>34020000002000000001</ParentID>
<SafetyWay>0</SafetyWay>
<RegisterWay>1</RegisterWay>
<Secrecy>0</Secrecy>
<Status>ON</Status>
</Item>
<Item>
<DeviceID>34020000001340000001</DeviceID>
<Name></Name>
<Manufacturer>Hikvision</Manufacturer>
<Model>AlarmIn</Model>
<Owner>Owner</Owner>
<CivilCode>3402000000</CivilCode>
<Address>Address</Address>
<Parental>0</Parental>
<ParentID>34020000001320000002</ParentID>
<SafetyWay>0</SafetyWay>
<RegisterWay>1</RegisterWay>
<Secrecy>0</Secrecy>
<Status>ON</Status>
</Item>
</DeviceList>
</Response>
void GB28181Parse::parseConfigDownload(GB28181Info info, QList<GB28181Device> &devices)
{
//找到对应的设备
GB28181Device device = GB28181Helper::getDevice(info.deviceId, devices);
if (device.deviceId.isEmpty()) {
return;
}
QDomNodeList nodes = info.bodyNodes;
for (int i = 0; i < nodes.count(); ++i) {
QDomNode node = nodes.at(i);
if (!node.isElement()) {
continue;
}
QDomElement element = node.toElement();
QString name = element.tagName();
QString text = element.text();
if (name == "Expiration") {
device.expiration = text.toInt();
} else if (name == "HeartBeatInterval") {
device.heartBeatInterval = text.toInt();
} else if (name == "HeartBeatCount") {
device.heartBeatCount = text.toInt();
}
}
//更新设备信息
devices[devices.indexOf(device)] = device;
}
//具体格式规范在gb28181-2016文档的第68页
GB28181Event GB28181Parse::parseAlarmInfo(GB28181Info info)
{
GB28181Event event;
event.deviceId = info.deviceId;
event.channelId = info.bodyAttr["DeviceID"];
event.alarmPriority = info.bodyAttr["AlarmPriority"].toInt();
event.alarmMethod = info.bodyAttr["AlarmMethod"].toInt();
event.alarmInfo = info.bodyAttr["AlarmInfo"].toInt();
event.alarmType = info.bodyAttr["Info"].toInt();
event.alarmTime = info.bodyAttr["AlarmTime"];
event.alarmDescription = info.bodyAttr["AlarmDescription"];
return event;
}
GB28181Status GB28181Parse::parseMediaStatus(GB28181Info info, const QList<GB28181Device> &devices)
{
//这里需要根据主机信息去查询设备/info.deviceId很可能是通道编号而不是设备编号
GB28181Device device = GB28181Helper::getDevice(info.deviceIp, info.devicePort, devices);
GB28181Status status;
status.deviceId = device.deviceId;
status.channelId = info.bodyAttr["DeviceID"];
//121-播放完成/122-播放中断/213-设备报警
status.notifyType = info.bodyAttr["NotifyType"].toInt();
//有些设备传过来的xml数据中的是设备编号而不是通道编号
if (status.channelId == status.deviceId) {
status.channelId = info.deviceId;
}
//每个通道可能有多个流/需要找到具体哪个流
QStringList ssrcs, froms, tos, callIds;
GB28181Helper::getChannel(device, status.channelId, "", ssrcs, froms, tos, callIds, false);
QString callId = info.attr["Call-ID"];
int index = callIds.indexOf(callId);
if (index >= 0) {
status.ssrc = ssrcs.at(index);
}
return status;
}
int GB28181Parse::parseDeviceList(GB28181Info info, const QString &deviceId, QList<GB28181Channel> &channels)
{
QDomNodeList nodes = info.bodyNodes;
for (int i = 0; i < nodes.count(); ++i) {
QDomNode node = nodes.at(i);
if (!node.isElement()) {
continue;
}
GB28181Channel channel;
channel.parentId = deviceId;
QDomNodeList list = node.childNodes();
for (int j = 0; j < list.count(); ++j) {
QDomElement element = list.at(j).toElement();
QString name = element.tagName();
QString text = element.text();
channel.attr.insert(name, text);
if (name == "DeviceID") {
channel.channelId = text;
} else if (name == "Name") {
channel.channelName = text;
} else if (name == "ParentID") {
//部分设备传回来的这里的编号其实并不是父编号
//channel.parentId = text;
} else if (name == "Status") {
}
}
//补全默认名称
if (channel.channelName.isEmpty()) {
channel.channelName = "xxx";
}
channels << channel;
}
return info.bodyAttr["SumNum"].toInt();
}