使用golang对海康sdk进行业务开发
本文内容纲要:
-准备工作
-开发环境信息
-改写HCNetSDK.h头文件
-开发过程
-基本数据类型转换
-业务开发
-参考
目录
-
准备工作
- 开发环境信息
- 改写HCNetSDK.h头文件
-
开发过程
-
基本数据类型转换
-
业务开发
- HCNetSDK.go
- Makefile
-
-
参考
项目最近需要改造升级:操作海康摄像头(包括登录,拍照,录像)等基本功能。经过一段时间研究后,发现使用golang的cgo来进行开发,甚是方便,不用考虑生成多余的golang代码,直接调用海康sdk中的函数代码。
准备工作
开发环境信息
在Windows10
下进行开发,使用海康sdk是CH-HCNetSDKV6.0.2.35_build20190411_Win64
版本。go版本号go1.12.7
。
改写HCNetSDK.h头文件
海康威视提供的头文件是不能被cgo所识别的,而cgo是不能使用C++
相关的东西的,比如标准库或者C++的面向对象特性,导致其会疯狂的报语法错误.
查询资料后得知,该头文件中有以下情况,就不能通过编译:
- 注释里面套注释,例如这样的
//这里是注释1/*这里是注释2*/
#definexxx
时,若后面函数被xxx
修饰,当xxx
无对应的值而仅仅是被定义的时候;- c++语法,例如联合嵌套在C++中是不支持的,c++的bool类型等
在开发的时候,发现原HCNetSDK.h
文件里面有五万多行,如果全部的改造,那么会花费大量的时间。在c++开发的同事的建议下:只取出与开发功能相关的代码进行改造(改造为cgo可以识别的代码)。
改造规则如下:
- 去掉所有注释
- 去掉函数前面的
NET_DVR_API
和__std
- 去掉CALLBACK
- 为没有tag的结构体加上tag前缀
- 删除无实现的函数
开发过程
基本数据类型转换
由于在开发过程中涉及到基本的golang和c的数据类型转换,查阅资料后,转换对应关系如下:
C语言类型 | CGO类型 | Go语言类型 |
---|---|---|
char | C.char | byte |
singedchar | C.schar | int8 |
unsignedchar | C.uchar | uint8 |
short | C.short | int16 |
unsignedshort | C.ushort | uint16 |
int | C.int | int32 |
unsignedint | C.uint | uint32 |
long | C.long | int32 |
unsignedlong | C.ulong | uint32 |
longlongint | C.longlong | int64 |
unsignedlonglongint | C.ulonglong | uint64 |
float | C.float | float32 |
double | C.double | float64 |
size_t | C.size_t | uint |
注意C中的整形比如int在标准中是没有定义具体字长的,但一般默认认为是4字节,对应CGO类型中C.int则明确定义了字长是4,但golang中的int字长则是8,因此对应的golang类型不是int而是int32。为了避免误用,C代码最好使用C99标准的数值类型,对应的转换关系如下:
C语言类型 | CGO类型 | Go语言类型 |
---|---|---|
int8_t | C.int8_t | int8 |
uint8_t | C.uint8_t | uint8 |
int16_t | C.int16_t | int16 |
uint16_t | C.uint16_t | uint16 |
int32_t | C.int32_t | int32 |
uint32_t | C.uint32_t | uint32 |
int64_t | C.int64_t | int64 |
uint64_t | C.uint64_t | uint64 |
业务开发
HCNetSDK.go
packagemain
/*
#cgoCFLAGS:-I.
#cgoLDFLAGS:-L.-lHCCore
#cgoLDFLAGS:-L.-lHCNetSDK
#include"HCNetSDK.h"
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
*/
import"C"
import(
"errors"
"fmt"
"time"
"unsafe"
)
//是否有错误
funcisErr(operstring)error{
errno:=int64(C.NET_DVR_GetLastError())
iferrno>0{
reMsg:=fmt.Sprintf("%s摄像头失败,失败代码号:%d",oper,errno)
returnerrors.New(reMsg)
}
returnnil
}
//初始化海康摄像头
funcInit()(errerror){
C.NET_DVR_Init()
iferr=isErr("Init");err!=nil{
return
}
//设置连接时间
C.NET_DVR_SetConnectTime(C.DWORD(2000),C.DWORD(1))
iferr=isErr("SetConnectTime");err!=nil{
return
}
returnnil
}
//登录摄像头
funcLogin()(int64,error){
vardeviceinfoV30C.NET_DVR_DEVICEINFO_V30
c_ip:=C.CString("192.168.1.64")
deferC.free(unsafe.Pointer(c_ip))
c_login:=C.CString("admin")
deferC.free(unsafe.Pointer(c_login))
c_password:=C.CString("admin")
deferC.free(unsafe.Pointer(c_password))
msgId:=C.NET_DVR_Login_V30(c_ip,C.WORD(8080),c_login,c_password,
(*C.NET_DVR_DEVICEINFO_V30)(unsafe.Pointer(&deviceinfoV30)),
)
ifint64(msgId)<0{
iferr:=isErr("Login");err!=nil{
return-1,err
}
return-1,errors.New("登录摄像头失败")
}
returnint64(msgId),nil
}
//退出摄像头登录
//uid:摄像头登录成功的id
funcLogout(uidint64)error{
C.NET_DVR_Logout_V30(C.LONG(uid))
iferr:=isErr("Logout");err!=nil{
returnerr
}
returnnil
}
//播放视频
//uid:摄像头登录成功的id
//返回播放视频标识pid
funcPlay(uidint64)(int64,error){
varpDetectInfoC.NET_DVR_CLIENTINFO
pDetectInfo.lChannel=C.LONG(1)
pid:=C.NET_DVR_RealPlay_V30(C.LONG(uid),(*C.NET_DVR_CLIENTINFO)(unsafe.Pointer(&pDetectInfo)),nil,nil,C.BOOL(1))
ifint64(pid)<0{
iferr:=isErr("Play");err!=nil{
return-1,err
}
return-1,errors.New("播放失败")
}
returnint64(pid),nil
}
//抓拍
funcCapture(uidint64)(string,error){
picPath:="D:\\"+time.Now().Format("20060102150405")+".jpeg"
varjpegparaC.NET_DVR_JPEGPARA
varlChanneluint32=1
c_path:=C.CString(picPath)
deferC.free(unsafe.Pointer(c_path))
msgId:=C.NET_DVR_CaptureJPEGPicture(C.LONG(uid),C.LONG(lChannel),
(*C.NET_DVR_JPEGPARA)(unsafe.Pointer(&jpegpara)),
c_path,
)
ifint64(msgId)<0{
iferr:=isErr("Capture");err!=nil{
return"",err
}
return"",errors.New("抓拍失败")
}
returnpicPath,nil
}
//停止相机
//pid播放标识符
funcPtzStop(pidint64)error{
msgId:=C.NET_DVR_StopRealPlay(C.LONG(pid))
ifint64(msgId)<0{
iferr:=isErr("PtzStop");err!=nil{
returnerr
}
returnerrors.New("停止相机失败")
}
returnnil
}
funcmain(){
varerrerror
err=Init()
deferClose()
iferr!=nil{
log.Fatal(err.Error())
}
varuidint64
ifuid,err=Login();err!=nil{
log.Fatal(err.Error())
}
varpicPathstring
ifpicPath,err=Capture(uid);err!=nil{
log.Fatal(err.Error())
}
log.Println("图片路径:",picPath)
varpidint64
ifpid,err=Play(uid);err!=nil{
log.Fatal(err.Error())
}
iferr=PtzStop(pid);err!=nil{
log.Fatal(err.Error())
}
iferr=Logout(uid);err!=nil{
log.Fatal(err.Error())
}
}
Makefile
exportCGO_ENABLED=1
exportWDIR=${PWD}
all:windows
windows:
CGO_LDFLAGS_ALLOW=".*"CGO_CFLAGS="-I${WDIR}/include"CGO_LDFLAGS="-L${WDIR}/lib/Windows-Wl,--enable-stdcall-fixup,-rpath=${WDIR}/lib/Windows-lHCNetSDK"GOOS=windowsCC=x86_64-w64-mingw32-gccCXX=x86_64-w64-mingw32-g++gobuild-ldflags"-s-w"-obuild/Windows/hk.exesrc/HCNetSDK.go
cplib/Windows/HCNetSDK.dllbuild/Windows/
cplib/Windows/HCCore.dllbuild/Windows/
cp-rlib/Windows/HCNetSDKCom/build/Windows/
clean:
rm-rbuild/
通过make命令该文件即可。(注意海康开发文档中的说明)
参考
SWIG编译海康威视SDK使用golang
golangcgo使用总结
hikavision-recover
本文内容总结:准备工作,开发环境信息,改写HCNetSDK.h头文件,开发过程,基本数据类型转换,业务开发,参考,
原文链接:https://www.cnblogs.com/dust90/p/11447622.html