2018-08-25经常记不清的在Java中添加C++代码的操作

2018-08-27  本文已影响27人  HellyCla

某参考网址

总结:

我们要在Java里调用C++代码,必须借助JNI工具, 这是他们之间交流的工具。
我们通常自己写项目调C/C++的流程:
1.在JavaClass中写要调用未来要在C++中实现的函数头:
public static native void xxxx();
2.在terminal中cd进入java文件的路径下,如:
cd C:\Users\changjianhui\Desktop\VCL_INTERN\githubDemo\FaceExpression\app\src\main\java
3.使用javah编译生成.h文件:
javah -d ../jni -jni cjh.faceexpression.env.ImageUtils
4.第2,3步也可以不要,替换成自己按规则来写出文件头,甚至.h可以没有,直接写.cpp文件,在.cpp中直接声明并实现。
但是函数名必须按照 Java_包名_类名_函数名来写。
比如宏定义一个统一的函数名前缀:
#define IMAGEUTILS_METHOD(METHOD_NAME) \ Java_cjh_faceexpression_env_ImageUtils_##METHOD_NAME
在每个要写的函数里就可以用统一的格式写,只需要替换自己的method_name:

JNIEXPORT void JNICALL
IMAGEUTILS_METHOD(convertYUV420SPToARGB8888)(
        JNIEnv* env, jclass clazz, jbyteArray input, jintArray output,
        jint width, jint height, jboolean halfSize);

5.最后就是实现方法了,参数、返回值等等都要遵循JNI编程的规则,但是我们也可以添加普通的熟知的纯C++式代码来调用,但是需要给出正确的函数头,尤其参数声明,例如:

#ifndef FACEEXPRESSION_RGB2YUV_H
#define FACEEXPRESSION_RGB2YUV_H
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

void ConvertARGB8888ToYUV420SP(const uint32_t* const input,
                               uint8_t* const output, int width, int height);

void ConvertRGB565ToYUV420SP(const uint16_t* const input, uint8_t* const output,
                             const int width, const int height);

#ifdef __cplusplus
}
#endif

#endif //FACEEXPRESSION_RGB2YUV_H

遵循这个函数头我们可以再重新来写我们熟悉的函数,例如:

void ConvertRGB565ToYUV420SP(const uint16_t* const input, uint8_t* const output,
                             const int width, const int height) {
    uint8_t* pY = output;
    uint8_t* pUV = output + (width * height);
    const uint16_t* in = input;

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            const uint32_t rgb = *in++;

            const int r5 = ((rgb >> 11) & 0x1F);
            const int g6 = ((rgb >> 5) & 0x3F);
            const int b5 = (rgb & 0x1F);

            // Shift left, then fill in the empty low bits with a copy of the high
            // bits so we can stretch across the entire 0 - 255 range.
            const int r8 = r5 << 3 | r5 >> 2;
            const int g8 = g6 << 2 | g6 >> 4;
            const int b8 = b5 << 3 | b5 >> 2;

            WriteYUV(x, y, width, r8, g8, b8, pY++, pUV);
        }
    }
}

然后就可以在遵循JNI的复杂函数体里直接调用它而不必重写:


JNIEXPORT void JNICALL
IMAGEUTILS_METHOD(convertRGB565ToYUV420SP)(
        JNIEnv* env, jclass clazz, jbyteArray input, jbyteArray output,
        jint width, jint height) {
    jboolean inputCopy = JNI_FALSE;
    jbyte* const i = env->GetByteArrayElements(input, &inputCopy);

    jboolean outputCopy = JNI_FALSE;
    jbyte* const o = env->GetByteArrayElements(output, &outputCopy);

    ConvertRGB565ToYUV420SP(reinterpret_cast<uint16_t*>(i),
                            reinterpret_cast<uint8_t*>(o), width, height);

    env->ReleaseByteArrayElements(input, i, JNI_ABORT);
    env->ReleaseByteArrayElements(output, o, 0);
}

6.修改cmakeList并重新编译。
当有多个cpp文件需要添加时,可以设一个统一的文件名,如下:
file(GLOB native_srcs "src/main/jni/*.cpp")
修改add_library参数:

add_library( # Sets the name of the library.
             imageUtils

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             #src/main/jni/native-lib.cpp
             ${native_srcs})

别忘记target_link_libraries也需要修改

target_link_libraries( # Specifies the target library.
                       imageUtils
                       #native-lib
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

7.make project

gradle 里配置不再赘述,如果有错误按照提示信息来查改。

上一篇 下一篇

猜你喜欢

热点阅读