#include #include #include #include "AndroidOut.h" #include "FaceApp.h" #include #include #include using namespace std; extern "C" { android_app* g_android_app = nullptr; FaceApp* g_Application = nullptr; AAssetManager* g_assetManager = nullptr; jobject g_callback = nullptr; jobject g_callbackAnimationFinished = nullptr; void handle_cmd(android_app *pApp, int32_t cmd) { switch (cmd) { case APP_CMD_INIT_WINDOW: aout << "APP_CMD_INIT_WINDOW" << std::endl; g_Application->initVulkan(); break; case APP_CMD_TERM_WINDOW: aout << "APP_CMD_TERM_WINDOW" << std::endl; break; default: break; } } const int ArgLen = 128*1024; char g_InitArgString[ArgLen] = {0}; void android_main(struct android_app *pApp) { aout << "Welcome to android_main" << std::endl; g_android_app = pApp; g_assetManager = pApp->activity->assetManager; FaceApp application; g_Application = &application; application.SetInitArg(g_InitArgString); pApp->onAppCmd = handle_cmd; long long last_update_time = 0; android_app_set_motion_event_filter(pApp, nullptr); long long _lastDrawFrameTime = chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); do { auto start_time = chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); // Process all pending events before running game logic. bool done = false; while (!done) { int timeout = 0; int events; android_poll_source *pSource; int result = ALooper_pollOnce(timeout, nullptr, &events, reinterpret_cast(&pSource)); switch (result) { case ALOOPER_POLL_TIMEOUT: [[clang::fallthrough]]; case ALOOPER_POLL_WAKE: // No events occurred before the timeout or explicit wake. Stop checking for events. done = true; break; case ALOOPER_EVENT_ERROR: aout << "ALooper_pollOnce returned an error" << std::endl; break; case ALOOPER_POLL_CALLBACK: break; default: if (pSource) { pSource->process(pApp, pSource); } } } if(application.isInited()) { auto frameTime = (start_time - _lastDrawFrameTime); _lastDrawFrameTime = chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); application.drawFrame(frameTime); } auto end_time = chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count(); auto frameTime = end_time - last_update_time; last_update_time = end_time; auto function_time = (end_time - start_time); //aout << "function_time:" << function_time << " fps:" << (1000/frameTime) << std::endl; if(function_time < 35) { this_thread::sleep_for(chrono::milliseconds((35-function_time))); } } while (!pApp->destroyRequested); application.cleanup(); } } extern void TextureLoadProcessWithVulkan(uint8_t* data, int width, int height, int rowStride, size_t dataSize); extern void ReceiveFacePoint(float* pos, int count, int width, int height); void processWithVulkan(uint8_t* data, int width, int height, int format, int rowStride, size_t dataSize) { TextureLoadProcessWithVulkan(data, width, height, rowStride, dataSize); } extern "C" JNIEXPORT void JNICALL Java_com_hmwl_face_1sdk_FaceActivity_processImageNative(JNIEnv *env, jobject thiz, jobject buffer, jint width, jint height, jint format, jint row_stride, jint pixel_stride, jint rotation) { // TODO: implement processImageNative() uint8_t* imageData = static_cast(env->GetDirectBufferAddress(buffer)); jlong capacity = env->GetDirectBufferCapacity(buffer); if (imageData == nullptr) { return; } // 在这里将图像数据传递给 Vulkan // 创建 Vulkan 图像或更新现有图像 processWithVulkan(imageData, width, height, format, row_stride, capacity); } extern "C" JNIEXPORT void JNICALL Java_com_hmwl_face_1sdk_FaceActivity_passDataToNative(JNIEnv *env, jobject thiz, jobject buffer, jint point_count, jint width, jint height) { // TODO: implement passDataToNative() float* pos = static_cast(env->GetDirectBufferAddress(buffer)); if (pos == nullptr) { // 处理错误 return; } // 或者直接将指针传递给Vulkan ReceiveFacePoint(pos, point_count, width, height); } extern "C" JNIEXPORT void JNICALL Java_com_hmwl_face_1sdk_FaceActivity_SetCppInitArg(JNIEnv *env, jobject thiz, jstring json) { // TODO: implement SetCppInitArg() const char *nativeString = env->GetStringUTFChars(json, nullptr); jsize len = env->GetStringUTFLength(json); if(len > ArgLen) { aout << "ArgLen to long:" << len << std::endl; return; } memcpy(g_InitArgString, nativeString, len); } extern "C" JNIEXPORT void JNICALL Java_com_hmwl_face_1sdk_FaceActivity_StopRunning(JNIEnv *env, jobject thiz) { g_Application->_running = false; } JavaVM* g_jvm = nullptr; // 添加 JNI_OnLoad 函数 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) { g_jvm = vm; // 保存 JavaVM 指针,供其他线程使用 return JNI_VERSION_1_6; } void CppCallback(const string& motion_type) { JNIEnv* env = nullptr; bool needDetach = false; // 获取当前线程的 JNIEnv JavaVM* vm = g_jvm; // 你需要提前保存 JavaVM* 到全局变量 g_jvm int status = vm->GetEnv((void**)&env, JNI_VERSION_1_6); if (status == JNI_EDETACHED) { // 当前线程未 attach,需 attach if (vm->AttachCurrentThread(&env, nullptr) != 0) { return; } needDetach = true; } else if (status != JNI_OK) { return; } if (g_callback == nullptr) { if (needDetach) vm->DetachCurrentThread(); return; } // 1. 获取 CallbackInterface 的 class jclass callbackClass = env->GetObjectClass(g_callback); if (callbackClass == nullptr) { if (needDetach) vm->DetachCurrentThread(); return; } // 2. 获取 OnLoadActionFinished 方法 ID(注意方法名大小写必须一致!) jmethodID methodId = env->GetMethodID(callbackClass, "OnLoadActionFinished", "(Ljava/lang/String;)V"); if (methodId == nullptr) { env->ExceptionDescribe(); // 打印异常 env->ExceptionClear(); if (needDetach) vm->DetachCurrentThread(); return; } // 3. 构造 jstring 参数 jstring jResult = env->NewStringUTF(motion_type.c_str()); // 4. 调用 Java 回调 env->CallVoidMethod(g_callback, methodId, jResult); // 5. 检查是否抛出异常 if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); } // 6. 释放局部引用(可选,但推荐) env->DeleteLocalRef(jResult); env->DeleteLocalRef(callbackClass); // 7. 如果是临时 attach 的线程,要 detach if (needDetach) { vm->DetachCurrentThread(); } } void CppAnimationFinishedCallback() { JNIEnv* env = nullptr; bool needDetach = false; // 获取当前线程的 JNIEnv JavaVM* vm = g_jvm; // 你需要提前保存 JavaVM* 到全局变量 g_jvm int status = vm->GetEnv((void**)&env, JNI_VERSION_1_6); if (status == JNI_EDETACHED) { // 当前线程未 attach,需 attach if (vm->AttachCurrentThread(&env, nullptr) != 0) { return; } needDetach = true; } else if (status != JNI_OK) { return; } if (g_callbackAnimationFinished == nullptr) { if (needDetach) vm->DetachCurrentThread(); return; } // 1. 获取 CallbackInterface 的 class jclass callbackClass = env->GetObjectClass(g_callbackAnimationFinished); if (callbackClass == nullptr) { if (needDetach) vm->DetachCurrentThread(); return; } // 2. 获取 OnLoadActionFinished 方法 ID(注意方法名大小写必须一致!) jmethodID methodId = env->GetMethodID(callbackClass, "OnAnimationFinished", "()V"); if (methodId == nullptr) { env->ExceptionDescribe(); // 打印异常 env->ExceptionClear(); if (needDetach) vm->DetachCurrentThread(); return; } // 4. 调用 Java 回调 env->CallVoidMethod(g_callbackAnimationFinished, methodId); // 5. 检查是否抛出异常 if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); } env->DeleteLocalRef(callbackClass); // 7. 如果是临时 attach 的线程,要 detach if (needDetach) { vm->DetachCurrentThread(); } } extern "C" JNIEXPORT jstring JNICALL Java_com_hmwl_face_1sdk_FaceActivity_PreReadAction(JNIEnv *env, jobject thiz, jstring motion, jobject callback) { // 清理旧的全局引用 if (g_callback != nullptr) { env->DeleteGlobalRef(g_callback); g_callback = nullptr; } // 保存新的回调 if (callback != nullptr) { g_callback = env->NewGlobalRef(callback); } else { g_callback = nullptr; } const char *nativeString = env->GetStringUTFChars(motion, nullptr); jsize len = env->GetStringUTFLength(motion); if(len > ArgLen) { aout << "ArgLen to long:" << len << std::endl; } std::string ret = g_Application->preReadyMotion(nativeString, CppCallback); return env->NewStringUTF(ret.c_str()); } extern "C" JNIEXPORT void JNICALL Java_com_hmwl_face_1sdk_FaceActivity_ChangeMotionCpp(JNIEnv *env, jobject thiz, jstring json, jobject callback, jboolean loop) { // TODO: implement ChangeMotionCpp() const char *nativeString = env->GetStringUTFChars(json, nullptr); jsize len = env->GetStringUTFLength(json); if(len > ArgLen) { aout << "ArgLen to long:" << len << std::endl; return; } // 保存新的回调 if (callback != nullptr) { g_callbackAnimationFinished = env->NewGlobalRef(callback); } else { g_callbackAnimationFinished = nullptr; } if(g_Application->isInited()) { g_Application->changeMotion(nativeString, CppAnimationFinishedCallback, loop); } }