国标GB28181协议客户端EasyGBS国标视频平台级联EasyNVR:EasyNVR到EasyGBS上是如何注册及注销的?
时间:2022-07-23
本文章向大家介绍国标GB28181协议客户端EasyGBS国标视频平台级联EasyNVR:EasyNVR到EasyGBS上是如何注册及注销的?,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
我们知道TSINGSEE青犀视频EasyGBS国标平台可以作为上级平台或下级平台,可以与支持国标协议的平台进行级联,上文提到与宇视等平台进行级联(EasyGBS如何实现视频流的向上级联)就是一个很好的案例。其实除了与市面上支持的国标平台做级联,Easy系列产品之间也可以与EasyGBS做级联。最近,有客户需要同时使用EasyGBS和EasyNVR两个平台融合使用,此时我们就可以将EasyNVR接入到EasyGBS中,使其方便管理。
由于文章内容比较多,我们分两块来讲一下这个配置过程。本文详细描述了EasyNVR平台到国标EasyGBS上的注册和注销。
EasyNVR视频监控直播解决方案
EasyGBS国标视频云直播解决方案
EasyGBS采用gb28181协议接入摄像头,我们将EasyNVR当作边缘设备,通过gb28181协议和EasyGBS平台进行对接。
EasyGBS有级联注册到其他EasyGBS的功能,EasyNVR接入到EasyGBS中其实就是将EasyNVR注册到EasyGBS中,我们可以仿照现有的EasyGBS级联注册功能仿写。从EasyGBS中找到级联注册功能那块代码,仿写EasyNVR的代码。此处是EasyNVR与EasyGBS交互的客户端:
func NewClient(cascade Cascade) *Client {
client := &Client{
Stoped: false,
Cascade: cascade,
AckTimeout: cascade.AckTimeout,
LocalHost: cascade.LocalHost,
LocalPort: cascade.LocalPort,
LocalWanIP: "",
LocalSerial: cascade.LocalSerial,
handleMap: make(map[string][]HandleFunc),
dispatcher: events.NewDispatcher(),
KeepAliveQuit: make(chan bool, 0),
RegisterQuit: make(chan bool, 0),
DevCache: cache.New(time.Duration(cascade.KeepaliveTimeout)*time.Second, 10*time.Second),
}
return client
}
以上我们已经完成了客户端的配置,接下来就可以启动客户端正式与EasyGBS交互了。
func (c *Client) Run() {
if c.LocalPort == 0 {
log.Println("没有可用的UDP级联端口")
return
}
lUdpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", c.LocalPort))
if err != nil {
return
}
rUdpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", c.Cascade.Host, c.Cascade.Port))
if err != nil {
return
}
c.udpConn, err = net.DialUDP("udp", lUdpAddr, rUdpAddr)
if err != nil {
log.Printf("uac start error:%v", err)
return
}
if e := c.udpConn.SetReadBuffer(UDP_BUF_SIZE); e != nil {
log.Printf("sip udp set connection read buffer[%d] error, %v", UDP_BUF_SIZE, e)
}
if e := c.udpConn.SetWriteBuffer(UDP_BUF_SIZE); e != nil {
log.Printf("sip udp set connection write buffer[%d] error, %v", UDP_BUF_SIZE, e)
}
defer c.udpConn.Close()
c.Transport = c.NewUDPTransport(rUdpAddr, c.udpConn)
go c.Register(false)
log.Printf("uac start ok:%s", c.udpConn.LocalAddr().String())
c.Stoped = false
c.Handle("MESSAGE", HandleMessage)
c.Handle("INVITE", HandleInvite)
c.Handle("BYE", HandleBye)
c.Handle("INFO", HandleInfo)
for !c.Stoped {
bufUDP := make([]byte, UDP_BUF_SIZE)
n, _, err := c.udpConn.ReadFromUDP(bufUDP)
if err != nil {
log.Printf("udp read error, %v", err)
continue
}
sipBuf := bufUDP[:n]
sipRaw := string(sipBuf)
sipMsg := siprocket.Parse(sipBuf)
statusCode := string(sipMsg.Req.StatusCode)
contentLen, _ := strconv.Atoi(string(sipMsg.ContLen.Value))
header := sipRaw[:len(sipRaw)-contentLen]
body := sipRaw[len(sipRaw)-contentLen:]
Logf("级联消息:[%s]<<<<<<[%s]<<<<<<rn%v", c.udpConn.LocalAddr().String(), c.udpConn.RemoteAddr().String(), sipRaw)
if statusCode == "" { // request
req, err := UnmarshalRequest(header, body)
if err != nil {
log.Printf("unmarshal request failed, %v", err)
continue
}
req.FixVia(c.Transport)
c.HandleRequest(req, &sipMsg)
} else { // response
res, err := UnmarshalResponse(header, body)
if err != nil {
log.Printf("unmarshal response failed, %v", err)
continue
}
callid := res.HeaderMap["Call-ID"]
cseq := res.HeaderMap["CSeq"]
c.dispatcher.Dispatch(fmt.Sprintf("%s:%s", callid, cseq), res)
}
}
}
上面两段代码都是实现EasyNVR注册到EasyGBS中,然后就需要将其整合到一起。
func Start() {
cascade := GetGbsConfig()
if cascade.Enable != 0 {
client = NewClient(cascade)
go client.Run()
}
return
}
func Stop() {
if client != nil {
if !client.Stoped {
client.Stoped = true
client.RegisterQuit <- true
client.KeepAliveQuit <- true
}
client = nil
log.Println("级联stop")
}
}
实现后效果如下:
这个设备就是虚拟构造的EasyNVR设备。我们接入的是16通道的EasyNVR,所以此处应该显示16个通道,然而现在注册上来并没有显示通道,所以我们还需要继续配置EasyGBS级联调阅EasyNVR的通道列表:EasyGBS如何实现调阅EasyNVR的视频通道。
- hdu----(1671)Phone List(Trie带标签)
- PHP-数组
- hdu---1506(Largest Rectangle in a Histogram/dp最大子矩阵)
- 日志分析实战之清洗日志小实例6:获取uri点击量排序并得到最高的url
- golang使用sort接口实现排序示例
- hdu----(5056)Boring count(贪心)
- hdu----(5055)Bob and math problem(贪心)
- hadoop3.0 Yarn支持网络资源:network原理设计文档说明【中文】
- PHP-超级全局变量
- 日志分析实战之清洗日志小实例5:实现获取不能访问url
- CentOS安装Redis、PHPredis扩展
- 日志分析实战之清洗日志小实例4:统计网站相关信息
- PHP-数组排序
- hdu---(3555)Bomb(数位dp(入门))
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- kubernetes(十三) k8s 业务上线流程(手动版)
- java+appium+安卓模拟器实现app自动化Demo
- webdriver使用已打开过的chrome
- Shortcodes
- Unexpected EOF 远程主机强迫关闭了一个现有的连接 如何处理
- npm 使用问题
- 接口自动化测试框架-AIM
- hexo 图片显示问题及使用typora设置图片路径
- 接口自动化项目实践
- 结对测试算法性能优化(代码层面)
- 结对测试算法性能优化(用例设计层面)
- 使用travisCI自动部署hexo博客并使用国内外不同dns
- 寻找cookie之旅
- send_keys报错element not interactable
- 博客园上传markdown文件