打开压缩包 byted_effect_andr.zip,再解压 android_c_sdk.zip
从aar文件里解压出来class.jar,拷贝jar包到项目主模块 libs 下,并确保主模块 build.gradle 的 dependencies 中有 api fileTree(include: ['*.jar'], dir: 'libs')
将 arm64-v8a 和 armeabi-v7a 下的 libeffect.so 添加到项目中
将 include 下的 SDK 头文件添加到项目中
添加素材,将提供的素材包(一般是 resource 文件夹)添加到工程中
注意事项:
Android端用C接口native接入的话(非hal的版本),还需要添加BEF_EFFECT_ANDROID_WITH_JNI预定义宏,指定要调用带jni环境的api,如下
cmake构建的话,通过以下方式添加
add_definitions(-DBEF_EFFECT_ANDROID_WITH_JNI=1)
Android.mk构建的话,通过以下方式添加
LOCAL_CFLAGS += -DBEF_EFFECT_ANDROID_WITH_JNI=1
针对以下特殊情况,在加入sdk时有额外操作。
这种情况下,android加载so时,调用不到sdk里面的JNI_OnLoad
接口,导致sdk里一些方法没办法使用,最终引起执行出错。
针对这种情况,我们增加了以下两个接口,用来处理这个问题:
/** * @brief 主动调用effect_sdk的JNI_OnLoad * @param vm 表示 Java 虚拟机 的对象地址 * @param reserved 传NULL即可 * @return 返回当前 NDK 使用的 JNI 版本 */ JNIEXPORT jint BEF_EFFECT_JNI_OnLoad(JavaVM* vm, void* reserved); /** * @brief 主动调用effect_sdk的JNI_OnUnload * @param vm 表示 Java 虚拟机 的对象地址 * @param reserved 传NULL即可 */ JNIEXPORT void BEF_EFFECT_JNI_OnUnload(JavaVM *vm, void *reserved);
接入方在自己的lib中使用dlopen加载libeffect.so的方式时,可以参考如下方法和示例代码:
BEF_EFFECT_JNI_OnLoad
以及BEF_EFFECT_JNI_OnUnload
函数的函数地址,参考如下:typedef void (*JNI_OnLoad_Def)(JavaVM *, void *); typedef void (*JNI_OnUnload_Def)(JavaVM *, void *); // 1.加载libeffect.so void * handle = dlopen( libeffect.so ,RTLD_NOW | RTLD_LOCAL) if (handle) { // 2.获取libeffect.so中 JNI_OnLoad和JNI_OnUnload的函数地址 JNI_OnLoad_Def BEF_EFFECT_JNI_OnLoad_ptr = (JNI_OnLoad_Def)dlsym(handle, "BEF_EFFECT_JNI_OnLoad" ); JNI_OnUnload_Def BEF_EFFECT_JNI_OnUnload_ptr = (JNI_OnUnload_Def)dlsym(handle, "BEF_EFFECT_JNI_OnUnload" ); }
JNI_Onload
中调用BEF_EFFECT_JNI_OnLoad_ptr
,JNI_OnUnload
中调用BEF_EFFECT_JNI_OnUnload_ptr
BEF_EFFECT_JNI_OnLoad_ptr
需要在java调用下来的native接口中调用才能生效(如JNI_OnLoad接口,或自定义的jni接口),不能直接在native层起的线程里去调用,否则会造成findclass失败。bef_effect_jni_manager.h
#ifndef bef_effect_jni_manager_h #define bef_effect_jni_manager_h #include <jni.h> #include "bef_effect_ai_public_define.h" /** * @brief Actively call the JNI_OnLoad interface of effect_sdk. * @param vm Object address representing the Java virtual machine. * @param reserved just pass NULL. * @return Returns the JNI version used by the current NDK. */ BEF_SDK_API jint BEF_EFFECT_JNI_OnLoad(JavaVM* vm, void* reserved); /** * @brief Actively call the JNI_OnUnload interface of effect_sdk. * @param vm Object address representing the Java virtual machine. * @param reserved just pass NULL. */ BEF_SDK_API void BEF_EFFECT_JNI_OnUnload(JavaVM *vm, void *reserved); #endif //bef_effect_jni_manager_h
JNI_Onload
中调用BEF_EFFECT_JNI_OnLoad
接口,JNI_OnUnload
中调用BEF_EFFECT_JNI_OnUnload
接口BEF_EFFECT_JNI_OnLoad
需要在java调用下来的native接口中调用才能生效(如JNI_OnLoad接口,或自定义的jni接口),不能直接在native层起的线程里去调用,否则会造成findclass失败。repositories { flatDir { dirs 'libs' } }
implementation(name: 'effect-sdkXXX', ext: 'aar')
dependencies { implementation(name: 'effect-sdkXXX', ext: 'aar') }
以下指南针对使用 SDK 提供的 C 接口(或者是 Android 提供的 aar 接口)进行集成,会列出正常执行必需的一些步骤。只会列出美颜相关的接入流程,算法接入及更多接口,参见 算法接口说明、特效接口说明。
由于 SDK 本身只有图像的处理功能,像什么 OpenGL 相关的处理、绘制都没有,所以如果没有必要,建议直接使用 sample 中的一些封装代码接入。
CV SDK 中美颜功能的接入可以分为三个阶段:
SDK 初始化需要以下几个函数的调用:
bef_effect_handle_t _handle; int ret = 0; // 创建 SDK 实例 ret = bef_effect_ai_create(&_handle); // 进行 SDK 授权验证,此步骤不调用 handle 无法使用 ret = bef_effect_ai_check_license(_handle, self.licensePath); // 设置是否使用并行渲染,默认可设置为开启 ret = bef_effect_ai_use_pipeline_processor(_handle, usePipeline); // 执行 SDK 初始化,除了第四个参数需要传模型路径,也就是素材包中的 ModelResource.bundle 路径,其他的可参照示例 ret = bef_effect_ai_init(_handle, 10, 10, [[self.provider modelDirPath] UTF8String], ""); // 设置 SDK 美颜模式,按照示例调用即可 ret = bef_effect_ai_composer_set_mode(_handle, 1, 0);
如使用 Android 提供的 aar,对应的 java 方法为
public int init(Context context, String modelDir, String licensePath, boolean usePipeline)
参数描述:
- context Android 中的 context
- modelDir 对应 bef_effect_ai_init 阶段的模型文件路径
- licensePath 对应 bef_effect_ai_check_license 阶段授权文件路径
- usePipeline 对应 bef_effect_ai_use_pipeline_processor 是否开启并行渲染
支持输入的数据类型
支持的数据类型 | 支持的数据格式 |
---|---|
buffer(不推荐) | RGBA、BGRA、YUV |
texture | 2D |
SDK 处理图像时有两类接口,可以分别处理 buffer 类型输入和纹理输入,注意,推荐使用纹理输入,如果目前项目中只能提供 buffer,建议先转成纹理再处理,外部可以做一些特殊优化,但如果直接给 SDK 输入 buffer,会很影响性能。
纹理输入需要调用的函数:
int ret; // 设置图像宽高,注意,如果前后两帧处理的图像大小不一致,可能会导致效果异常 ret = bef_effect_ai_set_width_height(_handle, width, height); // 设置图像旋转角度,一般直接取系统提供的手机旋转方向即可 ret = bef_effect_ai_set_orientation(_handle, orientation); // 对图像做算法处理,调用此函数才会执行人脸检测 // 本函数中只有 texture 和 timeStamp 是必需的,比如可以直接调用 bef_effect_ai_algorithm_texture_with_buffer(_handle, texture, NULL, 0, 0, 0, 0, timeStamp); // 另外几个参数为对 buffer 的描述,将 buffer 与 texture 一起使用在某些场景有加速效果,一般情况下只传 texture 即可 ret = bef_effect_ai_algorithm_texture_with_buffer(_handle, texture, buffer, format, width, height, bytesPerRow, timeStamp); // 对图像做特效处理,调用此函数才会增加美颜效果 // 注意,输入输出纹理需要保持宽高一致,且不要让二者共用同一纹理 ret = bef_effect_ai_process_texture(_handle, inputTexture, outputTexture, timeStamp);
如使用 Android 提供的 aar,对应的 java 方法为
// bef_effect_ai_set_width_height bef_effect_ai_set_orientation 已在内部调用,可不用关 // 对应 bef_effect_ai_algorithm_texture_with_buffer public boolean algorithmTextureWithBuffer(int texture, ByteBuffer buffer, BytedEffectConstants.Rotation orient, int pixelFormat, int width, int height, int stride, long timeStamp) // 对应 bef_effect_ai_process_texture public boolean processTextureOnly(int srcTexture, int dstTexture, int width, int height, BytedEffectConstants.Rotation rotation, long timeStamp)
int ret; // 设置图像宽高,注意,如果前后两帧处理的图像大小不一致,可能会导致效果异常 ret = bef_effect_ai_set_width_height(_handle, width, height); // 设置图像旋转角度,一般直接取系统提供的手机旋转方向即可 ret = bef_effect_ai_set_orientation(_handle, orientation); // 对图像做算法处理,调用此函数才会执行人脸检测 ret = bef_effect_ai_algorithm_buffer(_handle, buffer, format, width, height, bytesPerRow, timeStamp); // 对图像做特效处理,调用此函数才会增加美颜效果 // 注意,outputBuffer 为处理结果保存的位置,一定要保证它的内存大小与给定的图像宽高和格式相符合 ret = bef_effect_ai_process_buffer(_handle, inputBuffer, inputFormat, width, height, bytesPerRow, outputBuffer, outputFormat, timeStamp);
如使用 Android 提供的 aar,对应的 java 方法为
public boolean processBuffer(ByteBuffer inputdata, BytedEffectConstants.Rotation orient, int in_pixformat, int imagew, int imageh, int imagestride, byte[] outdata, int out_pixformat)
注意,SDK 参数设置需要在初始化之后调用,请尽量与 SDK图像处理 处于同一线程使用,以避免可能出现的问题。
美颜、美型、美妆的设置使用的是同一个接口,一般来说使一个美颜生效需要两步:
设置素材路径接口
// 设置素材 bef_effect_result_t result = bef_effect_ai_composer_set_nodes(_handle, (const char **)nodesPath, count);
如使用 Android 提供的 aar,对应的 java 方法为
public int setComposerNodes(String[] composerNodes)
nodesPath 是字符串数组,每一行代表一个素材在设备中的绝对路径
注意,SDK 内部不会保存已设置的素材,所以此方法每次调用都需要将所有需要生效的素材路径加上。
设置素材中,特效强度接口
// 设置素材中某个特效的强度 bef_effect_result_t result = bef_effect_ai_composer_update_node(_handle, (const char *)node, (const char *)key, intensity);
如使用 Android 提供的 aar,对应的 java 方法为
public int updateComposerNodes(String path, String key, float value)
node 为素材在设备中的绝对路径。
以美颜素材为例,需要通过 key 来控制我们要修改的是美白、磨皮还是锐化的强度,素材中 key 与功能的对应关系参见 素材 key 对应说明。
设置贴纸接口
// 设置贴纸 bef_effect_result_t result = bef_effect_ai_set_effect(_handle, (const char *)path);
如使用 Android 提供的 aar,对应的 java 方法为
public boolean setSticker(String resourcePath)
path 为贴纸在设备中的绝对路径。
设置滤镜的接口
// 设置滤镜路径 bef_effect_result_t result = bef_effect_ai_set_color_filter_v2(_handle, path); // 设置滤镜强度 result = bef_effect_ai_set_intensity(_handle, BEF_INTENSITY_TYPE_GLOBAL_FILTER_V2, intensity);
如使用 Android 提供的 aar,对应的 java 方法为
// 对应 bef_effect_ai_set_color_filter_v2 public boolean setFilter(String resourcePath); // 对应 bef_effect_ai_set_intensity public boolean updateIntensity(BytedEffectConstants.IntensityType.Filter.getId(), float intensity)
path 为滤镜在设备中的绝对路径。