使用Swig转换C++到别的编程语言
项目github地址: aoce
设定aoce能分别与UE4/Unity3D/android demo对接,就这三来看,分别是C++/C#/java三种语言.
C++导出给别的语言使用,一般来说,分为二种,使用C风格,这种兼容性最好,但是问题是很多时候API明明是同一对象,使用C风格的就变成先创建/拿到类似句柄的东东,然后相关API第一个函数全是这个句柄做参数,用同一句柄表示他们是同一对象,有同样的上下文(各种状态这些).而第二种就是直接C++导出,别的用户能直接调用并有智能提示对应API,但是问题就在于各个C++编译器对于标准库实现的不同,如STL类库里的string,vector这些,就会导致别人使用你的库时,造成一些奇怪问题.
结合一些开源项目来看,使用abstract class与基本数据类型这种方式算是结合上面二种的优势.主要需要如下修改,一是如string这种,导出给外部使用的头文件里全换成const char*,而得到列表数据如vector,转化成接口getCount/getObject(index)这种.二是所有导出给外部使用的类,全部把接口抽离出来变成abstract class,而对应基类实现全放在不给外部用户使用的文件里.
class IVideoManager {
public:
virtual ~IVideoManager(){};
// 得到摄像头的个数
virtual int32_t getDeviceCount(bool bUpdate = false) = 0;
// 得到所有摄像头
virtual void getDevices(IVideoDevice** videos, int32_t size,
int32_t start = 0) = 0;
virtual IVideoDevice* getDevice(int32_t index) = 0;
};
然后是回调函数的实现,全面放弃C的函数指针或是std::function这种,转成observer abstract class接口这种实现,主要有三个好处,一是避免C这种要转换成无状态的静态函数,以及避免不同std::function编译器实现的坑,二是对应类型多回调的话,这种更方便,三是要转换到别的语言,Swig天然支持这种observer abstract class,不需要做更多处理.
class IVideoDeviceObserver {
public:
virtual ~IVideoDeviceObserver(){};
// 摄像机打开/关闭/丢失等事件
virtual void onDeviceHandle(VideoHandleId id, int32_t codeId){};
// 普通桢数据
virtual void onVideoFrame(VideoFrame frame){};
// 带深度的桢数据
virtual void onDepthVideoFrame(VideoFrame colorFrame, VideoFrame depthFrame,
void* alignParamt){};
};
最后就是返回上面abstract class对应框架内部具体实现对象以及一些帮助类,这种就用C风格的导出.
extern "C" {
ACOE_EXPORT void setLogObserver(ILogObserver* observer);
// 检查模块aoce_cuda/aoce_vulkan/aoce_win_mf/aoce_ffmpeg是否加载成功
ACOE_EXPORT bool checkLoadModel(const char* modelName);
// 得到分配GPU管线的工厂对象,请不要手动释放这个对象,这个对象由aoce管理
ACOE_EXPORT PipeGraphFactory* getPipeGraphFactory(const GpuType& gpuType);
// 得到分配基本层的工厂对象,请不要手动释放这个对象,这个对象由aoce管理
ACOE_EXPORT LayerFactory* getLayerFactory(const GpuType& gpuType);
// 得到对应设备的管理对象,请不要手动释放这个对象,这个对象由aoce管理
ACOE_EXPORT IVideoManager* getVideoManager(const CameraType& cameraType);
// 得到分配媒体播放器的工厂对象,请不要手动释放这个对象,这个对象由aoce管理
ACOE_EXPORT MediaFactory* getMediaFactory(const MediaType& mediaType);
// 得到直播模块提供的管理对象,请不要手动释放这个对象,这个对象由aoce管理
ACOE_EXPORT ILiveRoom* getLiveRoom(const LiveType& liveType);
// 得到对应计算层的参数元数据信息
ACOE_EXPORT ILMetadata* getLayerMetadata(const char* layerName);
}
在aoce里,整理出给外部用户的相关接口与API,可以看到在aoce里有多个.h的文件,这种文件就是放给外部用户,也是swig自动转换成别的语言需要处理的文件,当然在框架内部的各个模块里,还是直接使用C++导出带STL这种更方便.
Swig注意事项
Swig的使用这里就不介绍了,就讲我在转换C#/Java时遇到一些需要注意的地方.
1 要使用回调observer类,需要打开swig的%module(directors = "1")这个,然后%feature("director") ILogObserver;声明相关类.
2 屏蔽相关的一些导出宏,如aoce模块里的ACOE_EXPORT,否则swig可能不能正常编译.
3 上面的getDevices(IVideoDevice** videos这种,本意是给C++申请空间后填充,但是对于别的语言来说,声明一个native的列表空间可能就很麻烦,然后swig默认也只能对二级指针生成SWIGTYPE_p_p这种无意义的对象,所以最好使用%ignore屏蔽掉.
4 如果类有中继承具体化模板的类,需要重新组织头文件,把这二个头分别放在不同头文件中,然后对对应二个%include之间使用%template指明具体化模板,否则生成的类可能丢失这个具体化模板的继承信息.
下面这个问题发生在android studio里,我本来直接使用swig把生成的java文件放入对应的package里,但是每次打开后,相应的package图标变成目录图标,还能正常运行,但是相关智能提示全部不能用,现解决方法是先复制到一个临时目录,然后从临时目录复制到这个package目录下.
然后通过cmake,每次更新编译都可以直接生成最新对应的java包,现用java就能完成以前C++编写的相关逻辑.
public class AoceManager extends IVideoDeviceObserver {
private IPipeGraph pipeGraph = null;
private LayerFactory layerFactory = null;
private IInputLayer inputLayer = null;
private IOutputLayer outputLayer = null;
private IYUVLayer yuv2RGBALayer = null;
private ITransposeLayer transposeLayer = null;
private IFlipLayer flipLayer = null;
private IReSizeLayer reSizeLayer = null;
private IBaseLayer extraLayer = null;
private IVideoDevice videoDevice = null;
private VideoFormat videoFormat = null;
private GLOutGpuTex gpuTex = new GLOutGpuTex();
public void initGraph(){
// 生成VULKAN计算管线
pipeGraph = AoceWrapper.getPipeGraphFactory(GpuType.vulkan).createGraph();
layerFactory = AoceWrapper.getLayerFactory(GpuType.vulkan);
// 输入层
inputLayer = layerFactory.createInput();
// 输出层
outputLayer = layerFactory.createOutput();
// YUV转RGBA
yuv2RGBALayer = layerFactory.createYUV2RGBA();
transposeLayer = layerFactory.createTranspose();
flipLayer = layerFactory.createFlip();
reSizeLayer = layerFactory.createSize();
TransposeParamet tp = transposeLayer.getParamet();
tp.setBFlipX(1);
tp.setBFlipY(1);
transposeLayer.updateParamet(tp);
OutputParamet op = outputLayer.getParamet();
op.setBGpu(1);
op.setBCpu(0);
outputLayer.updateParamet(op);
}
public void openCamera(){openCamera(false);}
// 打开摄像机
public void openCamera(boolean bFront){
if(videoDevice != null && videoDevice.bOpen()){
videoDevice.close();
}
// 底层用C++封装的NDK camera2 API,统一接口使用JAVA封装
int deviceCount = AoceWrapper.getVideoManager(CameraType.and_camera2).getDeviceCount();
for(int i=0;i<deviceCount;i++){
videoDevice = AoceWrapper.getVideoManager(CameraType.and_camera2).getDevice(i);
if(videoDevice.back() != bFront){
break;
}
}
// 找到1280x720的格式
int formatIndex = videoDevice.findFormatIndex(1280,720);
if(formatIndex < 0){
formatIndex = 0;
}
videoDevice.setFormat(formatIndex);
videoDevice.open();
videoFormat = videoDevice.getSelectFormat();
videoDevice.setObserver(this);
}
public void closeCamera(){
if(videoDevice != null){
videoDevice.close();
}
}
public void initLayers(List<IBaseLayer> baseLayers,boolean bAutoIn){
pipeGraph.clear();
// 连接各层
extraLayer = pipeGraph.addNode(inputLayer).addNode(yuv2RGBALayer);
if(baseLayers != null) {
for (IBaseLayer baseLayer : baseLayers) {
extraLayer = extraLayer.addNode(baseLayer);
}
if (bAutoIn) {
yuv2RGBALayer.getLayer().addLine(extraLayer, 0, 1);
}
}
extraLayer.addNode(transposeLayer).addNode(outputLayer);
}
@Override
public void onVideoFrame(VideoFrame frame){
// 检查当前桢是否需要YUV转换
if(AoceWrapper.getYuvIndex(frame.getVideoType()) < 0){
yuv2RGBALayer.getLayer().setVisable(false);
}else if(videoFormat != null){
if(yuv2RGBALayer.getParamet().getType() != frame.getVideoType()){
yuv2RGBALayer.getLayer().setVisable(true);
YUVParamet yp = yuv2RGBALayer.getParamet();
yp.setType(frame.getVideoType());
yuv2RGBALayer.updateParamet(yp);
}
}
inputLayer.inputCpuData(frame);
pipeGraph.run();
}
public void showGL(int textureId, int width, int height){
// 直接把VULKAN显示结果输出给OPENGL ES纹理
gpuTex.setImage(textureId);
gpuTex.setWidth(width);
gpuTex.setHeight(height);
outputLayer.outGLGpuTex(gpuTex);
}
}
整个过程下来,使用CMake+Swig,就可以自动把相关C++更合适(GPU,图像处理,音视频)的方面转化成各种别的编程语言接口,方便别的编程语言更合适(界面UI)调用,修改更新逻辑也会自动更新完成,非常方便.
使用Swig转换C++到别的编程语言的更多相关文章
- mac 环境下 Quantlib 使用Swig 转换到java
一.Mac安装boost方法:http://blog.csdn.net/xujiezhige/article/details/8230493 二.Swig,这里使用sudo install swig ...
- 利用Swig转换C++代码为C#可用的代码
详细的文件路径为:http://user.qzone.qq.com/1259374136/blog/1432887689 Swig学习教程 1.Swig的基本介绍 SWIG(Simplified Wr ...
- 使用SWIG将C++接口转换成Java接口
PS:此文章仅作为个人记录使用,代码属于私密,故无法公开: 以C++类classifier为例,文件保存于百度网盘 https://pan.baidu.com/s/1c2AwhaS(需密码) 系统:U ...
- 最强大的跨语言调用生成工具:Swig 快速实用教程
swig是一个生成其他高级语言调用c和C++代码的工具,比如,大家都知道java的jni,可能没写过,因为非常麻烦,swig可以帮助生成这样的代码,编译生成的代码后,它会生成java类和c代码文件.分 ...
- 我使用过的Linux命令之swig - 把C/C++的代码嵌入Java等语言的开发工具
用途说明 SWIG是Simplified Wrapper and Interface Generator的缩写,其官方站点是http://www.swig.org/.SWIG是个帮助使用C或者C++编 ...
- [转]SSIS数据转换组件_派生列、审核、字符映射转换和条件性拆分转换
本文转自:http://www.cnblogs.com/gudujianxiao/archive/2012/04/14/2446925.html 一 派生列 派生列转换通过对输入列进行类型转换或应用表 ...
- [Google Guava]字符串处理:连接器、拆分器、字符匹配器
一.连接器[Joiner] 二.拆分器[Splitter] 三.字符匹配器[CharMatcher] 四.字符集[Charsets] Charsets:针对所有Java平台都要保证支持的六种字符集提供 ...
- 用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(一)
本文为原创,如有转载,请注明出处:http://www.cnblogs.com/jackybu 前言 章节: 1.需求描述以及c/c++实现日期和月历的基本操作 2.ios实现自绘日期选择控件 3.a ...
- python成长之路13
一:SqlAlchemy ORM ORM:Object Relational Mapping 对象关系映射是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换 SQLAlchemy是 ...
- Python 第十一篇:开发堡垒机
一:SqlAlchemy ORM ORM:Object Relational Mapping 对象关系映射是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换 SQLAlchemy是 ...
随机推荐
- 教你用Perl实现Smgp协议
本文分享自华为云社区<华为云短信服务教你用Perl实现Smgp协议>,作者:张俭. 引言&协议概述 中国电信短消息网关协议(SMGP)是中国网通为实现短信业务而制定的一种通信协议, ...
- java代码审计-某酒店管理系统
java代码审计-某酒店后台管理系统 目录 java代码审计-某酒店后台管理系统 1.简介 2.文件上传漏洞 3.CSRF漏洞 4.存储型XSS 1.简介 文章只作研究学习,请勿非法渗透测试: 该系统 ...
- gitignore文件不生效的问题解决
如何添加 git的忽略文件 .gitignore 在使用git过程中,我们可能有些文件不需要上传上去,比如一些缓存文件,生成的图片,运行环境的一些配置等等,这时就需要用到.gitignore忽略掉这些 ...
- 经验分享:春招零Offer,5月份还有机会吗?
先说答案:5 月份依然有拿到 Offer 的机会. 5月份春招结束了吗? 对于应届大学生来说(也就是今年暑假毕业的学生),5 月中旬春招就陆续结束了,但是 5 月份会有很多补录的机会. 对于非应届的大 ...
- 西门子PLC设备如何接入AIRIOT物联网低代码平台 ?
西门子PLC设备广泛应用于工业控制领域,高性能和稳定是它最大的优势.下面我们要把西门子300 1200 1500 PLC设备连接到AIRIOT物联网低代码平台,具体操作如下所示: 西门子驱动配置(配套 ...
- turltle模块详解
引言:turtle(海龟)模块,我们是用它来进行画图的,基本上就是画简单的直线,点,和曲线. 你可以把它想成一个小海龟,在沙滩上行走,然后留下的各种痕迹,使用Turtle模块可以绘制很多精美的图形. ...
- 如此丝滑的API设计,用起来真香
分享是最有效的学习方式. 博客:https://blog.ktdaddy.com/ 故事 工位上,小猫一边撸着代码,一边吐槽着前人设计的接口. 如下: "我艹,货架模型明明和商品SKU模型是 ...
- Chart.js (v2.9.4)概要介绍
chart.js是一个非常优秀的开源图表插件,扩展非常灵活,同时也提供了大量的钩子函数,给与用户添加自定义插件,实现个性化的需求. 具体的优势特点,这里不详述,网上大把资料,现开始正式深入了解这个插件 ...
- GROUP BY clause and contains nonaggregated 报错处理
1055 - Expression #16 of SELECT list is not in GROUP BY clause and contains nonaggregated column 报错处 ...
- redis 的下载与安装
下载地址:https://github.com/MicrosoftArchive/redis/releases 选择免安装包: 解压到路径 D:\Redis-x64-3.0.504 用管理员权限打开 ...