使用golang对海康sdk进行业务开发
项目最近需要改造升级:操作海康摄像头(包括登录,拍照,录像)等基本功能。经过一段时间研究后,发现使用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*/
#define xxx
时,若后面函数被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 |
singed char | C.schar | int8 |
unsigned char | C.uchar | uint8 |
short | C.short | int16 |
unsigned short | C.ushort | uint16 |
int | C.int | int32 |
unsigned int | C.uint | uint32 |
long | C.long | int32 |
unsigned long | C.ulong | uint32 |
long long int | C.longlong | int64 |
unsigned long long int | 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
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命令该文件即可。(注意海康开发文档中的说明)
参考
使用golang对海康sdk进行业务开发的更多相关文章
- golang调用海康sdk
git地址:https://gitee.com/mimo431/hcnet-sdk_golang 网络不太流畅,先传gitee上 参考链接: https://www.cnblogs.com/dust9 ...
- 海康SDK编程指南(C#二次开发版本)
海康SDK编程指南 目前使用的海康SDK包括IPC_SDK(硬件设备),Plat_SDK(平台),其中两套SDK都需单独调用海康播放库PlayCtrl.dll来解码视频流,返回视频信息和角度信息.本文 ...
- 海康SDK编程指南
转至心澄欲遣 目前使用的海康SDK包括IPC_SDK(硬件设备),Plat_SDK(平台),其中两套SDK都需单独调用海康播放库PlayCtrl.dll来解码视频流,返回视频信息和角度信息.本文仅对视 ...
- 海康SDK JAVA版本调用步骤及问题介绍
一.前言 本文为海康SDK JAVA版本Demo的介绍,采用Eclipse运行,以及一些问题记录. 海康SDK版本:SDK_Win32 Eclipse版本:Mars2.0 JDK版本:1.8.0_15 ...
- 封装海康SDK出现无法加载 DLL“..\bin\HCNetSDK.dll”: 找不到指定的模块
今天在封装海康设备的时候出现了这么一个问题,在初始化的时候提升无法加载 DLL“..\bin\HCNetSDK.dll”: 找不到指定的模块. 在网上查找了几个方法,并不是很靠谱,于是从源头找找,是什 ...
- C#制作ActiveX控件中调用海康SDK的问题
事情是这样的,有一台海康威视的摄像头,客户需要一个ActiveX控件嵌入到网页中,通过点击按钮开始录制和结束录制来进行视频的录制和保存,关于海康摄像头的二次开发在此就不多说了,可以参考SDK中的说明. ...
- 海康sdk
package com.hikvision.artemis.sdk.util; import java.util.Collections; import java.util.Iterator; imp ...
- 使用c#封装海康SDK出现无法加载 DLL“..\bin\HCNetSDK.dll”: 找不到指定的模块
最近在研究网络摄像头的二次开发,测试了一款海康威视的网络摄像头,程序调试的时候,出现如题的报错. 调试随机自带的demo时,程序运行正常,但当把该程序引入到我自己的程序中时,就开始报错.根据开发软件包 ...
- 海康相机SDK二次开发只有视频无声音问题
海康SDK相信做企业开发的的同仁,在项目中经常会用到,毕竟使用范围这么广. 本次就开发遇到的奇葩问题来说明一下我们的解决方案. 场景 虽然海康有4200客户端,但是对于高度定制化的项目,肯定不能再使用 ...
随机推荐
- EF Core懒人小技巧之拒绝DbSet
前言 最近在项目中使用EF Core的频率越来越高,当项目比较大的时候,疯狂往DbContext中加各种DbSet,你会不会特难受?如果你是一键生成的大佬,那么请忽略本文.本文旨在不写 DbSet,那 ...
- win10下nodejs的安装及配置
这里主要引用两篇文章,写的非常详细,也能解决你可能出现的问题 nodejs安装及配置 如何删除之前nodejs设置的 npm config set prefix .....
- oracle一条语句插入多个值的方法
今天在实践过程中遇到一个问题, 我想往数据库插入多条数据时,使用了如下语句: insert into 表1 (字段1,字段2) values (1,2),(2,3),(3,4); 这条语句在mysql ...
- 优雅的对象转换解决方案-MapStruct及其入门(一)
第一次看到 MapStruct 的时候, 我个人非常的开心. 因为其跟我内心里面的想法不谋而合. 1 MapStruct 是什么? 1.1 JavaBean 的困扰 对于代码中 JavaBean之间的 ...
- 9-1、大型项目的接口自动化实践记录----数据库结果、JSON对比
上一篇写了如何从DB获取预期.实际结果,这一篇分别对不同情况说下怎么进行对比. PS:这部分在JSON对比中也适用. 1.结果只有一张表,只有一条数据 数据格式:因为返回的是dicts_list的格式 ...
- npm包开发与发布
把通用的功能开发成npm包,便用使用和维护,更重要的是可以分享给广大的开发者,是不是很激动人心! 那么,步骤如下: 1.创建项目 创建项目目录,npm init ,根据需要输入配置信息(建完后也可以在 ...
- 第四章 文件的基本管理和XFS文件系统备份恢复 随堂笔记
第四章 文件的基本管理和XFS文件系统备份恢复 本节所讲内容: 4.1 Linux系统目录结构和相对/绝对路径. 4.2 创建/复制/删除文件,rm -rf / 意外事故 4.3 查看文件内容的命令 ...
- 使用富文本编辑器Kindeditor
今天在做需求的时候,遇到有一个字段,需要保存带有格式的内容,决定使用富文本框编辑器Kindeditor来实现,解决方法如下: 登录官网下载控件包: http://kindeditor.net/down ...
- The introduction of the book American daily English notes (enlarged edition)
After reading the book of American daily English notes written by Linkun Yang[1], I think I should a ...
- kafka消息的处理机制(五)
这一篇我们不在是探讨kafka的使用,前面几篇基本讲解了工作中的使用方式,基本api的使用还需要更深入的去钻研,多使用才会有提高.今天主要是探讨一下kafka的消息复制以及消息处理机制. 1. bro ...