海康威视-字符叠加

前言

最近需要做一个视频里面的字符实时叠加,记录一下探索的过程。
机器型号,海康威视的NVR和摄像头应该都没问题,因为是向NVR发包,跟摄像头没什么关系。
我的NVR型号是DS-7104N-SN/P(NVR应该都行的。sdk邮箱给我的时候我也没发型号)

直接看解决的方法:HTTP的格式和C#代码—->直接跳转


探索前过程

还是说一下功能需求吧,需要在监控的屏幕上叠加环境监测仪的数据。接受数据啥的这里就不说了。
按照协议进行转化,这里只说进行字符叠加的东西,emm就这样…

底层|应用层?

在探索前期很自然的有两种选择的方式

  • 第一种,在底层进行叠加。因为监控视频的设备已经做好了,能够在视频上实时显示时间,那么讲道理也是可以自定义显示字符的。
  • 第二种,在应用层进行叠加。因为最后人看监控是在软件或者网页上进行查看。可以在应用层上进行叠加。

两种方法当然都可以,但是我想了下还是觉得在底层比较好,而且NVR会根据画面位置的亮暗来改变字的颜色(白色或黑色)
找了一下海康威视的sdk的咨询邮箱,然后问了下,他们还是给了比较好的回答,虽然没有demo,但是给出了基本的答案。

您好!
没有封装好的接口,可以直接使用ISAPI协议实现,附件8.4.21~8.4.25章节就是OSD字符叠加配置的协议内容。
该协议是基于标准HTTP协议和XML协议的,可以自己创建socket连接发送命令,也可以直接通过WEB控件开发包的I_SendHTTPRequest这个接口透传相关命令。

资料-图1
资料-图2

资料总结

上面给出了这个信息,我掐指一算大概能知道一点结果了。(下面的东西别问我怎么知道的,我觉得常识
NVR就是一个正在运行的server,字符显示和一堆配置文件都在这个server的/ISAPI/System/Video/下面。
我们的字符位置当然就是/ISAPI/System/Video/inputs/channels/ID/overlays/text下面咯,但是要注意ID改成对应的摄像头ID,因为监控可以同时显示多个摄像头嘛。然后实现的方法就是使用HTTP协议发包更改配置文件就能更改显示了对吧。


Postman探索

如何进行HTTP的发包。直接通过socket模拟(底层确实是这么实现的),在群里问了一下,知道了有这么一个chrome插件–Postman,确实很好用啊。下载啥的就不用说了吧。没错,就是下图这货
chrome商店Postman

发包

接下来就是发包了,发送GET请求很舒服啊。找到了自己想要的答案。如下图,其实到这里理论上就已经完成了。(记得写Authorization,NVR的账户密码,坑了几个小时)
Get发包
点send之后下面框就有内容了,然后使用PUT,发送我们想要的覆盖的内容也就行了,POST方法没有成功。
Put发包
发完之后看看监控屏幕,就已经达到了想要的效果。如下图
监控显示
然后经过个人尝试,录屏还是会保存到视频中,因为是从底层的修改。


HTTP格式和C#代码

那么通过Postman的尝试,知道了格式,那么就可以写代码了。(什么?别告诉我你还不知道格式!那么给你一个工具,用来监听socket内容的工具,自己看socket里面发的什么内容,链接跳转工具链接)

HTTP格式

下面给出HTTP的格式,Authorization当然需要时你自己的。
(注意PUT /ISAPI/System/Video/inputs/channels/ID/overlays/text中ID的替换)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PUT /ISAPI/System/Video/inputs/channels/1/overlays/text HTTP/1.1
Host: 192.168.1.100
Connection: keep-alive
Content-Length: 418
Authorization: Basic YWRtaW46Y3VnMTIzNDU=
Cache-Control: no-cache
Content-Type: text/plain;charset=UTF-8

<TextOverlayList>
<TextOverlay>
<id>1</id>
<enabled>true</enabled>
<positionX>200.000000</positionX>
<positionY>480.000000</positionY>
<displayText>xuan</displayText>
</TextOverlay>
</TextOverlayList>

C#代码

因为做的东西使用的是C#平台啦,仅给出一次发包的代码,多次发包写个循环。写好一个xml的模板,C:\\Test.xml,路径下,文件内容如下

1
2
3
4
5
6
7
8
9
<TextOverlayList>
<TextOverlay>
<id>1</id>
<enabled>true</enabled>
<positionX>50.000000</positionX>
<positionY>100.000000</positionY>
<displayText>温度</displayText>
</TextOverlay>
</TextOverlayList>

然后在C#中读取文件,进行显示文字的修改,然后发包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//------------mytest------------
//读取xml部分,注意xml的外层标签不能带属性,否则SelectSingleNode找不到对应的对象
string xmlPath = "C:\\Test.xml";
XmlDocument xml = new XmlDocument();
xml.Load(xmlPath);
//Console.WriteLine(xml.InnerXml); //xml文档内容
//XmlNode posX = xml.SelectSingleNode("/TextOverlayList/TextOverlay/positionX");
//XmlNode posY = xml.SelectSingleNode("/TextOverlayList/TextOverlay/positionY");
//Console.WriteLine("X:" + posX.InnerText+" Y:"+posY.InnerText); //标签位置
XmlNode text = xml.SelectSingleNode("/TextOverlayList/TextOverlay/displayText");
text.InnerText = "温度";
xml.Save(xmlPath); //保存
Console.WriteLine(text.InnerText);


//发送数据给NVR部分
//string URI = "http://127.0.0.1/ISAPI/System/Video/inputs/channels/1/overlays/text";
string URI = "http://192.168.1.100/ISAPI/System/Video/inputs/channels/1/overlays/text";
Stream outstream = null;
Stream instream = null;
StreamReader sr = null;

//新版定义HTTP的请求,不能用new,https://msdn.microsoft.com/zh-cn/library/system.net.httpwebresponse(v=vs.110).aspx
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(URI);
// 要注意的这是这个编码方式,还有内容的Xml内容的编码方式
Encoding encoding = Encoding.GetEncoding("UTF-8");
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml.InnerXml);
req.Method = "PUT";
req.ContentType = "text/plain;charset=UTF-8";
//添加用户名密码完成Authorization认证
string username = "admin";
string password = "cug12345";
string userPasswd = username + ":" + password;
CredentialCache mycache = new CredentialCache();
mycache.Add(new Uri(URI), "Basic", new NetworkCredential(username, password));
req.Credentials = mycache;
req.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(new ASCIIEncoding().GetBytes(userPasswd)));
//发送内容
outstream = req.GetRequestStream();
outstream.Write(data, 0, data.Length);
outstream.Flush();
outstream.Close();

HttpWebResponse res = (HttpWebResponse)req.GetResponse();
//接收NVR返回数据信息
res = req.GetResponse() as HttpWebResponse;
//直到req.GetResponse()程序才开始向目标网页发送Post请求
instream = res.GetResponseStream();
sr = new StreamReader(instream, encoding);
//返回结果网页代码
string content = sr.ReadToEnd();
Console.Write(content);
Console.Read();

运行结果如下:
运行结果
然后在画面上面就可以看到温度两个字了,写代码的时候记得看IP和你的IP是否对应。
测试结果


参考资料

工具

工具和文档
注:文档是海康威视sdk邮箱发给我的。

如果对您有帮助,请我喝杯咖啡?