Golang使用海康威视SDK
本文为原创文章,转载注明出处,欢迎关注网站https://hkvision.cn
接上一篇文章SWIG编译海康威视SDK-使用golang,这篇文章讲述的是如何使用编译好的文件,这涉及到SWIG和golang结合的问题
引入
编译好了之后.a
文件会出现在GOPATH
下,直接在import里面引入hikvision
就可以了,build的时候会自动找到对应的.a
文件
使用
下面从两个方面来介绍
- golang中已有的类型对应关系
- C里面
typedef
的值的对应关系,例如海康威视有BOOL
,DWORD
等
golang中已有的类型对应关系
这里说的已有的类型是指在C语言中已经有了,比如说int,char*等,具体的对应关系表网上有很多,SWIG在这里的策略和cgo
是一样的,这里给一个链接。这里就不多说了,在函数调用的时候可以直接把对应的go值传进去而不需要转换
C里面typedef
的值的对应关系
这里主要来说这个问题
由于海康威视的SDK大量使用了typedef
(应该是为了解决跨平台编译的问题),导致很多函数的返回值,参数值都不是正常的C类型,再加上大量的结构体,像我这样的菜鸟一开始根本无从下手,后来仔细看了SWIG生成的wrapper
文件和搜索引擎了一番,才弄明白SWIG的逻辑。
SWIG的实现其实就是调用了cgo,只是他给你封装了一层,你如果弄明白了cgo的逻辑,那SWIG的逻辑也就不难理解了。
Swigcptr uintptr unsafe.Pointer
这是核心,这三个东西构成了所有的C和go直接的类型交互。首先介绍一下C和go之间进行参数传递的流程
digraph G {
node [width=3]
a0 [label="go值"]
a1 [label="go野指针"]
a2 [label="内存地址的uint值"]
a3 [label="C指针"]
subgraph cluster_go2c {
style=filled;
a0 -> a1 [label=" unsafe.Pointer"];
a1 -> a2 [label=" uintptr"]
a2 -> a3 [label=" Swigcptrxxx"]
label = "Go to C";
}
b0 [label="C指针"]
b1 [label="内存地址的uint值"]
b2 [label="go野指针"]
b3 [label="go值"]
subgraph cluster_c2go {
style=filled;
b0 -> b1 [label=" Swigcptr"];
b1 -> b2 [label=" unsafe.Pointer"]
b2 -> b3 [label=" 指针转换"]
label = "C to Go";
}
}
这里的Swigcpterxxx
后面的xxx
对应的类型名称,Swig会自动帮我们生成这个函数。
整个的核心在于unsafe.Pointer
函数,这个函数接收一个指针类型的变量(也可以接收uintptr
类型的值),输出的是一个指针,但是对于go来说,这个指针已经变成了类似于野指针的存在,也就是说go不再承认这个指针是go体系里面的内容,gc也不会回收这块内存,需要我们自行管理。这个指针和C里面的void指针类似,代表这个指针可以指向任何一块内存。因此可以将这个指针对应的uint值(内存地址都可以用uint类型的变量来存储,这是一个特殊的类型,在GO和C中是uintptr
,本质和uint是一样的)传递到C中。C的值传递到GO也是一样的过程,都是通过void*
类型和unsafe.Pointer
类型的值可以互传来实现的。
多重指针
在海康威视的SDK中有一种类型本身就是指针,例如LPVOID
,那么使用SWIG编译后,对于GO程序而言,同样要用多重指针的思路来解决。
多重指针和单指针是一样的道理,在将GO值传递到C之前,我们首先要将这个值转化为多重指针,然后再进行上述步骤,这样海康威视SDK拿到的值才是正确的,不然就会报错。我也是实验了很多次才发现这个问题的,其实应该一开始就明白这个问题,还是基础不够扎实,没能一眼看明白。
下面是一个示例
|
|
这是截取的代码的一小部分,这里我是需要调用海康威视的NET_DVR_GetDVRConfig
函数,这个函数有一个参数即为LPVOID
类型,就是lpOutBuffer
这个变量,实际上这个变量的值类型是NET_DVR_DIGITAL_CHANNEL_STATE
,大家可以看到,这里首先在在创建一个NET_DVR_DIGITAL_CHANNEL_STATE
类型后,先用Swigcptr
函数拿到变量对应的地址,然后用两次unsafe.Pointer
函数,然后才转成LPVOID
,其余的变量我们只转换了一次。
函数调用
函数调用非常简单,当我们用unsafe.Pointer
组织好各个参数后,直接调用即可,注意返回值也需要进行转换,这里就是进行逆转换了,对于海康威视SDK,大家可以写一个公共函数来进行转换,这样方便调用。
- 原文作者:HaoKunT
- 原文链接:https://hkvision.cn/2019/09/13/golang%E4%BD%BF%E7%94%A8%E6%B5%B7%E5%BA%B7%E5%A8%81%E8%A7%86sdk/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。