准备工作

开发环境信息

Windows10CH-HCNetSDKV6.0.2.35_build20190411_Win64go1.12.7

改写HCNetSDK.h头文件

C++

查询资料后得知,该头文件中有以下情况,就不能通过编译:

//这里是注释1 /*这里是注释2*/#define xxxxxxxxx
HCNetSDK.h

改造规则如下:

NET_DVR_API__std

开发过程

基本数据类型转换

由于在开发过程中涉及到基本的golang和c的数据类型转换,查阅资料后,转换对应关系如下:

charC.charbyte
singed charC.scharint8
unsigned charC.ucharuint8
shortC.shortint16
unsigned shortC.ushortuint16
intC.intint32
unsigned intC.uintuint32
longC.longint32
unsigned longC.ulonguint32
long long intC.longlongint64
unsigned long long intC.ulonglonguint64
floatC.floatfloat32
doubleC.doublefloat64
size_tC.size_tuint

注意 C 中的整形比如 int 在标准中是没有定义具体字长的,但一般默认认为是 4 字节,对应 CGO 类型中 C.int 则明确定义了字长是 4 ,但 golang 中的 int 字长则是 8 ,因此对应的 golang 类型不是 int 而是 int32 。为了避免误用,C 代码最好使用 C99 标准的数值类型,对应的转换关系如下:

int8_tC.int8_tint8
uint8_tC.uint8_tuint8
int16_tC.int16_tint16
uint16_tC.uint16_tuint16
int32_tC.int32_tint32
uint32_tC.uint32_tuint32
int64_tC.int64_tint64
uint64_tC.uint64_tuint64

业务开发

HCNetSDK.go

package main

/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -L. -lHCCore
#cgo LDFLAGS: -L. -lHCNetSDK
#include "HCNetSDK.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> */
import "C"
import (
"errors"
"fmt"
"time"
"unsafe"
) // 是否有错误
func isErr(oper string) error {
errno := int64(C.NET_DVR_GetLastError())
if errno > 0 {
reMsg := fmt.Sprintf("%s摄像头失败,失败代码号:%d", oper, errno)
return errors.New(reMsg)
}
return nil
} // 初始化海康摄像头
func Init() (err error) {
C.NET_DVR_Init()
if err = isErr("Init"); err != nil {
return
}
// 设置连接时间
C.NET_DVR_SetConnectTime(C.DWORD(2000), C.DWORD(1))
if err = isErr("SetConnectTime"); err != nil {
return
}
return nil
} // 登录摄像头
func Login() (int64,error) {
var deviceinfoV30 C.NET_DVR_DEVICEINFO_V30
c_ip := C.CString("192.168.1.64")
defer C.free(unsafe.Pointer(c_ip)) c_login := C.CString("admin")
defer C.free(unsafe.Pointer(c_login)) c_password := C.CString("admin")
defer C.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)),
) if int64(msgId) < 0 {
if err := isErr("Login"); err != nil {
return -1,err
}
return -1,errors.New("登录摄像头失败")
}
return int64(msgId),nil
} // 退出摄像头登录
// uid:摄像头登录成功的id
func Logout(uid int64) error {
C.NET_DVR_Logout_V30(C.LONG(uid))
if err := isErr("Logout"); err != nil {
return err
}
return nil
} // 播放视频
// uid:摄像头登录成功的id
// 返回播放视频标识 pid
func Play(uid int64)(int64, error) {
var pDetectInfo C.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))
if int64(pid) < 0 {
if err := isErr("Play"); err != nil {
return -1,err
}
return -1,errors.New("播放失败")
} return int64(pid),nil
} // 抓拍
func Capture(uid int64) (string, error){
picPath := "D:\\" + time.Now().Format("20060102150405") + ".jpeg" var jpegpara C.NET_DVR_JPEGPARA
var lChannel uint32 = 1
c_path := C.CString(picPath)
defer C.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,
) if int64(msgId) < 0 {
if err := isErr("Capture"); err != nil {
return "",err
}
return "",errors.New("抓拍失败")
}
return picPath,nil
} // 停止相机
// pid 播放标识符
func PtzStop(pid int64) error {
msgId := C.NET_DVR_StopRealPlay(C.LONG(pid))
if int64(msgId) < 0 {
if err := isErr("PtzStop"); err != nil {
return err
}
return errors.New("停止相机失败")
}
return nil
} func main() {
var err error
err = Init()
defer Close()
if err != nil {
log.Fatal(err.Error())
} var uid int64
if uid,err = Login();err != nil {
log.Fatal(err.Error())
} var picPath string
if picPath,err = Capture(uid);err != nil {
log.Fatal(err.Error())
}
log.Println("图片路径:",picPath) var pid int64
if pid,err = Play(uid);err != nil {
log.Fatal(err.Error())
} if err = PtzStop(pid);err != nil {
log.Fatal(err.Error())
} if err = Logout(uid);err != nil {
log.Fatal(err.Error())
} }

Makefile

export CGO_ENABLED=1
export WDIR=${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=windows CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ go build -ldflags "-s -w" -o build/Windows/hk.exe src/HCNetSDK.go
cp lib/Windows/HCNetSDK.dll build/Windows/
cp lib/Windows/HCCore.dll build/Windows/
cp -r lib/Windows/HCNetSDKCom/ build/Windows/ clean:
rm -r build/

通过make命令该文件即可。(注意海康开发文档中的说明)


参考