本实例中包含:
- ByteArray的操作Java<->JNI双向操作
- Java的Object转C的struct以及struct转Java的Object
- ArrayList对象的操作
- Java 数组对象的解析
- malloc 需要free
- ByteArray需要release
//
// Created by liuhui on 2017/11/18.
//
#include <jni.h>
#include <math.h>
#include "Fp16Convert.h"
static jbyteArray normalizeFeatures2(JNIEnv *env, jbyte *feature_, int len);
uint64_t sTaskId = -1;
char *detectFeatureFromPicClazz = "com.xxx.xxx.xxx.model.DetectFaceFromPicture";
char *faceServiceNotificationClazz = "com.xxx.xxx.xxx.model.FaceServiceNotification";
//char* to jstring
int sto(JNIEnv *env, const char *pat) {
return 1;
}
jstring charTojstring(JNIEnv *env, char *chars) {
jclass strClass = env->FindClass("Ljava/lang/String;");
jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = env->NewByteArray(strlen(chars));
env->SetByteArrayRegion(bytes, 0, strlen(chars), (jbyte *) chars);
jstring encoding = env->NewStringUTF("utf-8");
return (jstring) env->NewObject(strClass, ctorID, bytes, encoding);
}
__attribute__((section (".mytext"))) static void nativeFaceDtrDestroy(JNIEnv *env, jobject thiz) {
//LOGW("facedtr_jni destroy");
sTaskId = -1;
}
__attribute__((section (".mytext"))) static int
nativeFaceDtrGetModelLength(JNIEnv *env, jobject thiz,
jstring name) {
if (name == NULL) {
//LOGE("clazz can't be null");
return -1;
}
char *clazzName = (char *) env->GetStringUTFChars(name, NULL);
int result = -2;
if (strlen(clazzName) == strlen(detectFeatureFromPicClazz) &&
memcmp(clazzName, detectFeatureFromPicClazz, strlen(detectFeatureFromPicClazz)) == 0) {
result = sizeof(xxx_xxx_mobile2movi_pic_bytes);
} else if (strlen(clazzName) == strlen(faceServiceNotificationClazz) &&
memcmp(clazzName, faceServiceNotificationClazz,
strlen(faceServiceNotificationClazz)) == 0) {
result = sizeof(xx_xxx_movi2mobile_notification_t);
}
env->ReleaseStringChars(name, (const jchar *) clazzName);
env->DeleteLocalRef(name);
return result;
}
__attribute__((section (".mytext"))) static jbyteArray
nativeFaceDtrInitParamter(JNIEnv *env, jobject thiz, jobject paramter) {
xxx_xxx_initialzation_paramter_t *initParamter = (xxx_xxx_initialzation_paramter_t *) malloc(
sizeof(xxx.xxx_initialzation_paramter_t));
jbyteArray jbyteArray1 = env->NewByteArray(sizeof(xxx.xxx_initialzation_paramter_t));
//Getting class have two method :
jclass jParamsCls = env->GetObjectClass(paramter);
//parse taskId
jfieldID taskIdTypeField = env->GetFieldID(jParamsCls, "taskId", "J");
uint64_t taskId = env->GetLongField(paramter, taskIdTypeField);
sTaskId = taskId;
initParamter->taskId = taskId;
// //LOGW("initParamter->taskId = %ld,sTaskId = %ld ", initParamter->taskId,sTaskId);
//parse ServiceType
jfieldID serviceTypeField = env->GetFieldID(jParamsCls, "serviceType", "I");
uint16_t serviceType = env->GetIntField(paramter, serviceTypeField);
// //LOGW("serviceType = %d ", serviceType);
initParamter->serviceType = (service_type) serviceType;
//parse multipleFaceDetectDelayTime
jfieldID multipleFaceDetectDelayTimeField = env->GetFieldID(jParamsCls,
"multipleFaceDetectDelayTime", "I");
uint16_t multipleFaceDetectDelayTime = env->GetIntField(paramter,
multipleFaceDetectDelayTimeField);
initParamter->multipleFaceDetectDelayTime = multipleFaceDetectDelayTime;
//解析Java Object对象
jfieldID areaFiledId = env->GetFieldID(jParamsCls, "area",
"Lcom/xxx/xxx/xxx/model/Area;");
//it works
// jfieldID areaFiledId = env->GetFieldID(jParamsCls,"area","com/xxx/glass3/sdk/facedtr/Area");
jobject areaObj = env->GetObjectField(paramter, areaFiledId);
jclass areaClass = env->FindClass("com/xxx/xxx/xxx/model/Area");
jfieldID leftFiledId = env->GetFieldID(areaClass, "left", "I");
jfieldID topFiledId = env->GetFieldID(areaClass, "top", "I");
jfieldID rightFiledId = env->GetFieldID(areaClass, "right", "I");
jfieldID bottomFiledId = env->GetFieldID(areaClass, "bottom", "I");
uint16_t left = env->GetIntField(areaObj, leftFiledId);
uint16_t top = env->GetIntField(areaObj, topFiledId);
uint16_t right = env->GetIntField(areaObj, rightFiledId);
uint16_t bottom = env->GetIntField(areaObj, bottomFiledId);
// //LOGW("(left,top),(right,bottom)-> (%d,%d),(%d,%d)", left, top, right, bottom);
area_t a;
a.left = left;
a.top = top;
a.right = right;
a.bottom = bottom;
initParamter->area = a;
//parse detect discrimatorn
jfieldID detectDiscrimatornField = env->GetFieldID(jParamsCls, "detectDiscrimatorn",
"Lcom/xxx/xxx/xxx/model/DetectThreshold;");
jobject detectDiscrimatornObj = env->GetObjectField(paramter, detectDiscrimatornField);
// jclass detectDiscrimatornClz = env->FindClass("com/xxx/glass3/sdk/facedtr/DetectThreshold");
jclass detectDiscrimatornClz = env->GetObjectClass(detectDiscrimatornObj);
jfieldID minDetectWidthField = env->GetFieldID(detectDiscrimatornClz, "minDetectWidth", "I");
jfieldID countOfFastField = env->GetFieldID(detectDiscrimatornClz, "countOfFast", "I");
jfieldID yawField = env->GetFieldID(detectDiscrimatornClz, "yaw", "I");
uint16_t minDetectWidth = env->GetIntField(detectDiscrimatornObj, minDetectWidthField);
uint16_t countOfFast = env->GetIntField(detectDiscrimatornObj, countOfFastField);
uint16_t yaw = env->GetIntField(detectDiscrimatornObj, yawField);
detect_discrimator_t detect_discrimator1;
detect_discrimator1.yaw = yaw;
detect_discrimator1.minDetectWidth = minDetectWidth;
detect_discrimator1.countOfFast = countOfFast;
initParamter->detectDiscrimatorn = detect_discrimator1;
// //LOGW("coutOfFast = %d, yaw = %d, minDetectWidthField = %d ", countOfFast, yaw, minDetectWidth);
//parse detectResultType
jfieldID detectResultTypeFiled = env->GetFieldID(jParamsCls, "detectResultType", "I");
uint16_t detectResultType = env->GetIntField(paramter, detectResultTypeFiled);
initParamter->detectResultType = (detect_result_type) detectResultType;
// //LOGW("detectResultType = %d", detectResultType);
//parse indicatorColorSize
jfieldID indicatorColorSizeFiled = env->GetFieldID(jParamsCls, "indicatorColorSize", "I");
uint16_t indicatorColorSize = env->GetIntField(paramter, indicatorColorSizeFiled);
initParamter->indicatorColorSize = indicatorColorSize;
// //LOGW("indicatorColorSize = %d", indicatorColorSize);
//parse indicatorColors
if (indicatorColorSize != 0) {
jfieldID indicatorColorsField = env->GetFieldID(jParamsCls, "indicatorColors",
"[Lcom/xxx/xxx/xxx/model/IndicatorColor;");
jobjectArray indicatorColorArrayObj = (jobjectArray) env->GetObjectField(paramter,
indicatorColorsField);
// //LOGD("数组长度:%d", env->GetArrayLength(indicatorColorArrayObj));
for (int i = 0; i < indicatorColorSize; i++) {
jobject indicatorColorObj = env->GetObjectArrayElement(indicatorColorArrayObj, i);
jclass indicatorClz = env->GetObjectClass(indicatorColorObj);
jfieldID indicatorColorSizeFiled = env->GetFieldID(indicatorClz, "state", "I");
uint16_t state = env->GetIntField(indicatorColorObj, indicatorColorSizeFiled);
indicator_color_t indicatorColor;
indicatorColor.state = (face_track_phase) state;
jfieldID indicatorColorFiled = env->GetFieldID(indicatorClz, "color", "I");
uint16_t color = env->GetIntField(indicatorColorObj, indicatorColorFiled);
indicatorColor.color = color;
initParamter->indicatorColors[i] = indicatorColor;
env->DeleteLocalRef(indicatorClz);
env->DeleteLocalRef(indicatorColorObj);
}
env->DeleteLocalRef(indicatorColorArrayObj);
// //LOGW("状态对应颜色值结束了");
}
//parse Camera width and height
jfieldID jfieldIDCameraWidth = env->GetFieldID(jParamsCls, "cameraPreviewWidth", "I");
uint16_t cameraWidth = env->GetIntField(paramter, jfieldIDCameraWidth);
initParamter->cameraPreviewWidth = cameraWidth;
jfieldID jfieldIDCameraHeight = env->GetFieldID(jParamsCls, "cameraPreviewheight", "I");
uint16_t cameraHeight = env->GetIntField(paramter, jfieldIDCameraHeight);
initParamter->cameraPreviewHeight = cameraHeight;
// //LOGW("paramter cameraWidth = %dpx,cameraHeight = %dpx", cameraWidth, cameraHeight);
env->SetByteArrayRegion(jbyteArray1, 0, sizeof(xxx.xxx_initialzation_paramter_t),
(const jbyte *) initParamter);
free(initParamter);
initParamter = NULL;
env->DeleteLocalRef(jParamsCls);
env->DeleteLocalRef(areaObj);
env->DeleteLocalRef(areaClass);
env->DeleteLocalRef(detectDiscrimatornObj);
env->DeleteLocalRef(detectDiscrimatornClz);
// //LOGW("convert paramters to byte[] len:%d",env->GetArrayLength(jbyteArray1));
return jbyteArray1;
}
__attribute__((section (".mytext"))) static void
nativeParseFaceNotificationCallback(JNIEnv *env, jobject thiz, jbyteArray array, jobject callback) {
// jbyte *raw_msg = env->GetByteArrayElements(array, 0);
jclass clazz = env->GetObjectClass(callback);
jmethodID faceNotificationCallbackMethodId = env->GetMethodID(clazz,
"onFaceNotificationCallback",
"(Lcom/xxx/xxx/xxx/model/FaceServiceNotification;)V");
jbyte *data = env->GetByteArrayElements(array, NULL);
int arrayLength = env->GetArrayLength(array);
jbyte *raw_msg = (jbyte *) malloc(arrayLength);
if (data != NULL) {
memcpy(raw_msg, data, arrayLength);
env->ReleaseByteArrayElements(array, data, JNI_ABORT);
env->DeleteLocalRef(array);
}
xxx.xxx_movi2mobile_notification_t *notification = (xxx_xxx_movi2mobile_notification_t *) raw_msg;
if (sTaskId != notification->taskId) {
//LOGE("两次TaskID不相同 sTaskID = %ld,last taskId = %ld ", sTaskId, notification->taskId);
if (notification->notificationType == 3) { //detect face from pic
env->CallVoidMethod(callback, faceNotificationCallbackMethodId, NULL);
}
free(raw_msg);
raw_msg = NULL;
notification = NULL;
env->DeleteLocalRef(clazz);
return;
}
const uint8_t *src = notification->resultData;
uint8_t *dest = (uint8_t *) malloc(FRAME_YUV_LEN);
const int yLen = 1280 * 720;
const int vLen = yLen / 4;
memcpy(dest, notification->resultData, yLen);//Y data
for (int i = 0; i < vLen; i++) {
dest[yLen + 2 * i] = src[yLen + i];//V data
dest[yLen + 2 * i + 1] = src[yLen + vLen + i];//U data
}
uint8_t *features = notification->features;
int notificationType = notification->notificationType;
if (LIKELY(clazz)) {
//get hid method ID
// //LOGE("faceNotificationCallbackMethodId");
jclass faceServiceNotificationClazz = env->FindClass(
"com/xxx/xxx.xxx/model/FaceServiceNotification");
// //LOGE("faceServiceNotificationClazz");
//new FaceServiceNotification
if (LIKELY(faceServiceNotificationClazz)) {
jmethodID hid_method_creator = env->GetMethodID(faceServiceNotificationClazz, "<init>",
"(I[BLjava/util/ArrayList;[B)V");
//construct arealist
jclass list_cls = env->FindClass("java/util/ArrayList");//获得ArrayList类引用
// //LOGW("Get ArrayList class");
jmethodID list_costruct = env->GetMethodID(list_cls, "<init>", "()V"); //获得得构造函数Id
jobject areaArrayList = env->NewObject(list_cls, list_costruct); //创建一个Arraylist集合对象
// //LOGW("create ArrayList instance areaArrayList");
//或得Arraylist类中的 add()方法ID,其方法原型为: boolean add(Object object) ;
jmethodID list_add = env->GetMethodID(list_cls, "add", "(Ljava/lang/Object;)Z");
jclass areaClz = env->FindClass("com/xxx/xxx/xxx/model/Area");
for (int i = 0; i < notification->areasize; ++i) {
area_t area1 = notification->area[i];
jmethodID area_method_creator = env->GetMethodID(areaClz, "<init>", "(IIII)V");
jobject areaObj = env->NewObject(areaClz, area_method_creator, area1.left,
area1.top,
area1.right + area1.left,
area1.bottom + area1.top);
//执行Arraylist类实例的add方法,添加一个Area对象
env->CallBooleanMethod(areaArrayList, list_add, areaObj);
}
env->DeleteLocalRef(list_cls);
env->DeleteLocalRef(areaClz);
jbyteArray notificationData = env->NewByteArray(FRAME_YUV_LEN);
env->SetByteArrayRegion(notificationData, 0, FRAME_YUV_LEN, (const jbyte *) dest);
// jbyteArray featureData = env->NewByteArray(FEATURES_LEN);
// env->SetByteArrayRegion(featureData, 0, FEATURES_LEN, (const jbyte *) features);
//归一化后的数据
jbyteArray featureData = normalizeFeatures2(env, (jbyte *) features, FEATURES_LEN);
jobject hidInfoObj = env->NewObject(faceServiceNotificationClazz, hid_method_creator,
notificationType, notificationData,
areaArrayList, featureData);
env->CallVoidMethod(callback, faceNotificationCallbackMethodId, hidInfoObj);
env->DeleteLocalRef(notificationData);
env->DeleteLocalRef(areaArrayList);
env->DeleteLocalRef(featureData);
env->DeleteLocalRef(hidInfoObj);
}
env->DeleteLocalRef(faceServiceNotificationClazz);
}
env->DeleteLocalRef(clazz);
notification = NULL;
if (raw_msg != NULL) {
free(raw_msg);
raw_msg = NULL;
}
if (LIKELY(dest)) {
free(dest);
dest = NULL;
}
env->DeleteLocalRef(array);
src = NULL;
env->DeleteLocalRef(callback);
}
__attribute__((section (".mytext"))) static jobject
nativeParseFaceServiceNotification(JNIEnv *env, jobject thiz, jbyteArray array) {
//LOGW("nativeParseFaceServiceNotification");
jbyte *data = env->GetByteArrayElements(array, NULL);
int arrayLength = env->GetArrayLength(array);
jbyte *raw_msg = (jbyte *) malloc(arrayLength);
if (data != NULL) {
memcpy(raw_msg, data, arrayLength);
env->ReleaseByteArrayElements(array, data, JNI_ABORT);
env->DeleteLocalRef(array);
}
jobject faceServerNotificationObj = NULL;
xxx.xxx_movi2mobile_notification_t *notification = (xxx.xxx_movi2mobile_notification_t *) raw_msg;
if (sTaskId != notification->taskId) {
//LOGE("different taskID taskID1 = %ld,last taskId2 = %ld ", sTaskId, notification->taskId);
free(raw_msg);
raw_msg = NULL;
notification = NULL;
return faceServerNotificationObj;
}
const uint8_t *src = notification->resultData;
uint8_t *dest = (uint8_t *) malloc(FRAME_YUV_LEN);
const int yLen = 1280 * 720;
const int vLen = yLen / 4;
memcpy(dest, notification->resultData, yLen);//Y data
for (int i = 0; i < vLen; i++) {
dest[yLen + 2 * i] = src[yLen + i];//V data
dest[yLen + 2 * i + 1] = src[yLen + vLen + i];//U data
}
uint8_t *features = notification->features;
int notificationType = notification->notificationType;
jclass faceServiceNotificationClazz = env->FindClass(
"com/xxx/xxx.xxx/model/FaceServiceNotification");
//new FaceServiceNotification
jmethodID hid_method_creator = env->GetMethodID(faceServiceNotificationClazz, "<init>",
"(I[BLjava/util/ArrayList;[B)V");
//construct arealist
jclass list_cls = env->FindClass("java/util/ArrayList");//获得ArrayList类引用
// //LOGW("Get ArrayList class");
jmethodID list_costruct = env->GetMethodID(list_cls, "<init>", "()V"); //获得得构造函数Id
jobject areaArrayList = env->NewObject(list_cls, list_costruct); //创建一个Arraylist集合对象
// //LOGW("create ArrayList instance areaArrayList");
//或得Arraylist类中的 add()方法ID,其方法原型为: boolean add(Object object) ;
jmethodID list_add = env->GetMethodID(list_cls, "add", "(Ljava/lang/Object;)Z");
jclass areaClz = env->FindClass("com/xxx/xxx.xxx/model/Area");
for (int i = 0; i < notification->areasize; ++i) {
area_t area1 = notification->area[i];
jmethodID area_method_creator = env->GetMethodID(areaClz, "<init>", "(IIII)V");
jobject areaObj = env->NewObject(areaClz, area_method_creator, area1.left,
area1.top,
area1.right + area1.left,
area1.bottom + area1.top);
//执行Arraylist类实例的add方法,添加一个Area对象
env->CallBooleanMethod(areaArrayList, list_add, areaObj);
}
env->DeleteLocalRef(list_cls);
env->DeleteLocalRef(areaClz);
jbyteArray notificationData = env->NewByteArray(FRAME_YUV_LEN);
env->SetByteArrayRegion(notificationData, 0, FRAME_YUV_LEN, (const jbyte *) dest);
// jbyteArray featureData = env->NewByteArray(FEATURES_LEN);
// env->SetByteArrayRegion(featureData, 0, FEATURES_LEN, (const jbyte *) features);
//归一化后的数据
jbyteArray featureData = normalizeFeatures2(env, (jbyte *) features, FEATURES_LEN);
faceServerNotificationObj = env->NewObject(faceServiceNotificationClazz, hid_method_creator,
notificationType, notificationData,
areaArrayList, featureData);
env->DeleteLocalRef(notificationData);
env->DeleteLocalRef(areaArrayList);
env->DeleteLocalRef(featureData);
env->DeleteLocalRef(faceServiceNotificationClazz);
notification = NULL;
if (raw_msg != NULL) {
free(raw_msg);
raw_msg = NULL;
}
if (LIKELY(dest)) {
free(dest);
dest = NULL;
}
env->DeleteLocalRef(array);
src = NULL;
return faceServerNotificationObj;
}
__attribute__((section (".mytext"))) static jbyteArray nativeGetFace(JNIEnv *env, jobject thiz,
jint dataType, jint size,
jint width, jint height,
jbyteArray bytes_) {
// //LOGW("facedtr_jni nativeGetFace");
xxx.xxx_mobile2movi_pic_bytes_t *mobile2moviPicBytes = (xxx_xxx_mobile2movi_pic_bytes_t *) malloc(
sizeof(xxx.xxx_mobile2movi_pic_bytes));
mobile2moviPicBytes->dataType = dataType;
mobile2moviPicBytes->size = size;
mobile2moviPicBytes->pic_width = width;
mobile2moviPicBytes->pic_height = height;
jint len = 0;
if (bytes_ != NULL) {
len = env->GetArrayLength(bytes_);
}
jbyteArray jbyteArray1 = env->NewByteArray(sizeof(xxx.xxx_mobile2movi_pic_bytes));
if (len > 0) {
jboolean isCopy;
jbyte *bytes = env->GetByteArrayElements(bytes_, &isCopy);
memcpy(mobile2moviPicBytes->bytes, bytes, len);
}
env->SetByteArrayRegion(jbyteArray1, 0, sizeof(xxx.xxx_mobile2movi_pic_bytes),
(const jbyte *) mobile2moviPicBytes);
free(mobile2moviPicBytes);
mobile2moviPicBytes = NULL;
// //LOGW("%d,%d",env->GetArrayLength(jbyteArray1), sizeof(*mobile2moviPicBytes));
return jbyteArray1;
}
__attribute__((section (".mytext"))) static jbyteArray
normalizeFeatures(JNIEnv *env, jobject thiz, jbyteArray feature_) {
jbyte *feature = env->GetByteArrayElements(feature_, NULL);
jbyteArray result = normalizeFeatures2(env, feature, 1024);
if (feature != NULL) {
env->ReleaseByteArrayElements(feature_, feature, JNI_ABORT);
env->DeleteLocalRef(feature_);
feature = NULL;
}
return result;
}
static jbyteArray normalizeFeatures2(JNIEnv *env, jbyte *feature, int len) {
//sto(env, KEY2);
float norm_feature[256];
float temp[512];
for (int i = 0; i < 512; i++) {
temp[i] = f16Tof32(*(unsigned int *) ((unsigned short *) feature + i));
}
const float *ptr = temp;
float sum = 0.0;
for (int i = 0; i < 512; i++) {
float num = *ptr++;
sum += num * num;
}
sum = sqrtf(sum);
ptr = temp;
float sum2 = 0;
for (int i = 0; i < 512; i++) {
temp[i] = *ptr++ / sum;
}
for (int i = 0; i < 256; i++) {
unsigned int x1 = f32Tof16(temp[i * 2]);
unsigned int x2 = f32Tof16(temp[i * 2 + 1]);
unsigned int x = x2 << 16 | x1;
norm_feature[i] = *(float *) &x;
}
jbyteArray result = env->NewByteArray(1024);
env->SetByteArrayRegion(result, 0, 1024, (jbyte *) norm_feature);
return result;
}
//**********************************************************************
//
//**********************************************************************
jint registerNativeMethods(JNIEnv *env, const char *class_name, JNINativeMethod *methods,
int num_methods) {
int result = 0;
jclass clazz = env->FindClass(class_name);
if (LIKELY(clazz)) {
int result = env->RegisterNatives(clazz, methods, num_methods);
if (UNLIKELY(result < 0)) {
//LOGD("registerNativeMethods failed(class=%s)", class_name);
}
} else {
//LOGD("registerNativeMethods: class'%s' not found", class_name);
}
return result;
}
static JNINativeMethod methods[] = {
{"nativeFaceDtrDestroy", "()V", (void *) nativeFaceDtrDestroy},
{"nativeFaceDtrInitParamter", "(Lcom/xxx/xxx/xxx/model/FaceInitParamter;)[B", (void *) nativeFaceDtrInitParamter},
{"nativeGetFace", "(IIII[B)[B", (void *) nativeGetFace},
{"normalizeFeatures", "([B)[B", (void *) normalizeFeatures},
{"nativeParseFaceNotificationCallback", "([BLcom/xxx/xxx/xxx/glxss/security/listener/IOnFaceNotificationCallback;)V", (void *) nativeParseFaceNotificationCallback},
{"nativeParseFaceServiceNotification", "([B)Lcom/xxx/xxx/xxx/model/FaceServiceNotification;", (void *) nativeParseFaceServiceNotification},
{"nativeFaceDtrGetModelLength", "(Ljava/lang/String;)I", (void *) nativeFaceDtrGetModelLength},
};
int register_libFaceDtr(JNIEnv *env) {
//LOGI("register_libfacedtr:");
if (registerNativeMethods(env,
"com/xxx/xxx/xxx/glxss/FaceDtr",
methods, NUM_ARRAY_ELEMENTS(methods)) < 0) {
return -1;
}
return 0;
}