JNI实现结构体嵌套返回给Java层

一、前言

对于一个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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值