MagicEngine-reuh0s1-x.x.x.x.aar
为特效引擎aar
包。licensing.0.0.10.aar
为鉴权aar
包tflite-2.4.1-0.0.7-jni.aar
依赖库MagicEngine.bundle
智能特效SDK内置素材,细条特效需要用到,实例化sdk时设到EngineConfig
的assetDir
*.aar
放到工程libs目录下或者自行决定目录并确保aar会被引进即可。-keep class com.kwai.FaceMagic.** { *; }
-keep class com.kwai.magicengine.** { *; }
-keep class org.wysaid.** { *; }
/**
* 业务类型
*/
public enum BusinessType {
Camera, ///< 相机业务
Video, ///< 视频业务
Image ///< 图片业务
}
/**
* 引擎配置
*/
public static class EngineConfig {
public int width; ///< 渲染尺寸
public int height; ///< 渲染尺寸
public String assetDir; ///< 内置资源跟目录
public BusinessType businessType; ///< 业务类型
}
/**
* 色域类型
*/
public enum ColorSpace {
BT601VideoRange,
BT601FullRange,
BT709VideoRange,
BT709FullRange,
BT2020VideoRange,
BT2020FullRange
}
/**
* 数据类型
*/
public enum InputDataFormat {
NV21,
NV12,
I420,
Texture2D
}
/**
* 相机位置
*/
public enum CameraPosition {
Unknown, ///< 未定义的相机位置
Front, ///< 前置
Back ///< 后置
}
/**
* 原始YUV帧数据
*/
public static class FrameData {
public ByteBuffer data; ///< YUV像素数据
public InputDataFormat format; ///< 像素数据格式
public CameraPosition position; ///< 相机位置(前置,后置)
public ColorSpace colorSpace; ///< 色域
public int texture; ///< 纹理ID
public int stride0; ///< data的Y平面一行字节数
public int stride1; ///< data的uv/u平面一行字节数
public int stride2; ///< data的v平面一行字节数
public int width; ///< 宽度
public int height; ///< 高度
public int rotation; ///< 顺时针旋转这个角度后为正图,取值:0, 90, 180, 270
public float fov; ///< 相机视野角度
public boolean mirror; ///< 镜像
}
/**
* 特效类型
*/
public enum EffectType {
Beautify, ///< 美颜
Makeup, ///< 美妆
Deform, ///< 美型
Lookup, ///< 滤镜
BodySlimming ///< 美体
}
/**
* 滤镜Lut类型
*/
public enum LookupTableType {
NxN, ///< 方形NxN的Lut
Nx1 ///< 横向Nx1的Lut
}
/**
* 滤镜配置
*/
public static class LookupInfo {
public String path; ///< Lut图路径
public int dimension; ///< 维数
public float intensity; ///< 强度
public LookupTableType lutType; ///< Lut类型
}
/**
* 美妆配置
*/
public static class MakeupInfo {
public String key; ///< 资源key, 用于替换
public String resourceDir; ///< 资源路径
public float intensity; ///< 强度
}
/**
* 美颜调节类型
*/
public enum BeautyType {
Bright, ///< 美白
Soften, ///< 磨皮
WrinkleRemove, ///< 去法令纹
EyeBagRemove, ///< 去黑眼圈
Teeth, ///< 白牙
EyeBrighten, ///< 亮眼
FaceShadow, ///< 立体
Clarity, ///< 清晰
EvenSkin, ///< 匀肤
}
/**
* 美体调节
*/
public enum BodySlimmingType {
Head, ///< 头部
Neck, ///< 脖子
Waist, ///< 腰部
Hip, ///< 臀部
Leg, ///< 腿部
Shoulder, ///< 肩膀
Breast ///< 胸部
}
/**
* 触摸手势状态
*/
public enum InteractionType {
None, ///< 未知
Begin, ///< 开始
Moved, ///< 移动
End ///< 结束或者取消
}
/**
* 坐标点
*/
public static class Point {
public float x;
public float y;
public Point(float x, float y) {
this.x = x;
this.y = y;
}
}
/**
* 手势触摸点数据
*/
public static class InteractionResponse {
public InteractionType type;
public List<Point> points; ///< 左上角为(0.0, 0.0)点,右下角为(1.0, 1.0)点
}
/**
* 魔表状态
*/
public enum EffectState {
Pause,
Resume,
Reset,
}
/**
* 传感器配置类型
*/
public enum SensorConfigType {
Reset,
Remove
}
/**
* 传感器配置
*/
public static class SensorConfig {
public float updateInterval;
public SensorConfigType configType;
}
/**
* 传感器数据
*/
public static class SensorData {
public long timestamp = 0;
public float rotation = 0;
}
/**
* 媒体类型
*/
public enum MediaType {
Image,
Video
}
/**
* 外部传入的所选媒体数据
*/
public static class MediaResource {
public MediaType type;
public String mediaPath;
}
/**
* 回传给客户端的提示信息内容
*/
public static class EffectHint {
public boolean mediaResult;
public String mediaPath;
public String errorMessage;
}
/**
* 魔表素材强度调节
*/
public enum EffectAdjustType {
DefaultEffect, ///< 美颜
MakeupEffect, ///< 美妆
LookupEffect, ///< 滤镜
}
智能特效SDK的使用依赖StreamlakeLicensing,请务必先初始化Licensing SDK,否则智能特效会调用失败,不生效
private void initSloManager() {
SloManager.get().init(new InitParams() {
@Override
public String getHost() {
return "https://vod.streamlakeapi.com";
}
@Override
public String getAccessKey() {
return "xxx"; // 对应申请好的AK
}
@Override
public String getSecretKey() {
return "secretKey"; //此字段为缺省字段, 目前可传任意字段
}
@Override
public String getVersion() {
return "2022-02-10"; //一般为Build日期
}
});
}
private void initSll() {
mSLLicensingManager = new SLLicensingManager(this, publicKey, prodCode,
new LicensingInitListener() {
@Override
public void onSuccess() {
Log.i(TAG, "init success");
}
@Override
public void onFailure(Throwable throwable) {
Log.i(TAG, "init failed" + throwable.getMessage());
}
});
}
智能特效SDK需要引以下的包:
import com.kwai.magicengine.MagicEngine;
import com.kwai.magicengine.MagicEngineCommon;
import com.kwai.magicengine.MagicEngineDefines;
import com.kwai.magicengine.MagicEngineSync;
智能特效 API中的参数和返回值类型以及每个属性的含义请看上面的**3.数据结构与枚举
**
智能特效SDK主要分为两个大模块:
setMagicEffect:
方法设定素材路径并渲染。ps:如果智能特效素材中存在跟细调一样的效果,加载的时候会按照配置去重。import com.kwai.magicengine.MagicEngine;
/**
* 实例化异步渲染引擎,务必在GL上下文中调用
* @param context Context实例
* @param config 引擎的配置数据
* @return 引擎实例
* @note 此模式下内部内部不维护GL上下文,因此需要在GL环境中创建SDL实例
*/
@Nullable
public static MagicEngineAsync createAsyncMagicEngine(@NonNull Context context, @NonNull MagicEngineDefines.EngineConfig config);
/**
* 实例化纯数据同步渲染引擎,没必要在GL上下文中调用
* @param context Context实例
* @param config 引擎的配置数据
* @return 引擎实例
* @note 此模式下内部自己创建GL上下文,跟外面进行数据交换,MEBusinessType非MEBusinessType_Image时会压帧,总返回上一帧的结果
*/
@Nullable
public static MagicEngineSync createSyncMagicEngine(@NonNull Context context, @NonNull MagicEngineDefines.EngineConfig config);
/**
* 实例化纯纹理同步渲染引擎,务必在GL上下文中调用
* @param context Context实例
* @param config 引擎的配置数据
* @return 引擎实例
* @note 此模式下内部共享外部GL上下文,跟外面进行纹理交换,MEBusinessType非MEBusinessType_Image时会压帧,总返回上一帧的结果
*/
@Nullable
public static MagicEngineSyncTexture createSyncTextureMagicEngine(@NonNull Context context, @NonNull MagicEngineDefines.EngineConfig config);
/**
* 同步渲染接口,结果写入返回值frameData中,不要求在GL上下文中调用
* @param frameData 帧数据描述
* @return 带渲染结果的MEFrameData
* @note
* 如果输入数据的高度不为8的倍数时会触发cpu转码,影响一些性能。建议关注一下高度尽量使用高度为8的倍数的分辨率
* 当输入尺寸发生变化时返回值的尺寸不一定会跟输入的frameData一致,不能有这个假设,使用返回值时使用返回值自身的尺寸 或者 要改变画面尺寸时调用clearFrameQueue方法来清理内部历史数据才能确保返回和输入大小一致
*/
MagicEngineDefines.FrameData processWithFrameData(MagicEngineDefines.FrameData frameData);
/**
* 同步渲染接口,结果写入返回值FrameData中,要求在GL上下文中调用
* @param frameData 一帧数据,必须得设里面texture
* @return 处理后的数据,处理结果写到里面的texture中
* @note 不用传 data[3], stride[3], colorSpace等数据, format传MEInputDataFormat_Texture2D,处理结果会写入返回结果中的texture中
*/
MagicEngineDefines.FrameData processWithTexture(MagicEngineDefines.FrameData frameData);
/**
* @brief 异步渲染所用,更新原始数据,需要在非渲染线程调用
* @param frameData 原始YUV数据
* @return 如果返回false说明内部渲染队列满了,需要丢帧
* @note: SDK内部维护了一个队列,在采集线程调用这个API时会放到队列中,render时从队列前端取数据进行渲染,如果一直传数据不调用render,则这个方法很快就会失败
*/
boolean updateFrameData(MagicEngineDefines.FrameData frameData);
/**
* 异步渲染所用,渲染到目标纹理 (适用于调用者管理渲染资源的情况),要求在GL上下文中调用
* @param inputTexture 输入纹理的ID
* @param outputFBO 已经绑好输出纹理的FBO ID.
* @param rotation 输入顺时针旋转rotation角度后为正图 取值:0, 90, 180, 270
* @return 返回值为 NO 时, 表示该帧被跳过, 什么操作都没执行. 请根据返回值做出合理的逻辑.如果直接渲染没有调用updateFrameData传数据,次方法会失败
* */
boolean render(int inputTexture, int outputFBO, int rotation);
下面这些接口主要是用来设定魔法表情,调节美颜,美型,美妆,美体,滤镜等。
/**
* @brief 设置引擎回调接口
* @param listener:回调接口
*/
void setEngineListener(MagicEngine.MagicEngineListener listener);
/**
* @brief 设定模型路径
* @param pathMap: 模型key和path的map
* */
void setModelPathMap(HashMap<String, String> pathMap);
/**
* @brief 开启/关闭 单个特效
* @param effectType 需要开启的特效类型
* @param enable 开启或者关闭状态
*/
void setEffectEnabled(MagicEngineDefines.EffectType effectType, boolean enabled);
/**
* @brief 设定滤镜资源
* @param info 需要设定的拍前滤镜信息
*/
void setLookupInfo(MagicEngineDefines.LookupInfo info);
/**
* @brief 设定滤镜强度
* @param intensity 滤镜强度
*/
void setLookupIntensity(float intensity);
/**
* @brief 设定美妆资源
* @param makeupInfo 需要设定的美妆信息,每个部分都是一个MakeupInfo结构
*/
void setMakeupInfo(ArrayList<MagicEngineDefines.MakeupInfo> makeupInfo);
/**
* @brief 设定美妆强度
* @param key 需要调整的美妆key(设定美妆时用户自定义)
* @param intensity 强度
*/
void setMakeupIntensity(String key, float intensity);
/**
* @brief 设定美颜强度
* @param type 需要调节的美颜类型
* @param intensity 强度
*/
void setBeautyIntensity(MagicEngineDefines.BeautyType beautyType, float intensity);
/**
* @brief 设定美型强度
* @param mode 美型类型
* @param intensity 强度
*/
void setDeformIntensity(int mode, float intensity);
/**
* @brief 设定美体强度
* @param type 需要调整的美体类型
* @param intensity 强度
*/
void setBodySlimmingIntensity(MagicEngineDefines.BodySlimmingType type, float intensity);
/**
* @brief 设定只能特效素材
* @param path 需要设定的素材路径
*/
void setMagicEffect(String path);
/**
* @brief 取消魔表素材
* */
void cancelMagicEffect();
/**
* 设定特效状态
* @param state: 特效状态支持 暂停,恢复,重置
*/
void setEffectState(MagicEngineDefines.EffectState state);
/**
* 设定素材强度
* type: 调节类型
* intensity: 强度
*/
void setEffectIntensity(MagicEngineDefines.EffectAdjustType type, float intensity);
/**
* 设定媒体资源,在支持替换资源的素材中可用。否则会被忽略
* @param resource 媒体资源结构
*/
void setMediaResource(MagicEngineDefines.MediaResource resource);
/**
* @brief 触摸手势设定
* @param response 手势触摸数据(左上角为[0.0, 1.0] ,右下角为[1.0, 1.0] )
*/
void setInteractionResponse(MagicEngineDefines.InteractionResponse response);
/**
* 更新传感器数据
* @param sensorData 传感器数据
*/
void setSensorData(MagicEngineDefines.SensorData sensorData);
/**
* @brief 清理内部正在处理的数据帧队列
* @note 如果中途切换分辨率,或者前后置切换等操作时可以调用此方法来清理内部一些历史数据, 避免遗留历史画面或者数据尺寸不一致
*/
void clearFrameQueue();
/**
* @brief 销毁引擎. 调用之后此实例不可再使用. 此方法主要用于保障 MagicEngine 在合适的时机合适的线程释放资源.
*/
void destroy();
大部分素材和美颜美型等都需要一些AI模型的支持。模型的路径通过上面所说的setModelPathDic
方法设定。模型资源都放在了resource目录中的model.7z
中,解压之后就能看到。其中模型的key为文件夹名字,path设此文件夹的路径。例如:key为magic_ycnn_model_landmark
的路径设为/path/to/magic_ycnn_model_landmark
。
当前所有的模型为:
magic_mmu_model_animoji1
magic_mmu_model_basewhite
magic_ycnn_model_cloth_seg
magic_ycnn_model_face_attributes
magic_ycnn_model_face_seg
magic_ycnn_model_finger
magic_ycnn_model_general_handpose
magic_ycnn_model_gesture
magic_ycnn_model_hair
magic_ycnn_model_head_seg
magic_ycnn_model_humanpose
magic_ycnn_model_landmark
magic_ycnn_model_matting
magic_ycnn_model_skin_seg
magic_ycnn_model_landmark
magic_ycnn_model_landmark
magic_ycnn_model_face_attributes
magic_ycnn_model_face_seg
magic_ycnn_model_landmark
magic_ycnn_model_landmark
magic_ycnn_model_humanpose
不需要AI模型
不同素材需要不同的模型,请线下获取素材/模型列表,并在应用某个素材之前确保设定的路径中存在对应的模型文件
每个素材有自己的所需的模型类型,如果内置素材可以把模型也内置。如果下发素材需要确保能够下载好对应的模型再应用素材。素材所需的模型跟素材本身有关。提供素材包时会标注对应的模型名字。开发阶段可以把模型都内置。
通过setModelPathDic
可以多次设定或刚开始把模型key和对应的路径先设定,应用对应功能之前确保再该路径中下载好或者放好对应模型。原则上需要模型的功能在被调用之前把对应的key和path通过这个dictionary设进去即可。
例如:刚开始只调用美颜和美型可以设定magic_ycnn_model_landmark
,magic_ycnn_model_face_attributes
,后面调节美体可以在之前的基础上添加magic_ycnn_model_humanpose
三个一起设进去。素材也是如此,可以一直累加,外部维护一个dictionary,或者全部一起设定,之后在确保模型存于早先设定的路径。
素材对应的模型列表请线下获取素材模型列表.xlsx
文件
在上面的接口文档中有提到public void setEngineListener(MagicEngineListener listener);
函数。这个函数设定的接口主要是会把魔表素材中的一些配置信息在魔表被应用后回调出来。
/**
* 引擎回调的接口
* */
public interface MagicEngineListener {
/**
* @brief 只能特效加载回调
* @param description 智能特效描述json数据,可以解析获取信息
* @param loadSucceed 表示加载状态,如果成功则为true否则为false
*/
default void onEffectDescriptionUpdate(String description, Boolean loadSucceed) {};
/**
* @brief 传感器配置回调
* @param sensorConfig 传感器配置。
* @note 如果config中的configType为 `Reset`则需要传递传感器数据,如果为`Remove `则不需要传感器,可以暂停。里面updateInterval是传感器更新时间间隔推荐值
*/
default void onSensorConfigUpdate(MagicEngineDefines.SensorConfig sensorConfig) {};
/**
* 魔表提示回调
* @param effectHint 提示信息
* @note 目前,相册选图后,会通过此回调告知客户端是否成功。客户端传图后,会转圈等待此回调。
*/
default void onEffectHintUpdate(MagicEngineDefines.EffectHint effectHint) {};
}
{
"disableCustomBeautify": true,
"disableCustomDeform": true,
"disableCustomMakeup": true,
"disableCustomColorFilter": true,
"disableCustomSlimming": true,
}
由于细调和素材中都有美妆,美型,美体,美颜,滤镜特效。所以有美妆的素材一般会配置禁用细调美妆,其他细调项同理。
客户端在加载成功后需要看一下description json中以下几个字段。如果 disableCustomXXX
为 true
表示素材加载后会禁用细调中的相关调节项。客户端从外面调节强度也不会生效。因此客户端需要把调节UI置灰 避免用户去做无用的操作。
{
"needTouch": true,
"needSwipe": true,
"needPinch": true
}
客户端在加载成功后需要看一下description json中以下几个字段。如果 needTouch
或 needSwipe
或 needPinch
为true客户端需要通过一下接口把用户的触摸信息传递进来。否则相关素材的点击交互不会生效。
public void setInteractionResponse(MagicEngineCommon.InteractionResponse response);
{
"needPickFirstMedia": true,
"needPickMediaResourceType": 1,
"embeddingMedias": [
{
"iconPath": "/path/to/icon.png",
"mediaPath": "/path/to/media.png",
"type": 0
}
]
}
客户端在加载成功后需要查看description json中是否有以上json字段。当needPickMediaResourceType
大于0时,说明此素材支持从本地选择媒体资源(图片/视频)。embeddingMedias
中返回了素材中内置的美体资源icon,路径和类型。客户端可以按需展示出来供用户选择替换。当needPickFirstMedia
为true时说明客户端在拿到description json的第一时间把embeddingMedias
中的第一个资源通过上面的public void setMediaResource(MagicEngineDefines.MediaResource resource) ;
api来设到智能引擎中。
ps: 如果为异步模式的接入方式setMediaResource:
务必在gl上下文中调用,否则行为是未定义的。
调用setMediaResource:
之后设定结果会在 onEffectHintUpdate
回调中通知客户端。该结构中记录了哪个路径下的媒体资源应用成功或者失败。如果失败则附带错误信息。
"adjustIntensityConfig": {
"enabled": true,
"defaultIntensity": 0.800000011920929,
"defaultLookupIntensity": 0.5,
"defaultMaleMakeupIntensityEnabled": false,
"defaultMaleMakeupIntensity": 0.800000011920929,
"effectTypes": [
"makeup"
]
}
客户端在加载成功后需要查看description json中是否有以上json字段。当存在adjustIntensityConfig
时,需要先解析里面的enabled
字段,如果该字段为true表示本素材支持做调节。其中effectTypes
表示支持调节的效果类型makeup
为美妆,lookup
为滤镜。defaultLookupIntensity
是默认滤镜强度,defaultIntensity
为默认强度,如果存在美妆则为美妆的强度。否则为素材默认强调。有时候素材中也有有一些逻辑支持调节会用到。
外部需要调整时需要调用void setEffectIntensity(MagicEngineDefines.EffectAdjustType type, float intensity);
来进行调节。传对应的type和强度就行。需要注意的是类型EffectAdjustType
必须对上上面返回的json内容。
"localeTips":{
"en":"",
"hi":"",
"id":"",
"ko":"",
"ms":"",
"pt":"",
"ru":"",
"tr":"",
"vi":"",
"zh":"低头有惊喜",
"zh-HK":"",
"zh-TW":""
}
通过回调中的localeTips获取一些素材中的玩儿法提示,不一定每个素材都有这个字段
1.调用鉴权API
进行授权
2.按需调用4.2.1中的实例化方法创建智能特效实例
3.按需调用4.2.2中对应的数据处理方法进行数据处理
4.准备退出时调用 destroy
方法销毁SDK,非MagicEngineSync
模式下需要在GL线程调用Destroy方法.
渲染都封装在了FMEffectRenderView 里面,FMEffectRenderView 继承自TextureView.客户端需要引入如下两个文件并调用下面的魔表接口即可。
import com.kwai.FaceMagic.nativePort.FMEffectRenderer;
import com.kwai.FaceMagic.view.FMEffectRenderView;
/**
* @brief 设定外部加载so的回调
*
* @param callback 回调
*/
public void setLibraryLoaderCallback(final FMEffectRenderer.LibraryLoaderCallback callback);
/**
* @breif 设定view创建回调
* @param onCreateCallback 回调接口,客户端对本View api调用务必得在这个回调成功后,否则会被忽略
*/
public void setOnCreateCallback(final OnCreateCallback callback);
/**
* @brief 设定魔表回调接口
* @param listener 魔表回调接口,需要客户端实现里面的方法来监听魔表加载,游戏数据等信息
*/
public void setEffectViewListener(final FMEffectRenderer.FMEffectRendererListener listener);
/**
* @brief 设定魔表素材
* @param path 魔表素材绝对路径
* @note 如果想取消当前素材可以传null或空字符
*/
public void setEffectPath(String path);
/**
* @param path 视频文件绝对路径
* @brief 直接播放透明视频文件
* @note 如果想取消当前视频可以传null或空字符
*/
public void setVideoBlendPath(String path, int playCount);
/**
* @brief 设定魔表游戏数据
* @param gameData 游戏数据json字符串
*/
public void setBoomGameData(String gameData);
/**
* @brief 设定手势数据
* @param type 手势触碰类型
* @param x 相对于view的归一化坐标数据,左上角为{0.0, 0.0} 右下角为{1.0, 1.0}
* @param y 相对于view的归一化坐标数据,左上角为{0.0, 0.0} 右下角为{1.0, 1.0}
* 备注:当前加载的魔表是否需要手势传递取决于onReceivedEffectDescription:loadSuccess:回调。
*/
public void touchWith(FMTouchType type, float x, float y);
/**
* @brief 暂停魔表渲染,需要暂停时或者进后台时需要调用,暂停之后画面停止更新只有resume才能恢复
*/
public void pause();
/**
* @brief 恢复魔表渲染,如果魔表被暂停可以用此方法来恢复
*/
public void resume();
/**
* @brief 重置魔表渲染
* @note 会重新开始当前的魔表素材
*/
public void reset();
/**
* @brief 释放GL资源
* @note 需要客户端在释放本view之前调用,确保资源的准确释放,调用release之后其他api都失效,只能重新实例化
*/
public void release();
客户端可以通过设置和实现 FMEffectRendererListener 来获取魔表加载状态等。
备注:这两个回调都在渲染线程回调。
public interface OnCreateCallback {
/**
* @brief gl相关资源创建成功后会回调
* @param succeeded 如果加载成功会回调true否则为false,表示发生了异常情况view不合法(例如so加载失败)
*/
void createOver(boolean succeeded);
}
public interface FMEffectRendererListener {
/**
* @brief 魔表加载回调
* @param description 是一个json string 可以解析获取一些魔表配置等信息
* @param loadSucceed 加载状态,如果只关心成功与失败,可以直接参考此值
*/
default void onReceivedEffectDescription(String description, Boolean loadSucceed) {};
/**
* @brief 游戏运行过程中的数据回调
* @param gameInfo 游戏数据,从素材中回调出来。可以按具体约定来解析和获取游戏状态
*/
default void onReceivedBoomGameInfo(String gameInfo) {};
/**
* 纯视频播放时表示视频播放完毕,素材和礼物场景下不回调
* @param path 视频文件的绝对路径
*/
default void onVideoBlendPlayingComplete(String path) {}
/**
* 礼物素材播放完毕时的回调,素材和视频播放场景下不回调
* @param path 礼物素材的绝对路径
*/
default void onGiftRenderingComplete(String path) {}
}
注意: