使用OpenHarmonyNDK移植三方库Speexdsp

系统 OpenHarmony
笔者最近为Speexdsp编写了CMakeLists.txt,使用OpenHarmony的NDK工具编译出来so动态库和可执行文件,并且成功在开发板上运行,现将经验分享如下。

想了解更多关于开源的内容,请访问:

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

NDK (原生开发套件) 是一套工具,使开发者能够在 OpenHarmony hap应用中使用 C/C++ 代码。它提供了一系列的工具可以帮助开发者快速的开发C/C++的动态库、静态库和可执行文件。

OpenHarmony 应用开发的Native C++开发方式就要依赖NDK。NDK被包含在OpenHarmony SDK中。可以在DevEco Studio使用 NDK 将 C/C ++ 代码编译到so库中,然后使用 DevEco Studio 的构建插件hvigor-ohos-plugin将so库打包到 Hap 中。ArkTS代码随后可以通过NAPI框架调用SO库中的函数。

深开鸿郭岳峰老师开发的OCRDemo就通过NAPI调用了C++的三方库Tesseract的能力,而这个库本身还依赖leptonica、libjpeg、libpng、libtiff等C/C ++ 等四方库。如果重新编写build.gn移植到OpenHarmony,工作量巨大。

Tesseract (Apache 2.0 License)是一个可以进行图像OCR识别的C ++ 库

OpenHarmony集成OCR三方库实现文字提取

一、编写build.gn与编写CMakeLists.txt移植到OpenHarmony两者的区别

1、编译环境不同,编译工具

编写build.gn方式,编译环境是在OpenHarmony源码中,编译时使用到的是源码中的编译工具。

编写CMakeLists.txt的移植方式实际上是Native C++应用开发方式的一种,并且NDK是SDK的一部分,编译so时候实际上使用的是NDK的编译工具。

2、so安装的地方不一样

编写build.gn方式,三方库编译出来的so和测试用例可以打包进入OpenHarmony固件中。

编写CMakeLists.txt方式,编译出来的实际上会被打包进入hap应用中,hap再安装到OpenHarmony操作系统上完成三方库so能力的调用。

3、编写CMakeLists.txt比编写build.gn更容易

build.gn总有各种各样的编译器标志要加入以消除编译报错,开发者学习成本比较高

CMakeLists.txt方式开发者则相对熟悉,对于原生库就是camke构建的三方库,只需要对原生库已有的CMakeLists.txt做少量修改,比如删除与其他操作系统有关的部分(笔者说的就是AOSP)。

二、使用OpenHarmony的NDK工具移植Speexdsp到Speexdsp

在windows端的IDE上调用NDK。

创建Native C++工程,但是先不写NAPI和ArkTS的部分,先为C/C ++的三方库编写CMakeLists.txt(如果三方库本身就是cmake构建的,但也要对CMakeLists.txt进行少量的修改,详细请参考该样例 https://gitee.com/openharmony-sig/knowledge_demo_temp/tree/master/FA/OCRDemo)。 然后编译hap应用来调用SDK中的NDK工具。

三、创建Native C++工程使用SDK中的NDK工具

创建Native C++工程参考:三方库移植之NAPI开发[3]通过IDE开发NAPI工程

1、打开IDE Deveco Studio,创建一个Native C++工程。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

2、SDK选择API9,model选择Stage。新建的Native C++工程有一个默认的hello world教程。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

将Speexdsp加入Native C++工程,在库中编写顶层CMakeLists.txt生成动态库。

将speexdsp源码移动到Native C++工程entry\src\main\cpp目录,cpp目录专门用于存放C/C ++代码。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

删除Speexdsp中无关的代码让代码结构简洁。Speexdsp中有一些无关的代码,例如和win32、macO上运行的有关代码,甚至还有塞班系统symbian上的代码。(不管了先删除,不知道Speexdsp的开源协议允不允许笔者这样做,但是看着乱乱的目录结构,笔者希望这样让自身的思路清晰一些。)

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

# 目录结构说明
cpp
├─include # .h文件
├─libspeexdsp # .c文件
└─CMakeLists.txt # 笔者编写的用来生成可执行文件库的CMakeLists.txt
├─BUILD.gn # 笔者之前写的BUILD.gn,现在拿来参考写CMakeLists.txt
├─CMakeLists.txt # 笔者编写的用来生成动态库的CMakeLists.txt
├─config.h # Speexdsp原生库在linux下编译构建生成的配置文件
├─speexdsp_api.txt # Speexdsp的api列表
└─speedsp_tested_api.txt

编写顶层在CMakeLists.txt生成动态库。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

############################################
# 创建so动态库

# 源文件
# CMAKE_CURRENT_SOURCE_DIR指的CMakeLists.txt当前所在的目录
set(SHARED_LIB_SRC "${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/preprocess.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/jitter.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/mdf.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/fftwrap.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/filterbank.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/resample.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/buffer.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/scal.c"
"${CMAKE_CURRENT_SOURCE_DIR}/libspeexdsp/smallft.c")

add_library(speexdsp SHARED ${SHARED_LIB_SRC})
target_include_directories(speexdsp PRIVATE ${INCLUDE_DIR})

############################################################

# 链接数学库-lm
# 如果为所有target统一指定编译时要链接的库用LINK_LIBRARIES
# 为每个target单独指定编译时要链接的库用TARGET_LINK_LIBRARIES
link_libraries(-lm)
target_link_libraries(speexdsp PUBLIC m)

# 使用add_subdirectory()将子目录添加到构建
add_subdirectory(libspeexdsp)

在库中编写底层CMakeLists.txt生成可执行文件,用来验证so库是否运行正常。

在.c源文件目录添加CMakeLists.txt用来编译出可执行文件,用来验证使用NDK移植三方库到OpenHarmony标准系统是否成功。如下:

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

cmake_minimum_required(VERSION 3.4.1)
project(test)

#生成执行二进制文件,生成testdenoise测试用例
ADD_EXECUTABLE(testdenoise testdenoise.c)
# 将二进制文件链接到生成的动态库
TARGET_LINK_LIBRARIES(testdenoise PUBLIC speexdsp)
# 将二进制文件链接的库文件
link_libraries(-lm)
# 添加编译器标志
add_compile_options(-g -O2 -fvisibility=hidden)

# 生成testecho测试用例
ADD_EXECUTABLE(testecho testecho.c)
TARGET_LINK_LIBRARIES(testecho PUBLIC speexdsp)
link_libraries(-lm)
add_compile_options(-g -O2 -fvisibility=hidden)

# 生成testjitter测试用例
ADD_EXECUTABLE(testjitter testjitter.c)
TARGET_LINK_LIBRARIES(testjitter PUBLIC speexdsp)
link_libraries(-lm)
add_compile_options(-g -O2 -fvisibility=hidden)

# 生成testresample测试用例
ADD_EXECUTABLE(testresample testresample.c)
TARGET_LINK_LIBRARIES(testresample PUBLIC speexdsp)
link_libraries(-lm)
add_compile_options(-g -O2 -fvisibility=hidden)

# 生成testresample2测试用例
ADD_EXECUTABLE(testresample2 testresample2.c)
TARGET_LINK_LIBRARIES(testresample2 PUBLIC speexdsp)
link_libraries(-lm)
add_compile_options(-g -O2 -fvisibility=hidden)

在库外的CMakeLists.txt中添加代码使能speexdsp编译。

新建的Native C++工程是有一个默认的Hello World模板的,在entry\src\main\cpp目录下有一个CMakeLists.txt,需要在其中添加代码使能speexdsp编译。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

在entry\src\main\cpp\CMakeLists.txt中主要做两件事情

# 添加子目录speexdsp
add_subdirectory(speexdsp)

# 添加链接libspeexdsp.so动态库
# 把动态库libentry.so链接到动态库libspeexdsp.so
target_link_libraries(entry PUBLIC libace_napi.z.so speexdsp)

如果不添加代码,则speexdsp的动态库和可执行用例编译不出来。

执行编译命令编译动态库和测试用例。

在IDE上方工具栏选择编译hap进行so和测试用例的编译。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

编译结果在entry\build\default\intermediates\cmake\default\obj目录下。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

├─arm64-v8a  
libc++_shared.so
libentry.so
libspeexdsp.so
testdenoise
testecho
testjitter
testresample
testresample2

└─armeabi-v7a
libc++_shared.so
libentry.so
libspeexdsp.so
testdenoise
testecho
testjitter
testresample
testresample2

为什么会IDE中的NDK会编译出64位和32位的动态库和可执行文件呢?因为OpenHarmony操作系统有32位和64位,这样是为了hap能在不同位数的OpenHarmony版本上运行。

根据32位和64位的OpenHarmony版本推送相应的so和可执行文件到开发板上。

如何分辨开发板上OpenHarmony版本是64位还是32位?和linux的方式是一样。用getconf WORD_BIT和getconf LONG_BIT获得word和long的位数。64位系统中分别得到32和64。32位系统中分别得到32和32。

笔者开发板上烧录的是32位的OpenHarmony Beta5版本。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

因此需要将Native C++工程目录下的entry\build\default\intermediates\cmake\default\obj\armeabi-v7a中的libspeexdsp.so和testdenoise、testecho、testjitter、testresample、testresample2推送到设备端的data目录。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

通过与ohos版本匹配的hdc_std工具,将编译生成的库以及测试用的可执行文件推送到开发板的data目录。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

hdc_std shell mount -o remount,rw /      ## 重新加载系统为可读写
hdc_std file send testdenoise /data ## 推送可执行文件testdenoise到data目录
hdc_std file send libspeexdsp /data ## 推送libspeexsdp.so到data目录

执行testdenoise可执行文件(其它测试用例的执行请参考 移植speexdsp到OpenHarmony标准系统⑤)。

通过分析testdenoise.c源码,执行测试程序时需要指定一份输入的不为空的8000Hz的input.pcm音频,并且需要指定一份空的输出的output.pcm音频。rk3568上运行,执行语句如下:

./testdenoise < input.pcm > output.pcm 

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

测试结果:对比输入的input.pcm和输出的outpu.pcm的波形图和声谱图,噪声已经被消除。pc端和rk3568开发板运行testdenoise可执行程序效果一致。可执行文件运行成功,使用OpenHarmonyNDK移植三方库Speexdsp成功。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

知识点附送

AIP8的应用如何更改为API9支持64位版本。

API8只支持32位,API9支持32位和64位。

以该PR https://gitee.com/openharmony/applications_app_samples/pulls/759 学习将api8应用适配适配Arm64。

修改build-profile.json5 ,将compileSdkVersion和compatibleSdkVersion属性由8改为9。

compileSdkVersion指定OpenHarmony应用/服务编译时的SDK版本。

compatibleSdkVersion指定OpenHarmony应用/服务兼容的最低SDK版本。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

修改entry/build-profile.json5,abi添加64位arm64-v8a。

abiFilters用于设置本机的ABI编译环境。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

修改entry/src/main/config.json,设备类型改为默认。

#创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp-开源基础软件社区

这个pr改动了XComponent/entry/src/main/cpp/common/plugin_common.h文件,plugin_common.h文件和hilog调试的功能有关。

编译构建子系统如何增加编译构建arm64选择。

以该issue https://gitee.com/openharmony/build/issues/I53E9I 来学习。

分别在hb工具和build.sh脚本添加–target-cpu选项。

电源服务子系统支持64位。

https://gitee.com/openharmony/powermgr_power_manager/issues/I55094。

graphic子系统适配64位编译。

https://gitee.com/openharmony/graphic_graphic_2d/issues/I53720。

想了解更多关于开源的内容,请访问:

​51CTO 开源基础软件社区​

​https://ost.51cto.com​

责任编辑:jianghua 来源: 51CTO 开源基础软件社区
相关推荐

2022-10-11 15:04:28

NAPI开发鸿蒙

2022-10-25 15:05:17

NAPI开发鸿蒙

2014-07-22 10:56:45

Android Stu第三方类库

2020-10-29 09:56:23

Linux静态库动态库

2023-02-07 15:43:13

三方库适配鸿蒙

2022-11-03 15:37:52

NAPI开发三方库移植

2013-08-14 09:50:32

iOS类库

2019-07-30 11:35:54

AndroidRetrofit

2022-09-13 16:10:15

鸿蒙操作系统

2022-09-15 15:21:22

操作系统鸿蒙

2022-11-21 16:15:41

ArkUI鸿蒙

2022-11-16 14:05:06

Tesseract应用调用

2012-04-19 14:16:22

TitaniumTiMVC

2022-10-20 16:18:37

JS类型C/C++数据类型

2014-04-08 15:16:00

2015-11-05 16:44:37

第三方登陆android源码

2010-05-25 11:09:31

SVN工具

2023-11-29 09:19:00

WebhookURL

2011-07-25 14:14:49

iPhone SQLITE Pldatabase

2010-03-03 15:10:49

第三方Python库
点赞
收藏

51CTO技术栈公众号