本文内容纲要:
-准备工作
-开发环境信息
-改写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