Android Some notes for Android Java JNI C++ NDK

Add multi include header files to project CMake: https://stackoverflow.com/questions/13703647/how-to-properly-add-include-directories-with-cmake

  • Way 1
My project directory was like this:
    --project
    ---Classes
    ----Application
    -----.h and .c files
    ----OtherFolders
    --main.cpp
And what I used to include the files in all those folders:
    file(GLOB source_files
            "*.h"
            "*.cpp"
            "Classes/*/*.cpp"
            "Classes/*/*.h"
    )

    add_executable(Server ${source_files})
  • Way 2
Add include_directories("/your/path/here").
This will be similar to calling gcc with -I/your/path/here/ option.
Make sure you put double quotes around the path.
  • Config local external import file CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
add_library(
        MagicJni
        SHARED
        MagicJni.cpp
        beautify/MagicBeautify.cpp
        beautify/MagicBeautify.h
        bitmap/BitmapOperation.cpp
        bitmap/BitmapOperation.h
        bitmap/Conversion.cpp
        bitmap/Conversion.h
        bitmap/JniBitmap.h
        )

find_library(
        log-lib
        log)


target_link_libraries( # Specifies the target library.
        MagicJni

        -ljnigraphics
        ${log-lib})
  • Log from native
#include <android/log.h>

#define log_print __android_log_print
#define  LOG_TAG    "MagicJni"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

….
#Using

    LOGE("no bitmap data was stored. returning null...”);
    log_print(ANDROID_LOG_VERBOSE, "stabilize", "Pointf %f %f", tp.GetPoint().x, tp.GetPoint().y);
  • Function void template
//
// Created by iNhan Cao on 2019-06-18.
//

#include <jni.h>
#include <string>
#include <stddef.h>

#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <android/bitmap.h>
#include <android/log.h>

#define  LOG_TAG    "native-lib"
#define  LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define log_print __android_log_print

using namespace cv;

extern "C" JNIEXPORT void JNICALL
Java_com_nhancv_facemask_tracking_PointState_init(JNIEnv *env, jobject /* this */) {
}
  • Return string
extern "C" JNIEXPORT jstring JNICALL
Java_com_nhancv_facemask_tracking_PointState_stringFromJNI(JNIEnv *env, jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
  • Pass bitmap object to native
extern "C" JNIEXPORT void JNICALL
Java_com_nhancv_facemask_tracking_PointState_canny(
        JNIEnv *env,
        jobject /* this */,
        jobject bitmap,
        jstring destination) {


    // Get information about format and size
    AndroidBitmapInfo info;
    AndroidBitmap_getInfo(env, bitmap, &info);


    // Get pointer to pixel buffer
    void *pixels = 0;
    AndroidBitmap_lockPixels(env, bitmap, &pixels);

    {


        Mat input(info.height, info.width, CV_8UC4, pixels);
        Mat dst;
        // Convert to gray
        cvtColor(input, input, COLOR_BGR2GRAY);
        // Histogram equalization
        equalizeHist(input, dst);
        // Saturation by 10%
        float alpha = 1.1f;
        float beta = 12.75f;
        dst.convertTo(dst, -1, alpha, beta);


        // Save to destination
        const char *dest = env->GetStringUTFChars(destination, 0);
        imwrite(dest, dst);
        env->ReleaseStringUTFChars(destination, dest);
    }


    // Release the Bitmap buffer once we have it inside our Mat
    AndroidBitmap_unlockPixels(env, bitmap);
}
  • Load library from java
static {
    System.loadLibrary("SuperpoweredAudio");
}
  • Java convert short to bytes
public short[] toShorts(byte[] bytes) {
    short[] out = new short[bytes.length / 2];
    ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(out);
    return out;
}

public byte[] toBytes(short[] shorts) {
    byte[] out = new byte[shorts.length * 2];
    ByteBuffer.wrap(out).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().put(shorts);
    return out;
}
  • Native read short[] from java and return short[]
extern "C" JNIEXPORT jshortArray
Java_com_nhancv_opentokeffects_SuperpoweredAudio_processData(
        JNIEnv *__unused env,
        jobject  __unused obj,
        jshortArray data
) {
    // Take data from java
    jshort *tempPointer = env->GetShortArrayElements(data, JNI_FALSE);
    int dataSize = env->GetArrayLength(data);
    
    // Return
    jshortArray result = (env)->NewShortArray(dataSize);
    (env)->SetShortArrayRegion(result, 0, dataSize, (jshort *) tempPointer);
    (env)->ReleaseShortArrayElements(data, tempPointer, JNI_ABORT);
    return result;
}
  • Native allocate array
static float *floatBuffer;

// allocate buffer
floatBuffer = (float *) malloc(sizeof(float) * 2 * bufferSize);
  • Native deal with vector
std::vector<PointState> trackPoints;

std::vector<float> resultVector;
for (const PointState &tp : trackPoints) {
    resultVector.push_back(tp.GetPoint().x);
    resultVector.push_back(tp.GetPoint().y);
}
  • Read float[] from java, deal with vector return float[]
extern "C" JNIEXPORT jfloatArray JNICALL
Java_com_nhancv_facemask_tracking_PointState_stabilize(JNIEnv *env, jobject /* this */,
        jfloatArray landmark_points) {
    // Read
    jfloat *tempPointer = env->GetFloatArrayElements(landmark_points, JNI_FALSE);
    int dataSize = env->GetArrayLength(landmark_points);
    // Populate data to vector
    std::vector<cv::Point2f> landmarks;
    for (int i = 0; i < dataSize; i += 2) {
        landmarks.emplace_back(Point2f(*(tempPointer + i), *(tempPointer + i + 1)));
    }
    
    for (const cv::Point2f &lp : landmarks) {
        trackPoints.emplace_back(lp);
    }
    
    std::vector<float> resultVector;
    for (const PointState &tp : trackPoints) {
        resultVector.push_back(tp.GetPoint().x);
        resultVector.push_back(tp.GetPoint().y);
    }

    // Format data to return
    jfloatArray result = (env)->NewFloatArray(dataSize);
    (env)->SetFloatArrayRegion(result, 0, dataSize, (jfloat *) &*resultVector.begin());

    (env)->ReleaseFloatArrayElements(landmark_points, tempPointer, JNI_ABORT);
    return result;
}
  • Error: unknown type name ‘size_t’
#include <stddef.h>

Leave a Reply

Your email address will not be published.Required fields are marked *