32 Commits
Author SHA1 Message Date
xsl 7ab4274e4f 整理卡死的问题 2026-04-21 00:03:27 +08:00
xsl 5d8e108306 fix crash bug 2026-02-05 21:06:02 +08:00
xsl 52c9da08ed save code 2026-01-13 08:12:46 +08:00
xsl 496d56f9c6 save code 2026-01-08 21:52:28 +08:00
xsl 60b40bfd5f 添加圆心遮罩 2026-01-08 21:19:32 +08:00
xsl b44162e6cb 修改背景图为透明 2025-12-26 16:23:07 +08:00
xsl 6ef6e012bd save code 2025-12-24 21:01:14 +08:00
xsl f5b2d490c0 save code 2025-12-24 10:55:30 +08:00
xsl 4c5a05ae21 asdf 2025-12-24 10:20:53 +08:00
xsl 1f9e4939b9 修改为高分辨率 2025-12-22 15:55:43 +08:00
xsl c83f36c976 修复 动画播放 错误的bug 2025-12-22 14:55:00 +08:00
xsl 29e0c1e9a8 完成动画序列播放 2025-12-22 00:40:45 +08:00
xsl 7b07e7fbc1 save code 2025-12-20 22:34:23 +08:00
xsl b6ac86a134 save code 2025-12-19 18:55:44 +08:00
xsl 6bbbb3c3ef save code 2025-12-19 13:47:16 +08:00
xsl e38da96e37 save code 2025-12-18 22:05:10 +08:00
xsl 9ee028248d save code 2025-12-17 22:58:30 +08:00
xsl 84cc693593 保存代码 2025-12-16 22:15:42 +08:00
xsl 4cf1990b16 save code 2025-12-12 10:27:49 +08:00
xsl 2130cf0e6b save 2025-12-12 09:58:03 +08:00
xsl 6717047d1d save code 2025-12-12 09:49:56 +08:00
xsl da2c97e412 修改检测参数,降低置信度,提高检测的延时 2025-12-06 11:59:00 +08:00
xsl db80a5dbbd asdf 2025-12-02 20:36:32 +08:00
xsl 634d22f3be 完成动画切换 2025-11-30 12:22:43 +08:00
xsl 835f768a4a 基本调通 回调 2025-11-29 23:44:22 +08:00
xsl 1859706412 优化内存读取 2025-11-29 11:35:56 +08:00
xsl 9c71e40c97 新版本f1118 更新图片 修复_running bug 2025-11-17 22:36:59 +08:00
xsl 84d567674f 化妆切换完成 2025-11-12 15:13:55 +08:00
xsl 43b00c8446 添加是否运行的标致 2025-11-12 15:05:31 +08:00
xsl e23ccd75cd 清理所有资源,有两处内存泄漏,暂时找不到了 2025-11-12 15:03:15 +08:00
xsl 8623b71ab7 总算是编译通过了 2025-11-12 10:53:41 +08:00
xsl 16efcbcff3 现在才真的能打包正确的 aar 2025-11-09 10:25:43 +08:00
673 changed files with 6947 additions and 2937 deletions
+35 -15
View File
@@ -1,7 +1,8 @@
plugins { plugins {
//alias(libs.plugins.android.application) //alias(libs.plugins.android.application)
alias(libs.plugins.android.library) alias(libs.plugins.android.library)
id 'org.jetbrains.kotlin.android' alias(libs.plugins.kotlin.android)
//id 'org.jetbrains.kotlin.android'
} }
ext.vvl_version='1.4.321.0' ext.vvl_version='1.4.321.0'
@@ -30,6 +31,17 @@ android {
debug { debug {
debuggable true debuggable true
jniDebuggable true jniDebuggable true
externalNativeBuild {
cmake {
arguments "-DCMAKE_BUILD_TYPE=Debug"
cppFlags "-DDEBUG -O0 -g"
}
}
ndk {
debugSymbolLevel 'FULL' // Debug 版本包含完整符号
}
} }
release { release {
@@ -43,13 +55,13 @@ android {
} }
// 添加 Kotlin 编译选项 // 添加 Kotlin 编译选项
kotlinOptions { // kotlinOptions {
jvmTarget = '17' // 与 Java 版本保持一致 // jvmTarget = '17' // 与 Java 版本保持一致
} // }
kotlin { // kotlin {
jvmToolchain(21) // jvmToolchain(17)
} // }
buildFeatures { buildFeatures {
prefab true prefab true
@@ -62,10 +74,10 @@ android {
'libs/tasks-vision/jni', 'libs/tasks-vision/jni',
'libs/tasks-core/jni' 'libs/tasks-core/jni'
] ]
java.srcDirs += [ //java.srcDirs += [
'libs/tasks-vision/vision_classes', // 'libs/tasks-vision/vision_classes',
'libs/tasks-core/core_classes' // 'libs/tasks-core/core_classes'
] //]
res.srcDirs += [ res.srcDirs += [
'libs/tasks-vision/res', 'libs/tasks-vision/res',
'libs/tasks-core/res' 'libs/tasks-core/res'
@@ -79,6 +91,13 @@ android {
version '3.22.1' version '3.22.1'
} }
} }
packagingOptions {
pickFirst '**/*.jar'
}
kotlinOptions {
jvmTarget = '17'
}
} }
dependencies { dependencies {
@@ -86,16 +105,17 @@ dependencies {
implementation libs.appcompat implementation libs.appcompat
implementation libs.material implementation libs.material
implementation libs.games.activity implementation libs.games.activity
implementation libs.androidx.core.core.ktx
testImplementation libs.junit testImplementation libs.junit
androidTestImplementation libs.ext.junit androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core androidTestImplementation libs.espresso.core
//implementation 'com.google.protobuf:protobuf-javalite:3.21.12' implementation 'com.google.protobuf:protobuf-javalite:3.21.12'
//implementation files('libs/tasks-vision.jar', 'libs/tasks-core.jar') implementation files('libs/tasks-vision.jar', 'libs/tasks-core.jar')
implementation fileTree(dir: 'libs/tasks-vision', include: ['*.jar']) //implementation fileTree(dir: 'libs/tasks-vision', include: ['*.jar'])
implementation fileTree(dir: 'libs/tasks-core', include: ['*.jar']) //implementation fileTree(dir: 'libs/tasks-core', include: ['*.jar'])
def camerax_version = '1.4.2' def camerax_version = '1.4.2'
Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

+26
View File
@@ -9,7 +9,33 @@ layout(location = 0) out vec4 outColor;
// 纹理采样器 // 纹理采样器
layout(binding = 0) uniform sampler2D texSampler; layout(binding = 0) uniform sampler2D texSampler;
layout(push_constant) uniform PushConstants {
float zoom;
float r;
float g;
float b;
float radius;
float ux;
float uy;
} pushConstants;
void main() { void main() {
// outFragColor = color;
// 获取当前片元的屏幕坐标(左下角为原点)
vec2 fragCoord = gl_FragCoord.xy;
// 屏幕中心(480x480 的中心是 (240, 240)
vec2 center = vec2(240.0, 240.0);
// 计算到中心的距离(欧氏距离,单位:像素)
float dist = length(fragCoord - center);
// 判断是否在半径之外
if (dist > pushConstants.radius) {
// 使用 push constant 中的 RGB 颜色(注意 alpha 设为 1.0
outColor = vec4(pushConstants.r, pushConstants.g, pushConstants.b, 1.0);
} else {
// 采样纹理 // 采样纹理
outColor = texture(texSampler, inTexCoord); outColor = texture(texSampler, inTexCoord);
}
} }
Binary file not shown.
+12 -2
View File
@@ -38,7 +38,15 @@ const vec2 texCoords[6] = vec2[6](
// 定义 Push Constant,只有一个 float // 定义 Push Constant,只有一个 float
layout(push_constant) uniform PushConstants { layout(push_constant) uniform PushConstants {
float myValue; float zoom;
float r;
float g;
float b;
float radius;
float ux;
float uy;
float offset_x;
float offset_y;
} pushConstants; } pushConstants;
@@ -48,7 +56,9 @@ layout(location = 0) out vec2 outTexCoord;
void main() { void main() {
// 获取顶点位置 // 获取顶点位置
vec2 position = positions[gl_VertexIndex]; vec2 position = positions[gl_VertexIndex];
position = position * pushConstants.myValue; position = position * pushConstants.zoom;
position.x = position.x + (pushConstants.offset_x/480);
position.y = position.y + (pushConstants.offset_y/480);
// 设置输出位置(Vulkan使用不同的坐标系) // 设置输出位置(Vulkan使用不同的坐标系)
gl_Position = vec4(position, 0.0, 1.0); gl_Position = vec4(position, 0.0, 1.0);
Binary file not shown.
+28 -1
View File
@@ -5,13 +5,40 @@ layout (binding = 1) uniform sampler2D samplerColor;
layout (location = 0) in vec2 inUV; layout (location = 0) in vec2 inUV;
layout (location = 1) in vec3 inNormal; layout (location = 1) in vec3 inNormal;
layout(push_constant) uniform PushConstants {
float zoom;
float r;
float g;
float b;
float radius;
float ux;
float uy;
} pushConstants;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
void main() void main()
{ {
vec4 color = texture(samplerColor, inUV); // outFragColor = color;
// 获取当前片元的屏幕坐标(左下角为原点)
vec2 fragCoord = gl_FragCoord.xy;
// 屏幕中心(480x480 的中心是 (240, 240)
vec2 center = vec2(240.0, 240.0);
// 计算到中心的距离(欧氏距离,单位:像素)
float dist = length(fragCoord - center);
// 判断是否在半径之外
if (dist > pushConstants.radius) {
// 使用 push constant 中的 RGB 颜色(注意 alpha 设为 1.0
outFragColor = vec4(pushConstants.r, pushConstants.g, pushConstants.b, 1.0);
} else {
vec2 pos = vec2(pushConstants.ux/4096.f, pushConstants.uy/2048.f);
vec2 uv = pos + vec2(inUV.x/8.f, inUV.y/4.f);
vec4 color = texture(samplerColor, uv);
outFragColor = color; outFragColor = color;
}
} }
Binary file not shown.
+12 -2
View File
@@ -17,7 +17,15 @@ layout (location = 0) out vec2 outUV;
layout (location = 1) out vec3 outNormal; layout (location = 1) out vec3 outNormal;
layout(push_constant) uniform PushConstants { layout(push_constant) uniform PushConstants {
float myValue; float zoom;
float r;
float g;
float b;
float radius;
float ux;
float uy;
float offset_x;
float offset_y;
} pushConstants; } pushConstants;
out gl_PerVertex out gl_PerVertex
@@ -30,7 +38,9 @@ void main()
outUV = inUV; outUV = inUV;
vec2 position = vec2(inPos.xy*2 -1); vec2 position = vec2(inPos.xy*2 -1);
position = position * pushConstants.myValue; position = position * pushConstants.zoom;
position.x = position.x + (pushConstants.offset_x/480);
position.y = position.y + (pushConstants.offset_y/480);
gl_Position = vec4(position, 0.5, 1.0); gl_Position = vec4(position, 0.5, 1.0);
vec4 pos = ubo.model * vec4(inPos, 1.0); vec4 pos = ubo.model * vec4(inPos, 1.0);
Binary file not shown.
+222 -10
View File
@@ -15,6 +15,9 @@ android_app* g_android_app = nullptr;
FaceApp* g_Application = nullptr; FaceApp* g_Application = nullptr;
AAssetManager* g_assetManager = nullptr; AAssetManager* g_assetManager = nullptr;
jobject g_callback = nullptr;
jobject g_callbackAnimationFinished = nullptr;
void handle_cmd(android_app *pApp, int32_t cmd) { void handle_cmd(android_app *pApp, int32_t cmd) {
switch (cmd) { switch (cmd) {
case APP_CMD_INIT_WINDOW: case APP_CMD_INIT_WINDOW:
@@ -36,9 +39,12 @@ void android_main(struct android_app *pApp) {
aout << "Welcome to android_main" << std::endl; aout << "Welcome to android_main" << std::endl;
g_android_app = pApp; g_android_app = pApp;
g_assetManager = pApp->activity->assetManager; g_assetManager = pApp->activity->assetManager;
FaceApp application; //FaceApp application;
g_Application = &application; //g_Application = &application;
application.SetInitArg(g_InitArgString); if(g_Application == nullptr) {
g_Application = new FaceApp();
}
g_Application->SetInitArg(g_InitArgString);
pApp->onAppCmd = handle_cmd; pApp->onAppCmd = handle_cmd;
long long last_update_time = 0; long long last_update_time = 0;
android_app_set_motion_event_filter(pApp, nullptr); android_app_set_motion_event_filter(pApp, nullptr);
@@ -70,23 +76,25 @@ void android_main(struct android_app *pApp) {
} }
} }
} }
if(application.isInited()) if(g_Application->isInited())
{ {
auto frameTime = (start_time - _lastDrawFrameTime); auto frameTime = (start_time - _lastDrawFrameTime);
_lastDrawFrameTime = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count(); _lastDrawFrameTime = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
application.drawFrame(frameTime); g_Application->drawFrame(frameTime);
} }
auto end_time = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count(); auto end_time = chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
auto frameTime = end_time - last_update_time; auto frameTime = end_time - last_update_time;
last_update_time = end_time; last_update_time = end_time;
auto function_time = (end_time - start_time); auto function_time = (end_time - start_time);
aout << "function_time:" << function_time << " fps:" << (1000/frameTime) << std::endl; //aout << "function_time:" << function_time << " fps:" << (1000/frameTime) << std::endl;
if(function_time < 35) if(function_time < 35)
{ {
this_thread::sleep_for(chrono::milliseconds((35-function_time))); this_thread::sleep_for(chrono::milliseconds((35-function_time)));
} }
} while (!pApp->destroyRequested); } while (!pApp->destroyRequested);
application.cleanup(); //application.cleanup();
g_Application->cleanupSecondInit();
g_Application->clearnSecondFaceApp();
} }
} }
@@ -147,10 +155,194 @@ Java_com_hmwl_face_1sdk_FaceActivity_SetCppInitArg(JNIEnv *env, jobject thiz, js
} }
memcpy(g_InitArgString, nativeString, len); memcpy(g_InitArgString, nativeString, len);
} }
extern "C" extern "C"
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_com_hmwl_face_1sdk_FaceActivity_ChangeStateCpp(JNIEnv *env, jobject thiz, jstring json) { Java_com_hmwl_face_1sdk_FaceActivity_StopRunning(JNIEnv *env, jobject thiz) {
// TODO: implement ChangeStateCpp() g_Application->Stop();
}
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()
{
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, "OnLoadMotionListFinished", "(Ljava/lang/String;)V");
if (methodId == nullptr) {
env->ExceptionDescribe(); // 打印异常
env->ExceptionClear();
if (needDetach) vm->DetachCurrentThread();
return;
}
// 3. 构造 jstring 参数
jstring jResult = env->NewStringUTF("ok");
// 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, "OnPlayMotionListFinished", "()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->preLoadMotionList(nativeString, CppCallback);
return env->NewStringUTF(ret.c_str());
}
const char DELIMITER = 0x1F; // same as \u001F
std::vector<std::string> splitMotionString(const std::string& input) {
std::vector<std::string> result;
if (input.empty()) return result;
size_t start = 0;
size_t pos = input.find(DELIMITER);
while (pos != std::string::npos) {
result.push_back(input.substr(start, pos - start));
start = pos + 1;
pos = input.find(DELIMITER, start);
}
// Add last part
result.push_back(input.substr(start));
return result;
}
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); const char *nativeString = env->GetStringUTFChars(json, nullptr);
jsize len = env->GetStringUTFLength(json); jsize len = env->GetStringUTFLength(json);
if(len > ArgLen) if(len > ArgLen)
@@ -158,8 +350,28 @@ Java_com_hmwl_face_1sdk_FaceActivity_ChangeStateCpp(JNIEnv *env, jobject thiz, j
aout << "ArgLen to long:" << len << std::endl; aout << "ArgLen to long:" << len << std::endl;
return; return;
} }
// 保存新的回调
if (callback != nullptr) {
g_callbackAnimationFinished = env->NewGlobalRef(callback);
} else {
g_callbackAnimationFinished = nullptr;
}
if(g_Application->isInited()) if(g_Application->isInited())
{ {
g_Application->changeMotion(nativeString); std::vector<std::string> motions = splitMotionString(nativeString);
g_Application->changeMotionList(motions, CppAnimationFinishedCallback, loop);
} }
} }
extern "C"
JNIEXPORT void JNICALL
Java_com_hmwl_face_1sdk_FaceActivity_StopMotionNative(JNIEnv *env, jobject thiz) {
g_Application->StopMotion();
}
extern "C"
JNIEXPORT void JNICALL
Java_com_hmwl_face_1sdk_FaceActivity_ResumeMotionNative(JNIEnv *env, jobject thiz) {
// TODO: implement ResumeMotionNative()
g_Application->ResumeMotion();
}
@@ -4,7 +4,6 @@ import android.Manifest;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -31,7 +30,6 @@ import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.LandmarkerListener { public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.LandmarkerListener {
private static final String TAG = "FaceActivity"; private static final String TAG = "FaceActivity";
@@ -50,6 +48,21 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
} }
} }
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_PERMISSION) {
// 检查权限是否被授予
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 用户授予了权限,启动相机
startCamera();
} else {
requestCameraPermission();
}
}
}
private void startCamera() { private void startCamera() {
ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ListenableFuture<ProcessCameraProvider> cameraProviderFuture =
ProcessCameraProvider.getInstance(this); ProcessCameraProvider.getInstance(this);
@@ -81,12 +94,12 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
{ {
detectFace(image); detectFace(image);
} }
else // else
{ // {
image.close(); // image.close();
} // }
} finally { } finally {
//image.close(); // 确保在这里关闭 image.close(); // 确保在这里关闭
//Log.d("Camera", "Image closed, ready for next frame"); //Log.d("Camera", "Image closed, ready for next frame");
} }
} }
@@ -122,6 +135,22 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
} }
} }
public void Stop(){
StopRunning();
}
private native void StopMotionNative();
public void StopMotion(){
StopMotionNative();
}
private native void ResumeMotionNative();
public void ResumeMotion(){
ResumeMotionNative();
}
private native void StopRunning();
// Native 方法 // Native 方法
private native void processImageNative(ByteBuffer buffer, int width, int height, private native void processImageNative(ByteBuffer buffer, int width, int height,
int format, int rowStride, int pixelStride, int format, int rowStride, int pixelStride,
@@ -261,21 +290,45 @@ public class FaceActivity extends GameActivity implements FaceLandmarkerHelper.L
protected native void SetCppInitArg(String json); protected native void SetCppInitArg(String json);
protected void SetInitArg(String json) public void SetInitArg(String json)
{ {
SetCppInitArg(json); SetCppInitArg(json);
} }
protected native void ChangeStateCpp(String json); public interface LoadMotionListFinishedCallback {
protected void ChangeState(String json){ void OnLoadMotionListFinished(String result);
Log.i("FaceActivity", "ChangeState:" + json); }
ChangeStateCpp(json);
public interface PlayMotionListFinishedCallback {
void OnPlayMotionListFinished();
}
protected native String PreReadAction(String motion, LoadMotionListFinishedCallback callback);
public String PreLoadAction(String json, LoadMotionListFinishedCallback callback){
return PreReadAction(json, callback);
}
protected native void ChangeMotionCpp(String json, PlayMotionListFinishedCallback callback, boolean loop);
public void PlayMotionList(List<String> motionList, boolean loop, PlayMotionListFinishedCallback callback)
{
if(callback == null)
{
callback = new PlayMotionListFinishedCallback() {
@Override
public void OnPlayMotionListFinished() {
Log.i(TAG, "OnPlayMotionListFinished: ");
}
};
}
final String DELIMITER = "\u001F"; // ASCII Unit Separator
String motion_list_str = String.join(DELIMITER, motionList);
ChangeMotionCpp(motion_list_str, callback, loop);
} }
// 添加这个缺失的方法 // 添加这个缺失的方法
@Override @Override
public void onEmpty() { public void onEmpty() {
// 当没有检测到人脸时的处理逻辑 // 当没有检测到人脸时的处理逻辑
Log.d(TAG, "No face detected in the current frame"); //Log.d(TAG, "No face detected in the current frame");
} }
} }
@@ -67,6 +67,9 @@ class FaceLandmarkerHelper(
} }
} }
minFaceDetectionConfidence = 0.1f;
minFaceTrackingConfidence = 0.1f;
minFacePresenceConfidence = 0.1f;
try { try {
val baseOptions = baseOptionBuilder.build() val baseOptions = baseOptionBuilder.build()
// Create an option builder with base options and specific // Create an option builder with base options and specific
@@ -189,7 +192,7 @@ class FaceLandmarkerHelper(
Bitmap.Config.ARGB_8888 Bitmap.Config.ARGB_8888
) )
imageProxy.use { bitmapBuffer.copyPixelsFromBuffer(imageProxy.planes[0].buffer) } imageProxy.use { bitmapBuffer.copyPixelsFromBuffer(imageProxy.planes[0].buffer) }
imageProxy.close() //imageProxy.close()
val matrix = Matrix().apply { val matrix = Matrix().apply {
// Rotate the frame received from the camera to be in the same direction as it'll be shown // Rotate the frame received from the camera to be in the same direction as it'll be shown
@@ -238,32 +241,33 @@ class FaceLandmarkerHelper(
val frameId = result.timestampMs() val frameId = result.timestampMs()
if( result.faceLandmarks().size > 0 ) { if( result.faceLandmarks().size > 0 ) {
// 计算各种延时 // 计算各种延时
val timings = frameTimings[frameId] // val timings = frameTimings[frameId]
if (timings != null) { // if (timings != null) {
val totalLatency = resultTime - timings.captureTime // val totalLatency = resultTime - timings.captureTime
val preprocessLatency = timings.preprocessEndTime - timings.preprocessStartTime // val preprocessLatency = timings.preprocessEndTime - timings.preprocessStartTime
val detectionLatency = resultTime - timings.detectionStartTime // val detectionLatency = resultTime - timings.detectionStartTime
val captureToDetectionLatency = timings.detectionStartTime - timings.captureTime // val captureToDetectionLatency = timings.detectionStartTime - timings.captureTime
//
Log.i("TimeLatency", // Log.i("TimeLatency",
"总延时: ${totalLatency}ms | " + // "总延时: ${totalLatency}ms | " +
"预处理: ${preprocessLatency}ms | " + // "预处理: ${preprocessLatency}ms | " +
"检测: ${detectionLatency}ms | " + // "检测: ${detectionLatency}ms | " +
"捕获到检测: ${captureToDetectionLatency}ms | " + // "捕获到检测: ${captureToDetectionLatency}ms | " +
"FPS: ${String.format("%.1f", currentFps)}" // "FPS: ${String.format("%.1f", currentFps)}"
) // )
//
val finishTimeMs = SystemClock.uptimeMillis() // val finishTimeMs = SystemClock.uptimeMillis()
val inferenceTime = finishTimeMs - result.timestampMs() // val inferenceTime = finishTimeMs - result.timestampMs()
faceLandmarkerHelperListener?.onResults( // faceLandmarkerHelperListener?.onResults(
ResultBundle( // ResultBundle(
result, // result,
inferenceTime, // 主要是检测时间 // inferenceTime, // 主要是检测时间
input.height, // input.height,
input.width, // input.width,
) // )
) // )
} else { // } else
//{
val finishTimeMs = SystemClock.uptimeMillis() val finishTimeMs = SystemClock.uptimeMillis()
val inferenceTime = finishTimeMs - result.timestampMs() val inferenceTime = finishTimeMs - result.timestampMs()
Log.i("TimeLatency", Log.i("TimeLatency",
@@ -277,7 +281,7 @@ class FaceLandmarkerHelper(
input.width input.width
) )
) )
} //}
} }
else { else {
faceLandmarkerHelperListener?.onEmpty() faceLandmarkerHelperListener?.onEmpty()
@@ -0,0 +1,27 @@
package com.hmwl.face_sdk;
import org.json.JSONObject;
public class Frame {
public String name;
public float x;
public float y;
public Frame(String name, float x, float y)
{
this.name = name;
this.x = x;
this.y = y;
}
public JSONObject toJsonObject(){
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", name);
jsonObject.put("x", x);
jsonObject.put("y", y);
return jsonObject;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
@@ -4,13 +4,23 @@ import org.json.JSONObject;
public class InitArg { public class InitArg {
public int action_fps; public int action_fps;
public float zoom; public float zoom;
public Motion motion; public float r;
public float g;
public float b;
public float radius;
public float offset_x;
public float offset_y;
public String toJson() { public String toJson() {
try { try {
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("action_fps", action_fps); jsonObject.put("action_fps", action_fps);
jsonObject.put("zoom", zoom); jsonObject.put("zoom", zoom);
jsonObject.put("motion", motion.toJsonObject()); jsonObject.put("r", r);
jsonObject.put("g", g);
jsonObject.put("b", b);
jsonObject.put("radius", radius);
jsonObject.put("offset_x", offset_x);
jsonObject.put("offset_y", offset_y);
return jsonObject.toString(); return jsonObject.toString();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
+13 -16
View File
@@ -5,32 +5,29 @@ import org.json.JSONObject;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class Motion { public class Motion {
public String type = "no"; public String name = "no";
public List<String> png_names = new ArrayList<>(); public List<Frame> frames = new ArrayList<>();
public Motion(String name, List<Frame> frames)
{
this.name = name;
this.frames = frames;
}
public JSONObject toJsonObject() { public JSONObject toJsonObject() {
try { try {
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
jsonObject.put("type", type); jsonObject.put("name", name);
JSONArray ja = new JSONArray(); JSONArray jframes = new JSONArray();
for(int i = 0; i < png_names.size(); ++i){ for(int i = 0; i < frames.size(); ++i){
ja.put(png_names.get(i)); jframes.put(frames.get(i).toJsonObject());
} }
jsonObject.put("png_names", ja); jsonObject.put("frames", jframes);
return jsonObject; return jsonObject;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }
} }
public String toJson() {
try {
return toJsonObject().toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}; };
@@ -0,0 +1,28 @@
package com.hmwl.face_sdk;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class MotionList {
public List<Motion> motions = new ArrayList<>();
public JSONObject toJsonObject() {
try {
JSONObject jsonObject = new JSONObject();
JSONArray jMotions = new JSONArray();
for(int i = 0; i < motions.size(); ++i){
jMotions.put(motions.get(i).toJsonObject());
}
jsonObject.put("motions", jMotions);
return jsonObject;
} catch (Exception e) {
e.printStackTrace();
return new JSONObject();
}
}
public String toJsonString(){
return toJsonObject().toString();
}
}
+15 -2
View File
@@ -1,6 +1,19 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.3.2'
}
}
plugins { plugins {
alias(libs.plugins.android.application) apply false alias(libs.plugins.android.application) apply false
alias(libs.plugins.android.library) apply false // 添加这行 alias(libs.plugins.android.library) apply false
id 'org.jetbrains.kotlin.android' version '1.9.0' apply false alias(libs.plugins.kotlin.android) apply false // 添加这行
//alias(libs.plugins.kotlin.android) apply false
//id 'org.jetbrains.kotlin.android' version '2.2.0' apply false
} }
+4 -3
View File
@@ -4,8 +4,9 @@ glslangValidator -V app/src/main/assets/shaders/bg.vert -o app/src/main/assets/s
glslangValidator -V app/src/main/assets/shaders/texture.frag -o app/src/main/assets/shaders/texture.frag.spv glslangValidator -V app/src/main/assets/shaders/texture.frag -o app/src/main/assets/shaders/texture.frag.spv
glslangValidator -V app/src/main/assets/shaders/texture.vert -o app/src/main/assets/shaders/texture.vert.spv glslangValidator -V app/src/main/assets/shaders/texture.vert -o app/src/main/assets/shaders/texture.vert.spv
glslangValidator -V app/src/main/assets/shaders/texture_thick.frag -o app/src/main/assets/shaders/texture_thick.frag.spv
glslangValidator -V app/src/main/assets/shaders/texture_thick.vert -o app/src/main/assets/shaders/texture_thick.vert.spv
glslangValidator -V app/src/main/assets/shaders/simple_shader.frag -o app/src/main/assets/shaders/simple_shader.frag.spv glslangValidator -V app/src/main/assets/shaders/simple_shader.frag -o app/src/main/assets/shaders/simple_shader.frag.spv
glslangValidator -V app/src/main/assets/shaders/simple_shader.vert -o app/src/main/assets/shaders/simple_shader.vert.spv glslangValidator -V app/src/main/assets/shaders/simple_shader.vert -o app/src/main/assets/shaders/simple_shader.vert.spv
glslangValidator -V app/src/main/assets/shaders/texture_thick.frag -o app/src/main/assets/shaders/texture_thick.frag.spv
rem glslangValidator -V app/src/main/assets/shaders/texture_thick.vert -o app/src/main/assets/shaders/texture_thick.vert.spv
+32 -2
View File
@@ -1,13 +1,15 @@
plugins { plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
//alias(libs.plugins.kotlin.android)
} }
android { android {
namespace 'com.hmwl.example' namespace 'com.inewme.uvmirror'
compileSdk 36 compileSdk 36
defaultConfig { defaultConfig {
applicationId "com.hmwl.f20251110" applicationId "com.inewme.uvmirror.f20260113"
minSdk 30 minSdk 30
targetSdk 36 targetSdk 36
versionCode 1 versionCode 1
@@ -18,6 +20,7 @@ android {
buildTypes { buildTypes {
release { release {
signingConfig signingConfigs.debug
minifyEnabled false minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} }
@@ -26,6 +29,20 @@ android {
sourceCompatibility JavaVersion.VERSION_17 sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17
} }
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.5.1'
}
kotlinOptions {
jvmTarget = '17'
}
// kotlinOptions {
// jvmTarget = '17'
// }
} }
dependencies { dependencies {
@@ -33,11 +50,21 @@ dependencies {
implementation libs.appcompat implementation libs.appcompat
implementation libs.material implementation libs.material
implementation libs.games.activity implementation libs.games.activity
implementation libs.core.ktx
implementation libs.androidx.core.ktx
testImplementation libs.junit testImplementation libs.junit
androidTestImplementation libs.ext.junit androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core androidTestImplementation libs.espresso.core
implementation project(':app') implementation project(':app')
// Jetpack Compose
implementation "androidx.compose.ui:ui:1.5.0"
implementation "androidx.compose.material3:material3:1.0.0"
implementation "androidx.compose.foundation:foundation:1.5.0"
implementation "androidx.compose.runtime:runtime:1.5.0"
implementation "androidx.activity:activity-compose:1.7.2" // ؼṩ setContent
implementation "androidx.compose.ui:ui-tooling:1.5.4"
def camerax_version = '1.4.2' def camerax_version = '1.4.2'
implementation "androidx.camera:camera-core:$camerax_version" implementation "androidx.camera:camera-core:$camerax_version"
@@ -53,4 +80,7 @@ dependencies {
implementation 'com.google.flogger:flogger-system-backend:0.7.4' implementation 'com.google.flogger:flogger-system-backend:0.7.4'
implementation 'com.google.guava:guava:31.1-android' implementation 'com.google.guava:guava:31.1-android'
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7") // 提供 lifecycleScope
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
} }
+4
View File
@@ -20,6 +20,10 @@
android:name="android.app.lib_name" android:name="android.app.lib_name"
android:value="face_sdk" /> android:value="face_sdk" />
</activity> </activity>
<activity
android:name=".MakeupActivity"
android:exported="false" />
</application> </application>
</manifest> </manifest>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Some files were not shown because too many files have changed in this diff Show More