一、前言
对于一个JNI小白,查了很多网上的资料加上请教java大神才得以搞明白!
参考文章
https://www.jianshu.com/p/67081d9b0a9c
https://blog.csdn.net/u012690435/article/details/38612461
二、实现过程
1、java层数据结构
package com.tg.jni.sdk;
public class Cface_rect {
public int x;
public int y;
public int width;
public int height;
}
package com.tg.jni.sdk;
public class Cface_info {
public Cface_rect face_pos; //人脸在背景图上的坐标信息
public byte[] imageBuffer; //人脸图片数据
}
package com.tg.jni.sdk;
public class Cface_info_array {
public Cface_rect[] track_face_array;//视频画框的人脸坐标信息
public Cface_info[] face_info_array;//过滤重复人脸后的人脸信息
}
2、java层接口类 JNI_MultiFaceCore_SDK
package com.tg.jni.sdk;
public class JNI_MultiFaceCore_SDK {
public final static native Cface_info[] multiFaceCore_detectFace_image(byte[] imageBuffer, int width, int height);
public final static native Cface_info_array multiFaceCore_detectFace_video(byte[] imageBuffer, int width, int height);
static
{
System.loadLibrary("MultiFaceCore");
}
}
3、C++层头文件,代码没有完全贴出,贴两个结构嵌套的接口代码
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_tg_jni_sdk_JNI_MultiFaceCore_SDK */
#ifndef _Included_com_tg_jni_sdk_JNI_MultiFaceCore_SDK
#define _Included_com_tg_jni_sdk_JNI_MultiFaceCore_SDK
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_tg_jni_sdk_JNI_MultiFaceCore_SDK
* Method: multiFaceCore_detectFace_image
* Signature: ([BII)[Lcom/tg/jni/sdk/face_info;
*/
JNIEXPORT jobjectArray JNICALL Java_com_tg_jni_sdk_JNI_1MultiFaceCore_1SDK_multiFaceCore_1detectFace_1image
(JNIEnv *, jobject, jbyteArray, jint, jint);
/*
* Class: com_tg_jni_sdk_JNI_MultiFaceCore_SDK
* Method: multiFaceCore_detectFace_video
* Signature: ([BII)Lcom/tg/jni/sdk/face_info_array;
*/
JNIEXPORT jobject JNICALL Java_com_tg_jni_sdk_JNI_1MultiFaceCore_1SDK_multiFaceCore_1detectFace_1video
(JNIEnv *, jobject, jbyteArray, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
3、C++层接口实现cpp
JNIEXPORT jobjectArray JNICALL Java_com_tg_jni_sdk_JNI_1MultiFaceCore_1SDK_multiFaceCore_1detectFace_1image
(JNIEnv *env, jobject obj, jbyteArray imageBuffer, jint width, jint height)
{
jbyte* bBuffer = env->GetByteArrayElements(imageBuffer, 0);
ListFacePosInfo face_info;
multiFaceCore_detectFace_image(reinterpret_cast<char*>(bBuffer), width, height, face_info);
//释放jbyteArray资源
(env)->ReleaseByteArrayElements(imageBuffer, bBuffer, 0);
//查找类, FindClass参数格式:FindClass("包名+类名"),注意:结尾不需要分号
jclass clsFaceInfo = env->FindClass("com/tg/jni/sdk/Cface_info");
//数组大小
jsize len = face_info.size();
//申明一个object数组
jobjectArray args = env->NewObjectArray(len, clsFaceInfo, NULL);
jclass clsFaceRect = env->FindClass("com/tg/jni/sdk/Cface_rect");
//查找类成员变量,GetFieldID(类对象,“类成员变量名”, “L+包名+类成员变量名类型+分号”)
jfieldID jfield_face_rect = env->GetFieldID(clsFaceInfo, "face_pos", "Lcom/tg/jni/sdk/Cface_rect;");
//获取类中每一个变量的定义(标准格式,网上都有介绍)
jfieldID jfield_x = (env)->GetFieldID(clsFaceRect, "x", "I");
jfieldID jfield_y = (env)->GetFieldID(clsFaceRect, "y", "I");
jfieldID jfield_width = (env)->GetFieldID(clsFaceRect, "width", "I");
jfieldID jfield_height = (env)->GetFieldID(clsFaceRect, "height", "I");
//byte[] 数组格式用“[B”
jfieldID jfield_imageBuffer = env->GetFieldID(clsFaceInfo, "imageBuffer", "[B");
//构造方法名就是class类名。JNI里一律用<init>代替。重载的构造函数,参数签名不同,我这里没有构造函数默认为以下格式。
jmethodID consID_clsFaceInfo = env->GetMethodID(clsFaceInfo, "<init>", "()V");
jmethodID consID_clsFaceRect = env->GetMethodID(clsFaceRect, "<init>", "()V");
//给每一个实例的变量赋值,并且将实例作为一个object,添加到objcet数组中
auto itor = face_info.begin();
for (int i = 0; i < len; i++)
{
jobject jobj_FaceRect = env->NewObject(clsFaceRect, consID_clsFaceRect);
jobject jobj_FaceInfo = env->NewObject(clsFaceInfo, consID_clsFaceInfo);
//class face_rect成员赋值
env->SetIntField(jobj_FaceRect, jfield_x, (*itor)->x);
env->SetIntField(jobj_FaceRect, jfield_y, (*itor)->y);
env->SetIntField(jobj_FaceRect, jfield_width, (*itor)->width);
env->SetIntField(jobj_FaceRect, jfield_height, (*itor)->height);
env->SetObjectField(jobj_FaceInfo, jfield_face_rect, jobj_FaceRect);
int img_size = (*itor)->width * (*itor)->height * 3;
jbyteArray data = env->NewByteArray(img_size);
//创建与buffer容量一样的byte[]
env->SetByteArrayRegion(data, 0, img_size, (jbyte*)((*itor)->face_data.get()));
//数据拷贝到data中
env->SetObjectField(jobj_FaceInfo, jfield_imageBuffer, data);
//添加到objcet数组中
env->SetObjectArrayElement(args, i, jobj_FaceInfo);
//释放资源,一定要释放资源,否则会导致内存泄漏
env->DeleteLocalRef(jobj_FaceRect);
env->DeleteLocalRef(jobj_FaceInfo);
env->DeleteLocalRef(data);
itor++;
}
//返回object数组
return args;
}
JNIEXPORT jobject JNICALL Java_com_tg_jni_sdk_JNI_1MultiFaceCore_1SDK_multiFaceCore_1detectFace_1video
(JNIEnv *env, jobject obj, jbyteArray imageBuffer, jint width, jint height)
{
jbyte* bBuffer = env->GetByteArrayElements(imageBuffer, 0);
char* szImage = reinterpret_cast<char*>(bBuffer);
ListFacePosInfo track_info;
ListFacePosInfo face_info;
multiFaceCore_detectFace_video(szImage, width, height, track_info, face_info);
env->ReleaseByteArrayElements(imageBuffer, bBuffer, 0);
jclass clsFaceInfoArray = env->FindClass("com/tg/jni/sdk/Cface_info_array");
//Cface_rect
jclass clsFaceRect = env->FindClass("com/tg/jni/sdk/Cface_rect");
jsize array_FaceRect_len = track_info.size(); //数组大小
jobjectArray array_FaceRect = env->NewObjectArray(array_FaceRect_len, clsFaceRect, NULL); //申明一个object数组
//Cface_info
jclass clsFaceInfo = env->FindClass("com/tg/jni/sdk/Cface_info");
jsize array_FaceInfo_len = face_info.size(); //数组大小
jobjectArray array_FaceInfo = env->NewObjectArray(array_FaceInfo_len, clsFaceInfo, NULL);
jmethodID consID_clsFaceRect = env->GetMethodID(clsFaceRect, "<init>", "()V");
jmethodID consID_clsFaceInfo = env->GetMethodID(clsFaceInfo, "<init>", "()V");
jmethodID consID_clsFaceInfoArray = env->GetMethodID(clsFaceInfoArray, "<init>", "()V");
jfieldID jfield_track_face_array = env->GetFieldID(clsFaceInfoArray, "track_face_array", "[Lcom/tg/jni/sdk/Cface_rect;");
jfieldID jfield_x = (env)->GetFieldID(clsFaceRect, "x", "I");
jfieldID jfield_y = (env)->GetFieldID(clsFaceRect, "y", "I");
jfieldID jfield_width = (env)->GetFieldID(clsFaceRect, "width", "I");
jfieldID jfield_height = (env)->GetFieldID(clsFaceRect, "height", "I");
jfieldID jfield_face_info_array = env->GetFieldID(clsFaceInfoArray, "face_info_array", "[Lcom/tg/jni/sdk/Cface_info;");
jfieldID jfield_face_rect = env->GetFieldID(clsFaceInfo, "face_pos", "Lcom/tg/jni/sdk/Cface_rect;");
jfieldID jfield_imageBuffer = env->GetFieldID(clsFaceInfo, "imageBuffer", "[B");
auto itor_track_info = track_info.begin();
for (int i = 0; i < array_FaceRect_len; i++)
{
jobject jobj_FaceRect = env->NewObject(clsFaceRect, consID_clsFaceRect);
env->SetIntField(jobj_FaceRect, jfield_x, (*itor_track_info)->x);
env->SetIntField(jobj_FaceRect, jfield_y, (*itor_track_info)->y);
env->SetIntField(jobj_FaceRect, jfield_width, (*itor_track_info)->width);
env->SetIntField(jobj_FaceRect, jfield_height, (*itor_track_info)->height);
//添加到objcet数组中
env->SetObjectArrayElement(array_FaceRect, i, jobj_FaceRect);
env->DeleteLocalRef(jobj_FaceRect);
itor_track_info++;
}
auto itor_face_info = face_info.begin();
for (int j = 0; j < array_FaceInfo_len; j++)
{
jobject jobj_FaceRect = env->NewObject(clsFaceRect, consID_clsFaceRect);
jobject jobj_FaceInfo = env->NewObject(clsFaceInfo, consID_clsFaceInfo);
env->SetIntField(jobj_FaceRect, jfield_x, (*itor_face_info)->x);
env->SetIntField(jobj_FaceRect, jfield_y, (*itor_face_info)->y);
env->SetIntField(jobj_FaceRect, jfield_width, (*itor_face_info)->width);
env->SetIntField(jobj_FaceRect, jfield_height, (*itor_face_info)->height);
env->SetObjectField(jobj_FaceInfo, jfield_face_rect, jobj_FaceRect);
int img_size = (*itor_face_info)->width * (*itor_face_info)->height * 3;
jbyteArray data = env->NewByteArray(img_size);
//创建与buffer容量一样的byte[]
env->SetByteArrayRegion(data, 0, img_size, (jbyte*)((*itor_face_info)->face_data.get())); //数据拷贝到data中
env->SetObjectField(jobj_FaceInfo, jfield_imageBuffer, data);
//添加到objcet数组中
env->SetObjectArrayElement(array_FaceInfo, j, jobj_FaceInfo);
env->DeleteLocalRef(jobj_FaceRect);
env->DeleteLocalRef(jobj_FaceInfo);
env->DeleteLocalRef(data);
itor_face_info++;
}
jobject jobj_FaceInfoArray = env->NewObject(clsFaceInfoArray, consID_clsFaceInfoArray);
env->SetObjectField(jobj_FaceInfoArray, jfield_track_face_array, array_FaceRect);
env->SetObjectField(jobj_FaceInfoArray, jfield_face_info_array, array_FaceInfo);
env->DeleteLocalRef(array_FaceRect);
env->DeleteLocalRef(array_FaceInfo);
env->ExceptionDescribe();
return jobj_FaceInfoArray;
}