Android 三方算法库导入及使用

如图直接上步骤:
1.需要先弄一个nativeLib module
2.整理目录层级
3.导入算法库。
4.根据头文件写入对应的方法。

nativeLib module

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
可以看到以及有了基础模型
同时我们需要在
settings.gradle 中添加

include ':nativelib'

将当前模块编译到。
settings.gradle 是 Gradle 构建系统中的一个配置文件,用于配置构建环境的设置,特别是在多项目构建(multi-project build)中。它主要用于定义哪些项目包含在构建中,并设置一些全局属性。

settings.gradle 的作用(可以跳过,就是简单了解它是导入model的就可)

1.包含子项目

  • 在多项目构建中,settings.gradle 文件用于指定包含哪些子项目。使用 include 方法将子项目添加到构建中。
  • 例如,如果你的项目结构如下:
  • settings.gradle 的作用(可以跳过,就是简单了解它是导入model的就可)
    1.包含子项目
  • 在多项目构建中,settings.gradle 文件用于指定包含哪些子项目。使用 include 方法将子项目添加到构建中。
  • 例如,如果你的项目结构如下:
    ├── settings.gradle
    ├── build.gradle
    ├── app/
    │ └── build.gradle
    └── library/
    └── build.gradle

你可以在 settings.gradle 中包含子项目:

include 'app', 'library'

2.设置项目的名称
使用 rootProject.name 设置根项目的名称:

rootProject.name = 'MyProject'

3.配置子项目路径
如果子项目的目录结构不在默认位置,可以通过 projectDir 属性配置子项目的路径:

include 'app' 
project(':app').projectDir = new File(settingsDir, 'custom/app-directory')

4.插件管理
从 Gradle 6.0 开始,settings.gradle 支持插件管理块,用于配置插件仓库和应用插件:

pluginManagement {
    repositories {
        gradlePluginPortal()
        mavenCentral()
        google()
    }
}

5.初始化脚本

  • 可以在 settings.gradle 中添加一些初始化代码,配置构建脚本执行前的行为。

nativeLib层级编写整理

我们打开CMakeLists.txt。初始的时候是一个写好的示例。我们不建议这样,因为不可能只放一个算法。
在这里插入图片描述
1.修改最外层的CMakeLists(通过ADD_SUBDIRECTORY添加子模块)
2.添加子目录及写子目录的CMakeLists.txt(简单的copy一下,下面有讲解里面关键字的含义)
3.我们在子目录的SDK文件中放入算法商提供的文件(库,头文件,示例代码)
4.创建JNI对应的C++文件。

在这里插入图片描述

# 设置项目名称project(MyProject)
project("nativelib")

#INCLUDE_DIRECTORIES 可以确保你的项目在编译时能够正确地找到所需的头文件。
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/SDK/inc")

#file(GLOB ...) 命令来收集当前目录中所有 .cpp 文件
file(GLOB src-files
        ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
# 添加可执行文件
add_library( # Sets the name of the library.
        nativelib

        # Sets the library as a shared library.
        SHARED

        ${src-files}
)

add_library 命令可以创建一个库(静态库或共享库)。你提供的代码片段显示了如何设置一个共享库(shared library),并将源文件添加到库中。

  • 是库的名称。
  • STATIC、SHARED 或 MODULE 指定库的类型。
  • STATIC:静态库。
  • SHARED:共享库(动态库)。
  • MODULE:模块库,不会被链接到其它目标,通常在插件系统中使用。
  • EXCLUDE_FROM_ALL(可选):表示该库不会被构建为默认目标的一部分。
  • source1 source2 … sourceN 是源文件列表。
# 添加导入的共享库
add_library(sdk SHARED IMPORTED)
# 根据目标架构设置共享库的实际位置
set_target_properties(sdk PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/SDK/lib/${ANDROID_ABI}/zhongmin_capture.so)
# 链接导入的共享库到可执行文件
target_link_libraries( # Specifies the target library.
        nativelib
        # Links the target library to the log library
        # included in the NDK.
        sdk
        )
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.10.2)
# Declares and names the project.

project("nativelib")

INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/SDK/inc")


file(GLOB src-files
        ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        nativelib

        # Sets the library as a shared library.
        SHARED

        ${src-files}
)

add_library(sdk SHARED IMPORTED)
set_target_properties(sdk PROPERTIES IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/SDK/lib/${ANDROID_ABI}/zhongmin_capture.so)


# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        nativelib

        # Links the target library to the log library
        # included in the NDK.
        sdk
        )

在这里插入图片描述

Java代码中可以快速导入生成方法

在这里插入图片描述
在这里插入图片描述
大体框架基本搭建成功,然后导入对应算法。我们将算法放在SDK 目录下。

原理流程:

在这里插入图片描述
此时,算法库与jni层基础连接已完成。我们需要根据算法商提供的smaplecode来参考如何写JNI层。

我们以init 为例子。(算法不同,编写JNI不同,简单以Init 举例)
在这里插入图片描述
它需要一个MHandle 类型的指针数据,创建一个int 类型的hanlde传给算法。
在这里插入图片描述
java 中提供public 给其他类调用。
在这里插入图片描述
大体流程如此。根据算法要的数据来传递处理。

JNI 中的数据类型

基本数据类型

/* Primitive types that match up with Java equivalents. */
typedef uint8_t  jboolean; /* unsigned 8 bits */
typedef int8_t   jbyte;    /* signed 8 bits */
typedef uint16_t jchar;    /* unsigned 16 bits */
typedef int16_t  jshort;   /* signed 16 bits */
typedef int32_t  jint;     /* signed 32 bits */
typedef int64_t  jlong;    /* signed 64 bits */
typedef float    jfloat;   /* 32-bit IEEE 754 */
typedef double   jdouble;  /* 64-bit IEEE 754 */

/* "cardinal indices and sizes" */
typedef jint     jsize;


#ifdef __cplusplus
// 内部的数据结构由虚拟机实现,只能从虚拟机源码看
class _jobject {};
class _jclass : public _jobject {};
class _jstring : public _jobject {};
class _jarray : public _jobject {};
class _jobjectArray : public _jarray {};
class _jbooleanArray : public _jarray {};
...
// 说明我们接触到到 jobject、jclass 其实是一个指针
typedef _jobject*       jobject;
typedef _jclass*        jclass;
typedef _jstring*       jstring;
typedef _jarray*        jarray;
typedef _jobjectArray*  jobjectArray;
typedef _jbooleanArray* jbooleanArray;
Java 类型JNI 类型描述长度(字节)
booleanjbooleanunsigned char1
bytejbytesigned char1
charjcharunsigned short2
shortjshortsigned short2
intjint、jsizesigned int4
longjlongsigned long8
floatjfloatsigned float4
doublejdoublesigned double8
ClassjclassClass 类对象1
Stringjstrting字符串对象/
Objectjobject对象/
Throwablejthrowable异常对象/
boolean[]jbooleanArray布尔数组/
byte[]jbyteArraybyte 数组/
char[]jcharArraychar 数组/
short[]jshortArrayshort 数组/
int[]jinitArrayint 数组/
long[]jlongArraylong 数组/
float[]jfloatArrayfloat 数组/
double[]jdoubleArraydouble 数组/
private static native boolean nativeSetInputImage(long engine, ByteBuffer yBuffer,
                                                  ByteBuffer uBuffer, ByteBuffer vBuffer,
                                                  int index, int yStride, int uvStride,
                                                  int width, int height, float evValue,string str);
                                                  
extern "C"
JNIEXPORT jboolean JNICALL
Java_*_*_*_nativeSetInputImage(JNIEnv *env, jclass clazz,jlong engine,jobject y_buffer,jobject u_buffer,jobject v_buffer,jint index,jint y_stride,jint uv_stride,
 jint width,jint height,jfloat ev_value,jString jStr) {
     ```
     auto *yBuffer = static_cast<uint8_t *>(env->GetDirectBufferAddress(y_buffer));
     char *fileName = new char[200];
sprintf(fileName, "%s_in_%s_index_%d_ev_%.2f_%dx%d.%s", getCameraTypeStr(mCameraType), getSameTimeStamp(),
        index, ev_value,
        y_stride, height, nv12 ? "nv12" : "nv21");
        
        const char *str = env->GetStringUTFChars(jStr, JNI_FALSE);
        
        std::string hello = "Hello from C++";
        jstring jStr1 = env->NewStringUTF(hello.c_str());
        jstring jStr2 = env->NewStringUTF("Hello 2 from C++");
}         

ByteBuffer -> jobject
auto 通常是 C++ 的关键字,用于在编译时自动推断变量类型。
void* GetDirectBufferAddress(jobject buf)
{ return functions->GetDirectBufferAddress(this, buf); } //用于获取 Direct ByteBuffer 对象的地址

int sprintf(char *str, const char *format, …);

  • str:目标字符数组,用于接收格式化后的字符串。
  • format:格式控制字符串,规定了如何将后续参数格式化为字符串。
  • …:可变参数列表,用于提供给格式控制字符串中的格式化标识符指定的数据。
    获取指向 Java 字符串中 UTF-16 数据的指针。
    const jchar* GetStringChars(jstring string, jboolean* isCopy)
    { return functions->GetStringChars(this, string, isCopy); }
    获取指向 Java 字符串中 UTF-8 数据的指针。
    const char* GetStringUTFChars(jstring string, jboolean* isCopy)
    { return functions->GetStringUTFChars(this, string, isCopy); }
    根据传入的 UTF-8 字符串创建一个 Java 字符串对象。
    jstring NewStringUTF(const char* bytes)
    { return functions->NewStringUTF(this, bytes); }
private static native int nativeSetFaceInfo(long handle, Rect[] face);

extern "C"
JNIEXPORT jint JNICALL
Java_*_*_*_*_nativeSetFaceInfo(JNIEnv *env,
                                                                                 jclass clazz,
                                                                                 jlong handle,
                                                                                 jobjectArray face) {
int len = env->GetArrayLength(face);

}

获取 Java 数组的长度。array:Java 数组对象(jarray),可以是基本类型数组或对象数组。

jsize GetArrayLength(jarray array)
{ return functions->GetArrayLength(this, array); }

以yuvutils实战

具体不做过多介绍 可以https://github.com/hzl123456/LibyuvDemo/yuvUtils 作为三方算法示例导入

CMakeLists.txt

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.10.2)

# Declares and names the project.

project("yuvutils")

# jniLibs
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
include_directories(${PROJECT_SOURCE_DIR}/libyuv/include)

#add_subdirectory(${PROJECT_SOURCE_DIR}/libyuv)

add_library( # Sets the name of the library.
        yuvutils

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        yuvutils.cpp)


add_library(yuv STATIC IMPORTED)
set_target_properties(
        yuv
        PROPERTIES IMPORTED_LOCATION
        ${CMAKE_CURRENT_SOURCE_DIR}/libyuv/jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libyuv.a)
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        yuvutils

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib}

        yuv)

以NV12ToI420为例,写对应的JNI。

extern "C"
void
Java_com_yuvutils_YuvUtils_convertNV12ToI420(JNIEnv *env, jclass clazz,
                                                     jobject y, jint y_row_stride,
                                                     jobject uv, jint uv_row_stride,
                                                     jobject out,
                                                     jint width, jint height, jint rotation) {

    uint8_t *src_y = static_cast<uint8_t *>(env->GetDirectBufferAddress(y));
    uint8_t *src_uv = static_cast<uint8_t *>(env->GetDirectBufferAddress(uv));
    uint8_t *output = static_cast<uint8_t *>(env->GetDirectBufferAddress(out));

    rotation = rotation % 360;
    RotationMode rotationMode = getRotationMode(rotation);
    int outW = width;
    int outH = height;
    if (rotation % 180 != 0) {
        outW = height;
        outH = width;
    }
    uint8_t *out_y = output;
    uint8_t *out_u = output + outW * outH;
    uint8_t *out_v = out_u + (outW * outH >> 2);

    NV12ToI420Rotate(src_y, y_row_stride,
                     src_uv, uv_row_stride,
                     out_y, outW,
                     out_u, outW >> 1,
                     out_v, outW >> 1,
                     width, height, rotationMode);
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值