用FPC翻译海康SDK头文件,供Delphi和Lazarus使用

引言

多年前用delphi写一些小程序时,曾用到海康威视的视频产品(当时是MPEG4视频采集卡),但是海康当时没有提供pascal版的SDK(说是因为版权问题被发过律师函,所以不提供,现在FPC没版权限制,可惜Delphi基本成了昔日黄花,使用的人越来越少,估计海康也没心思去弄这个版本,现在提供的除了传统的c/c++版,开始提供java、C#等版本的SDK)。所以我自己翻译头文件,结果弄了几天,成效不大(弄了几千行,整个头文件2W多行…),然后写了个小程序来自动转换,结果水平有限,只能针对性修改大部分的代码,然后又手动弄了两周,才算是修改通过编译,但是有些问题被忽略了,毕竟真正用到的数据结构和函数不多。最近手头要弄个热成像的接口,发觉早先的版本中没有,干脆把原单元对照新版的头文件修改一遍,顺便理一下FPC,毕竟不是专业的,好多知识不熟悉,现在花点时间学习一下。顺便把大华的SDK也弄了一遍,哈
以下就在进行转化过程中出现的问题进行记录一下,也希望能给别人一点参考。

一、预编译指令

讲真的,对编译环境这块我真不熟悉,一直都用IDE,很少去关心这块,原先对头文件中的预编译指令都是直接注释掉,按实际环境配置相应的类型申明。以我当前手头最新的SDK HCNetSDK.h(5.2版)为例,头文件中开头有如下内容:
#ifndef HC_NET_SDK_H
#define HC_NET_SDK_H

#ifndef WINDOWS
#if (defined(_WIN32) || defined(_WIN64))
#include <winsock2.h>
#include <windows.h>
#endif
#endif

#if defined(_WIN64)
#define OS_WINDOWS64 1
#endif

#if defined(LP64)
#define OS_POSIX64 1
#endif

#ifndef __PLAYRECT_defined
#define __PLAYRECT_defined
typedef struct __PLAYRECT
{
int x;
int y;
int uWidth;
int uHeight;
}PLAYRECT;
#endif

这个翻译成FPC倒是不难(不过我一直不知道什么会生效,所以我直接在满足条件的地方把定义取出来就不管了):

{KaTeX parse error: Double subscript at position 21: …f _HC_NET_SDK_H_̲} {define HC_NET_SDK_H}
{$endif}

//{KaTeX parse error: Expected group after '_' at position 16: ifndef _WINDOWS_̲} //我用的Lazarus…if (defined(_WIN32) or defined(_WIN64))}
// #include <winsock2.h>
// #include <windows.h>
// {KaTeX parse error: Expected 'EOF', got '}' at position 6: endif}̲ //{endif}

{KaTeX parse error: Expected 'EOF', got '}' at position 19: …defined(_WIN64)}̲ {define OS_WINDOWS64}
{$endif}

{KaTeX parse error: Expected group after '_' at position 12: if defined(_̲_LP64__)} {define OS_POSIX64}
{$endif}

{KaTeX parse error: Expected group after '_' at position 8: ifndef _̲_PLAYRECT_defin…define __PLAYRECT_defined}
type
__PLAYRECT = record
x:integer;
y:integer;
uWidth:integer;
uHeight:integer;
end;
PLAYRECT = __PLAYRECT;
{$endif}

这里最有用的就是这个操作系统的定义了,现在用的是win64,在后面的结构定义中确实会使用这个定义(这个函数内容有点多,删除了一点内容,也是后面进行联合体翻译的示例):
typedef struct tagNET_DVR_ALARMINFO_FIXED_HEADER
{
DWORD dwAlarmType;//报警类型
NET_DVR_TIME_EX struAlarmTime; //发生报警的时间
union
{
BYTE byUnionLen[116]; //分出去8个字节用于扩展时区
struct
{
DWORD dwAlarmChanNum;
DWORD dwPicLen;//Jpeg图片长度
BYTE byPicURL; //图片数据采用URL方式 0-二进制图片数据,1-图片数据走URL方式
BYTE byTarget; /0-不区分识别目标,1-识别目标为人,2-识别目标为车/
BYTE byRes1[2]; //保留
#if (defined(OS_WINDOWS64) || defined(OS_POSIX64))//win64及linux64下指针为8字节
char
pDataBuff; //报警图片或者图片URL
#else
char
pDataBuff; //报警图片或者图片URL
BYTE byRes3[4];
#endif**
}struAlarmChannel; // dwAlarmType为2,3,6,9,10、13或28时有效
struct
{
DWORD dwAlarmHardDiskNum;
}struAlarmHardDisk; // dwAlarmType为1,4,5时有效
}uStruAlarm;
DWORD* pRes; //用于兼容64位下结构体字节不对齐问题
BYTE byTimeDiffFlag; /*时差字段是否有效 0-时差无效, 1-时差有效 */
char cTimeDifferenceH;
char cTimeDifferenceM;
BYTE byRes; //保留
WORD wDevInfoIvmsChannel; //增加后端透传前端时的通道号
BYTE byRes2[2]; //保留
}NET_DVR_ALRAM_FIXED_HEADER, *LPNET_DVR_ALARM_FIXED_HEADER;

翻译到此处时,发觉else下的代码激活状态,与实际的不符,原来我都直接使用if后的代码,其它都注释掉,嘿嘿
后面看其它高手们提供linux下线程应用的办法,我考虑这个开关应该也是要手动打开的,所以在菜单:project - project options…,弹出对话框options for project…-compiler options - custom options点击【defines】直接添加 OS_WINDOWS64定义或是添加_WIN64(这个定义会定义OS_WINDOWS64):
{KaTeX parse error: Expected 'EOF', got '}' at position 19: …defined(_WIN64)}̲ {define OS_WINDOWS64}
{KaTeX parse error: Expected 'EOF', got '}' at position 6: endif}̲ 然后这个定义就激活了,同样…IFDEF UNIX}{KaTeX parse error: Expected 'EOF', got '}' at position 18: …DEF UseCThreads}̲ cthread…ENDIF}{$ENDIF}

二、数据基本类型定义

因为使用lazarus,许多类型定义比较齐全,不须要扩展定义DWORD、QWORD、ULONG、UINT64等类型,所以头文件中这些内容可以直接注释掉。

三、枚举与集合类型

之前用delphi,枚举元素不能赋序号值,只能按是默认的排序进行,FPC是支持的,可以和C一样对每一个元素赋值,不连续也可以,但是不能乱序和重复,SDK中给出的枚举定义中有,让人头大,只好分成几个定义了。
对于delphi,直接采用枚举定义,肯定与原头文件中的不一致,主要是其序号值不对,可以考虑的解决办法是,将原枚举对象中的元素提取出来定义为常量,然后再用集合定义一个包括原来范围的一个类型,这样在引用时不会出现问题。
头文件中有:
typedef enum tagCharEncodeType
{
ENUM_MEM_CHAR_ENCODE_ERR = -1, //Error
ENUM_MEM_CHAR_ENCODE_NO = 0, //Don’t know.
ENUM_MEM_CHAR_ENCODE_CN = 1, //EUC-CN, GB2312
ENUM_MEM_CHAR_ENCODE_GBK = 2, //GBK
ENUM_MEM_CHAR_ENCODE_BIG5 = 3, //BIG5
ENUM_MEM_CHAR_ENCODE_JP = 4, //JISX0208-1, EUC-JP
ENUM_MEM_CHAR_ENCODE_KR = 5, //EUC-KR
ENUM_MEM_CHAR_ENCODE_UTF8 = 6, //UTF-8
ENUM_MEM_CHAR_ENCODE_ISO8859_1 = 7, //ISO-8859-n: ENUM_MEM_CHAR_ENCODE_ISO8859_1 + n -1
ENUM_MEM_CHAR_ENCODE_UNICODE = 8, //Unicode
}CHAR_ENCODE_TYPE;

转为FPC格式为
type
tagCharEncodeType = (
ENUM_MEM_CHAR_ENCODE_ERR = -1, //Error
ENUM_MEM_CHAR_ENCODE_NO = 0, //Don’t know.
ENUM_MEM_CHAR_ENCODE_CN = 1, //EUC-CN, GB2312
ENUM_MEM_CHAR_ENCODE_GBK = 2, //GBK
ENUM_MEM_CHAR_ENCODE_BIG5 = 3, //BIG5
ENUM_MEM_CHAR_ENCODE_JP = 4, //JISX0208-1, EUC-JP
ENUM_MEM_CHAR_ENCODE_KR = 5, //EUC-KR
ENUM_MEM_CHAR_ENCODE_UTF8 = 6, //UTF-8
ENUM_MEM_CHAR_ENCODE_ISO8859_1 = 7, //ISO-8859-n: ENUM_MEM_CHAR_ENCODE_ISO8859_1 + n -1
ENUM_MEM_CHAR_ENCODE_UNICODE = 8 //Unicode
);
CHAR_ENCODE_TYPE = tagCharEncodeType;
在delphi中,可以这样定义:
const
ENUM_MEM_CHAR_ENCODE_ERR = -1; //Error
ENUM_MEM_CHAR_ENCODE_NO = 0; //Don’t know.
ENUM_MEM_CHAR_ENCODE_CN = 1; //EUC-CN, GB2312
ENUM_MEM_CHAR_ENCODE_GBK = 2; //GBK
ENUM_MEM_CHAR_ENCODE_BIG5 = 3; //BIG5
ENUM_MEM_CHAR_ENCODE_JP = 4; //JISX0208-1, EUC-JP
ENUM_MEM_CHAR_ENCODE_KR = 5; //EUC-KR
ENUM_MEM_CHAR_ENCODE_UTF8 = 6; //UTF-8
ENUM_MEM_CHAR_ENCODE_ISO8859_1 = 7; //ISO-8859-n: ENUM_MEM_CHAR_ENCODE_ISO8859_1 + n -1
ENUM_MEM_CHAR_ENCODE_UNICODE = 8; //Unicode
type
tagCharEncodeType = set of Integer ; //因为含-1,不能用 tagCharEncodeType =set of -1…8;而tagCharEncodeType =set of 10…100则是可以的;
CHAR_ENCODE_TYPE = tagCharEncodeType;
这样即可引用元素名称,也可以引用类型定义。

四、联合体定义

pascal不支持联合体结构,都是用集合体来定义,通过free pascal wiki和网上一些文章,以上面的函数为例,我总结了两个定义方式,一种直接使用嵌套定义:

tagNET_DVR_ALARMINFO_FIXED_HEADER = record
dwAlarmType:longint ;//报警类型
struAlarmTime:NET_DVR_TIME_EX ;//发生报警的时间
uStruAlarm:record
case word of
0:(byUnionLen:array[0…115] of BYTE); //分出去8个字节用于扩展时区
1:(struAlarmChannel:record // 报警类型dwAlarmType为0时有效
dwAlarmChanNum: DWORD;
dwPicLen: DWORD; //Jpeg图片长度
byPicURL: BYTE;
byTarget: BYTE ; //0-不区分识别目标,1-识别目标为人,2-识别目标为车*/
byRes1:array[0…1] of BYTE ; //保留
{KaTeX parse error: Expected 'EOF', got '}' at position 50: …ed(OS_POSIX64))}̲//win64及linux64…else}
pDataBuff:PChar; //报警图片或者图片URL
byRes3:array[0…3] of byte;
{$endif}
end;);
2:(struAlarmHardDisk:record
dwAlarmHardDiskNum: DWORD ;
end;);
end;
pRes:PInteger ; //用于兼容64位下结构体字节不对齐问题
byTimeDiffFlag:BYTE; //时差字段是否有效 0-时差无效, 1-时差有效 */
cTimeDifferenceH: char;
cTimeDifferenceM: char;
byRes: BYTE; //保留
wDevInfoIvmsChannel: WORD; //增加后端透传前端时的通道号
byRes2:array[0…1] of BYTE; //保留
end;
NET_DVR_ALRAM_FIXED_HEADER = tagNET_DVR_ALARMINFO_FIXED_HEADER;
LPNET_DVR_ALARM_FIXED_HEADER =^tagNET_DVR_ALARMINFO_FIXED_HEADER;

还有一种是将个子结构分别定义,然后定义最后的结构:
//子结构定义
tagSTRUALARMCHANNEL = record
dwAlarmChanNum: DWORD ;
dwPicLen: DWORD ; //Jpeg图片长度
byPicURL: BYTE; //图片数据采用URL方式 0-二进制图片数据,1-图片数据走URL方式
byTarget: BYTE; //0-不区分识别目标,1-识别目标为人,2-识别目标为车*/
byRes1:array[0…1] of BYTE ; //保留
{KaTeX parse error: Expected 'EOF', got '}' at position 50: …ed(OS_POSIX64))}̲//win64及linux64…else}
pDataBuff:PChar; //报警图片或者图片URL
byRes3:array[0…3] of byte;
{$endif}
end;
//子结构定义
tagSTRUALARMHARDDISK = record
dwAlarmHardDiskNum: DWORD ;
end;
//联合体定义
taguStruAlarm = record
case word of //uStruAlarm
0:(byUnionLen:array[0…115] of BYTE); //分出去8个字节用于扩展时区
2:(struAlarmChannel:tagSTRUALARMCHANNEL;); //引用上面的子结构定义
3:(struAlarmHardDisk:tagSTRUALARMHARDDISK;); // 引用上面的子结构定义
end;

tagNET_DVR_ALARMINFO_FIXED_HEADER = record
dwAlarmType:longint ;//报警类型
struAlarmTime:NET_DVR_TIME_EX ;//发生报警的时间
uStruAlarm:taguStruAlarm; //引用上面的联合体定义
pRes:PInteger ; //用于兼容64位下结构体字节不对齐问题
byTimeDiffFlag:BYTE; //时差字段是否有效 0-时差无效, 1-时差有效 */
cTimeDifferenceH: char;
cTimeDifferenceM: char;
byRes: BYTE; //保留
wDevInfoIvmsChannel: WORD; //增加后端透传前端时的通道号
byRes2:array[0…1] of BYTE; //保留
end;
NET_DVR_ALRAM_FIXED_HEADER = tagNET_DVR_ALARMINFO_FIXED_HEADER;
LPNET_DVR_ALARM_FIXED_HEADER =^tagNET_DVR_ALARMINFO_FIXED_HEADER;

暂时结束

因为pascal与C类型的类型定义相似,而且有指针类型,所以翻译C头文件还是比较容易的,这次主要是这些头文件太大了,搞的没脾气,还没搞完呢,先记录这么多

海康SDK for FPC及大华SDK for FPC均已经上传到资源中,可以参考。均在Lazarus2.0.10 Win64下编译通过,并测试调用摄像机预览、图像参数调节、音频控制、PTZ操作、视频抓图、视频录像等函数是成功的,其它的函数没有测试过,请慎重使用。

2022.12.25 hefei

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
RealThinClient SDK Copyright 2004-2013 (c) RealThinClient.com All rights reserved. -------------------------------- ******************************** 1.) License Agreement 2.) Install RTC SDK components in Delphi 3.) Make the RTC SDK accessible from XCode (for iOS development) 4.) Update RTC SDK components in Delphi 5.) Help 6.) Demos 7.) Support ******************************** -------------------------------- --------------------- 1.) License Agreement --------------------- Please read the RTC SDK License Agreement before using RTC SDK components. You will find the RTC SDK License Agreement in the "License.txt" file. -------------------------------- 2.) INSTALL RTC SDK components in Delphi -------------------------------- After you have unpacked the files in a folder of your choice and started Delphi, open the "Package_Main" Project Group where you will find 3 packages: rtcSDK.dpk -> The main Package. Includes all Client and Server HTTP/S components. rtcSDK_DBA.dpk -> Optional, includes only "TRtcMemDataSet" and "TRtcDataSetMonitor" components. rtcSDK_RAW.dpk -> Optional, includes only raw TCP/IP and UDP communication components. Install the components in Delphi by using the "Install" button, or the "Install" menu option. In older Delphi versions, you will see the "Install" button in the Project Manager window. In newer Delphi versions, you will find the "Install" option if you right-click the package file in the Project Manager accessed in the "View" drop-down menu. When compiled and installed, you will see a message listing all components installed. After that, you should add the path to the RTC SDK's "Lib" folder to "Library paths" in Delphi. In older Delphi versions, the Library Path is located in the "Tools / Environment Options" menu. Select the "Library" tab and add the full path to the RTC SDK's "Lib" folder to "Library path". In newer Delphi versions, Library Paths are located in the "Tools / Options" menu. Select the "Environment Options / Delphi Options / Library" tree branch, where you will find the "Library Path" field. There, you should click the "..." button next to "Library path" and add the path to the RTC SDK's "Lib" folder. In Delphi XE2 and later, you will also see a "Selected Platform" drop-down menu. There, all the settings are separated by platforms, so you will need to repeat the process for every platform you want to use the "RTC SDK" with. ------------------------------- 3.) Make the RTC SDK accessible from XCode (for iOS development) - Delphi XE2 ------------------------------- For the FPC compiler to find RTC SDK files, you can either copy the complete "Lib" folder (with sub-folders) from the RTC SDK package into the "/Developer/Embarcadero/fmi" folder (quick and dirty solution), or ... You can add the path to the RTC SDK 揕ib?folder (located on your Windows PC, made accessible to Mac over LAN) to the FPC search path. Unfortunatelly, there is no 損arameter?for adding FPC search paths in XCode directly, so you will need to do this manually for every XCode Project. And not only once, but every time you recreate XCode Project files by using the 揹pr2xcode?tool, because all your changes will be overwritten by "dpr2xcode". To avoid having to make these changes too often, use "dpr2xcode" ONLY if you have made changes to the Project file itself (changed the Project icon, for example). There is no need to recreate XCode Project files if you have only changed forms or units inside the Project. To add the RTC SDK paths to FPC, you will need to modify the file "xcode/<ProjectName>.xcodeproj/project.pbxproj". The path to the RTC SDK 揕ib?folder needs to be added as two new ?Fu?parameters. Once for iOS-Simulator and once for iOS-Device compilation, both of are configured through the 搒hellScript?parameter. The best place to add the RTC SDK Lib path is after the FireMonkey path, so you should search for ?Fu/Developer/Embarcadero/fmi?in the above mentioned XCode Project file. You will find 2 such instances in the "ShellScript" line and you should add the path to the RTC SDK Lib folder directly after each "-Fu/Developer/Embarcadero/fmi" instance. For example, if you have made the complete RTC SDK folder on your Windows PC available to your Mac OSX through a network share named 揜TC_SDK?(read/write access rights to that folder will be required for FPC compilation to work), you should add ?Fu/Volumes/RTC_SDK/Lib?after both ?Fu/Developer/Embarcaedro/fmi?locations. One is for the iOS-Simulator, the other one for the iOS device. That will be enough to let FPC know where to look for RTC SDK files. Should you still get "File not found" errors when trying to compile a Project using RTC files, make sure the path you have used is correct and that Mac OSX has read and write access to that folder. PS. Before configuring access to the RTC SDK, you will need to have OSX 10.6 or 10.7, the latest XCode 4.x version and both packages provided by Embarcadero (included with RAD Studio XE2) installed on your Mac. To make sure your Mac OSX configuration is correct, create an empty "FireMonkey iOS HD" Project, use "dpr2xcode" to create XCode Project files and try to run that Project from XCode, either inside the iOS-Simulator or directly on your iOS device (iPhone or iPad). ------------------------------- 4.) UPDATE RTC SDK components in Delphi ------------------------------- Download the latest version of the RTC SDK from the RTC Support Forum: http://sf.realthinclient.com Information about recent RTC SDK updates is in the "Updates*.txt" file(s). To update RTC SDK components, it's adviseable to uninstall the old packages and delete the old BPL and DCP files (rtcSDK.bpl, rtcSDK.dcp, rtcSDK_DBA.bpl, rtcSDK_DBA.dcp, rtcSDK_RAW.bpl and rtcSDK_RAW.dcp) before installing new packages. To uninstall RTC SDK components, after you start Delphi, open the menu "Component / Install Packages ..." where you will see a list of all packages currently installed in your Delphi. Scroll down to find "RealThinClient SDK" and click on it (single click). When you select it, click the button "Remove" and Delphi will ask you if you want to remove this package. Clicking "Yes" will uninstall the RTC SDK. After that, *close* Delphi and follow step (2) to install the new RTC SDK package. NOTE: Uninstalling the RTC SDK package will also uninstall all packages which are using the RTC SDK (for example, rtcSDK_DBA, rtcSDK_RAW and "Nexus Portal" packages). So ... if you are using "Nexus Portal" or any other product using the RTC SDK, you will need to Build and Install all related packages again, after you reinstall the RTC SDK. ------------- 5.) Help ------------- The best place to start learning about RTC SDK is the QuickStart guide. After going through the online lessons, you should also go through the QuickStart examples included in the RTC SDK package. When you are done examining QuickStart examples, I suggest browsing through the FAQ. Even if you won't be reading all the articles, you should at least get the feeling about the information included there. RTC SDK Demos are another good source of information, including a lot of examples and best practices for using the RealThinClient SDK. And the most extensive source of information on the RealThinClient SDK are Help files. Some of the information is spread across the files, but if you know which class you need, you will most likely be able to find what you are looking for. When you start working on your project, the FAQ will come in handy when you have to do something specific (use Sessions, accept form post data, write and call remote functions, etc). The FAQ is continually being extended, as more questions come in. If you have a question for which you were unable to find the answer in the QuickStart guide, QuickStart examples or the FAQ ?and searching through the Help files didn't give you the answers you need, don't hesitate to post your question(s) on Developer Support groups. The latest Help file for Off-line viewing is in the "Help" folder: - "Help\RTCSDK_Help.chm" ------------------- 6.) Demos ------------------- You can find Demos using RTC SDK components in the "Demos" folder. Simple Quick Start Examples are available in the "QuickStart" folder. There are also 5 Project Groups which include all the Demos and Quick Start examples: * Demos_VCL - Demos using the VCL and the rtcSDK.dpk * Demos_VCL_DBA - Demos using the VCL with the rtcSDK.dpk and rtcSDK_DBA.dpk * Demos_FMX - Demos using FMX (Win,OSX,iOS) with the rtcSDK.dpk * Demos_FMX_DBA - Demos using FMX (Win,OSX,iOS) with the rtcSDK.dpk and rtcSDK_DBA.dpk * Examples_QuickStart_VCL - Short "QuickStart" examples using the VCL with the rtcSDK.dpk For short descriptions of available demos and quick start examples, please find the "Readme_Demos.txt" file in the "Demos" folder, and "Readme_QuickStart.txt" file in the QuickStart folder. ------------- 7.) Support ------------- More information on RTC SDK: > http://www.realthinclient.com/about.htm Download the latest version of RTC components and get Support through the RTC Forums: > http://sf.realthinclient.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

远东999

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值