diff --git a/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/framework/PreprocessorFaceUnity.java b/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/framework/PreprocessorFaceUnity.java index 77a93d59..79a6adf4 100644 --- a/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/framework/PreprocessorFaceUnity.java +++ b/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/framework/PreprocessorFaceUnity.java @@ -6,7 +6,12 @@ import android.os.Looper; import android.util.Log; +import com.faceunity.FUConfig; +import com.faceunity.core.faceunity.FUAIKit; +import com.faceunity.core.faceunity.FURenderKit; +import com.faceunity.core.model.facebeauty.FaceBeautyBlurTypeEnum; import com.faceunity.nama.FURenderer; +import com.faceunity.nama.utils.FuDeviceUtils; import io.agora.capture.framework.modules.channels.VideoChannel; import io.agora.capture.framework.modules.processors.IPreprocessor; @@ -16,14 +21,12 @@ public class PreprocessorFaceUnity implements IPreprocessor { private final static String TAG = PreprocessorFaceUnity.class.getSimpleName(); private FURenderer mFURenderer = FURenderer.getInstance(); - private Context mContext; private boolean renderSwitch; private int skipFrame = 0; private Handler mGLHandler; public PreprocessorFaceUnity(Context context) { - mContext = context; } @Override @@ -40,6 +43,10 @@ public VideoCaptureFrame onPreProcessFrame(VideoCaptureFrame outFrame, VideoChan return outFrame; } mFURenderer.setInputOrientation(outFrame.rotation); + + if (FUConfig.DEVICE_LEVEL> FuDeviceUtils.DEVICE_LEVEL_MID)//高性能设备 + cheekFaceNum(); + int texId = mFURenderer.onDrawFrameDualInput(outFrame.image, outFrame.textureId, outFrame.format.getWidth(), outFrame.format.getHeight()); @@ -77,6 +84,7 @@ public void releasePreprocessor(VideoChannel.ChannelContext context) { private void startGLThread() { if (mGLHandler == null) { mGLHandler = new Handler(Looper.myLooper()); + mGLHandler.post(() -> {if (mSurfaceViewListener !=null ) mSurfaceViewListener.onSurfaceCreated();}); } } @@ -98,9 +106,40 @@ public void skipFrame() { public void releaseFURender() { renderSwitch = false; mGLHandler.removeCallbacksAndMessages(0); - mGLHandler.post(() -> FURenderer.getInstance().release()); + mGLHandler.post(() -> { + if (mSurfaceViewListener !=null ) mSurfaceViewListener.onSurfaceDestroyed(); + }); mGLHandler = null; } + private SurfaceViewListener mSurfaceViewListener; + public interface SurfaceViewListener{ + void onSurfaceCreated(); + void onSurfaceDestroyed(); + } + + public void setSurfaceListener(SurfaceViewListener surfaceViewListener) { + this.mSurfaceViewListener = surfaceViewListener; + } + + /** + * 检查当前人脸数量 + */ + private void cheekFaceNum() { + //根据有无人脸 + 设备性能 判断开启的磨皮类型 + float faceProcessorGetConfidenceScore = FUAIKit.getInstance().getFaceProcessorGetConfidenceScore(0); + if (faceProcessorGetConfidenceScore>= 0.95) { + //高端手机并且检测到人脸开启均匀磨皮,人脸点位质 + if (FURenderKit.getInstance() != null && FURenderKit.getInstance().getFaceBeauty() != null && FURenderKit.getInstance().getFaceBeauty().getBlurType() != FaceBeautyBlurTypeEnum.EquallySkin) { + FURenderKit.getInstance().getFaceBeauty().setBlurType(FaceBeautyBlurTypeEnum.EquallySkin); + FURenderKit.getInstance().getFaceBeauty().setEnableBlurUseMask(true); + } + } else { + if (FURenderKit.getInstance() != null && FURenderKit.getInstance().getFaceBeauty() != null && FURenderKit.getInstance().getFaceBeauty().getBlurType() != FaceBeautyBlurTypeEnum.FineSkin) { + FURenderKit.getInstance().getFaceBeauty().setBlurType(FaceBeautyBlurTypeEnum.FineSkin); + FURenderKit.getInstance().getFaceBeauty().setEnableBlurUseMask(false); + } + } + } } diff --git a/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/MyApplication.java b/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/MyApplication.java index fa1b1773..dc1a7edd 100644 --- a/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/MyApplication.java +++ b/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/MyApplication.java @@ -59,6 +59,10 @@ public void removeRtcHandler(RtcEngineEventHandler handler) { mRtcEventHandler.removeEventHandler(handler); } + public RtcEngineEventHandlerProxy getRtcEventHandler() { + return mRtcEventHandler; + } + public CameraVideoManager videoManager() { return mVideoManager; } diff --git a/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/RtcEngineEventHandlerProxy.java b/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/RtcEngineEventHandlerProxy.java index f50209e8..b91dba78 100644 --- a/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/RtcEngineEventHandlerProxy.java +++ b/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/RtcEngineEventHandlerProxy.java @@ -5,6 +5,7 @@ import io.agora.rtc.IRtcEngineEventHandler; public class RtcEngineEventHandlerProxy extends IRtcEngineEventHandler { + private static final String TAG = "RtcEngineEventHandlerPr"; private ArrayList mEventHandlers = new ArrayList(); public void addEventHandler(RtcEngineEventHandler handler) { @@ -42,4 +43,59 @@ public void onRemoteVideoStateChanged(int uid, int state, int reason, int elapse handler.onRemoteVideoStateChanged(uid, state, reason, elapsed); } } + + private int mCallbackCount; + private int mWidth; + private int mHeight; + private int mSumRenderFps; + private int mSumDecoderFps; + private int mSumReceivedBitrate; + + public static class StatsInfo { + public int width; + public int height; + public int renderFps; + public int decoderFps; + + public int receivedBitrate; + } + + public StatsInfo retrieveStatsInfo() { + StatsInfo statsInfo = new StatsInfo(); + synchronized (this) { + statsInfo.width = mWidth; + statsInfo.height = mHeight; + int count = mCallbackCount; + if (count> 0) { + statsInfo.renderFps = mSumRenderFps / count; + statsInfo.decoderFps = mSumDecoderFps / count; + statsInfo.receivedBitrate = mSumReceivedBitrate / count; + } + mCallbackCount = 0; + mSumRenderFps = 0; + mSumDecoderFps = 0; + mSumReceivedBitrate = 0; + } + return statsInfo; + } + + @Override + public void onRemoteVideoStats(RemoteVideoStats remoteVideoStats) { + super.onRemoteVideoStats(remoteVideoStats); + // Log.d(TAG, String.format("onRemoteVideoStats. width %d, height %d, " + +// "delay %d, receivedBitrate %d, decoderOutputFrameRate %d, rendererOutputFrameRate %d, " + +// "packetLossRate %d, totalFrozenTime %d, totalActiveTime %d, rxStreamType %d", +// remoteVideoStats.width, remoteVideoStats.height, remoteVideoStats.delay, remoteVideoStats.receivedBitrate, +// remoteVideoStats.decoderOutputFrameRate, remoteVideoStats.rendererOutputFrameRate, +// remoteVideoStats.packetLossRate, remoteVideoStats.totalFrozenTime, remoteVideoStats.totalActiveTime, +// remoteVideoStats.rxStreamType)); + synchronized (this) { + mWidth = remoteVideoStats.width; + mHeight = remoteVideoStats.height; + mSumRenderFps += remoteVideoStats.rendererOutputFrameRate; + mSumDecoderFps += remoteVideoStats.decoderOutputFrameRate; + mSumReceivedBitrate += remoteVideoStats.receivedBitrate; + ++mCallbackCount; + } + } } diff --git a/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/activities/FUChatActivity.java b/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/activities/FUChatActivity.java index f71c3882..f23a7077 100644 --- a/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/activities/FUChatActivity.java +++ b/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/activities/FUChatActivity.java @@ -11,6 +11,7 @@ import android.view.SurfaceView; import android.view.TextureView; import android.view.View; +import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.RelativeLayout; import android.widget.TextView; @@ -18,11 +19,13 @@ import com.faceunity.core.enumeration.FUAIProcessorEnum; import com.faceunity.nama.FURenderer; import com.faceunity.nama.data.FaceUnityDataFactory; -import com.faceunity.nama.dialog.ToastHelper; import com.faceunity.nama.listener.FURendererListener; import com.faceunity.nama.ui.FaceUnityView; -import java.util.concurrent.CountDownLatch; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; import io.agora.capture.video.camera.CameraVideoManager; import io.agora.capture.video.camera.Constant; @@ -32,6 +35,7 @@ import io.agora.rtc.RtcEngine; import io.agora.rtc.video.VideoCanvas; import io.agora.rtc.video.VideoEncoderConfiguration; +import io.agora.rtcwithfu.MyApplication; import io.agora.rtcwithfu.R; import io.agora.rtcwithfu.RtcEngineEventHandler; import io.agora.rtcwithfu.utils.Constants; @@ -64,6 +68,7 @@ public class FUChatActivity extends RtcBasedActivity implements RtcEngineEventHa @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.activity_base); initUI(); initRoom(); @@ -131,6 +136,17 @@ public void onCameraClosed() { TextureView localVideo = findViewById(R.id.local_video_view); mVideoManager.setLocalPreview(localVideo); + preprocessor.setSurfaceListener(new PreprocessorFaceUnity.SurfaceViewListener() { + @Override + public void onSurfaceCreated() { + mFaceUnityDataFactory.bindCurrentRenderer(); + } + + @Override + public void onSurfaceDestroyed() { + mFURenderer.release(); + } + }); } private void joinChannel() { @@ -186,7 +202,6 @@ protected void onResume() { super.onResume(); Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL); - mFaceUnityDataFactory.bindCurrentRenderer(); preprocessor.setRenderEnable(true); mVideoManager.startCapture(); } diff --git a/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/activities/MainActivity.java b/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/activities/MainActivity.java index 4d724259..c0e399be 100644 --- a/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/activities/MainActivity.java +++ b/Agora-Video-With-FaceUnity-Android/app/src/main/java/io/agora/rtcwithfu/activities/MainActivity.java @@ -12,8 +12,11 @@ import android.widget.EditText; import android.widget.Toast; -import io.agora.rtcwithfu.utils.Constants; +import com.faceunity.FUConfig; +import com.faceunity.nama.utils.FuDeviceUtils; + import io.agora.rtcwithfu.R; +import io.agora.rtcwithfu.utils.Constants; public class MainActivity extends Activity { private static final int REQUEST_CODE_ALL_PERMISSIONS = 999; @@ -25,6 +28,7 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_navigation); mChannelName = findViewById(R.id.edt_channel); checkPermissions(); + FUConfig.DEVICE_LEVEL = FuDeviceUtils.judgeDeviceLevel(this); } private void checkPermissions() { @@ -68,6 +72,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis } public void onStartBroadcastClick(View view) { + if (!isFastClick()) {return;} String name = mChannelName.getText().toString(); if (name.isEmpty()) { Toast.makeText(this, R.string.empty_room_name_toast, Toast.LENGTH_SHORT).show(); @@ -77,4 +82,18 @@ public void onStartBroadcastClick(View view) { startActivity(intent); } } + + // 两次点击按钮之间的点击间隔不能少于1000毫秒 + private static final int MIN_CLICK_DELAY_TIME = 1000; + private static long lastClickTime; + + public static boolean isFastClick() { + boolean flag = false; + long curClickTime = System.currentTimeMillis(); + if ((curClickTime - lastClickTime)>= MIN_CLICK_DELAY_TIME) { + flag = true; + } + lastClickTime = curClickTime; + return flag; + } } diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/build.gradle b/Agora-Video-With-FaceUnity-Android/faceunity/build.gradle index 079b72b3..9eb276eb 100644 --- a/Agora-Video-With-FaceUnity-Android/faceunity/build.gradle +++ b/Agora-Video-With-FaceUnity-Android/faceunity/build.gradle @@ -6,9 +6,8 @@ android { defaultConfig { minSdkVersion 19 targetSdkVersion 28 - versionCode 741 - versionName "7.4.1.0" - // 7.3.0_phy_505b959b_bf80f59 + versionCode 802 + versionName "8.0.2" } buildTypes { release { @@ -28,7 +27,7 @@ dependencies { resolutionStrategy.cacheDynamicVersionsFor 0,'seconds' } implementation 'com.android.support:appcompat-v7:28.0.0' - api 'com.faceunity:core:7.4.1.0' - implementation 'com.faceunity:model:7.4.1.0' + api 'com.faceunity:core:8.0.2' + implementation 'com.faceunity:model:8.0.2' implementation 'com.android.support:recyclerview-v7:28.0.0' } \ No newline at end of file diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/FUConfig.java b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/FUConfig.java new file mode 100644 index 00000000..7e797594 --- /dev/null +++ b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/FUConfig.java @@ -0,0 +1,8 @@ +package com.faceunity; + +import com.faceunity.nama.utils.FuDeviceUtils; + +public class FUConfig { + //设备等级默认为中级 + public static int DEVICE_LEVEL = FuDeviceUtils.DEVICE_LEVEL_MID; +} diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/FURenderer.java b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/FURenderer.java index fcd9a0e7..f7ac5e02 100644 --- a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/FURenderer.java +++ b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/FURenderer.java @@ -69,6 +69,14 @@ public static FURenderer getInstance() { /*检测标识*/ private int aIProcessTrackStatus = -1; + /** + * + * @return version + */ + public String getVersion() { + return mFURenderKit.getVersion(); + } + /** * 初始化鉴权 * @@ -122,8 +130,8 @@ public int onDrawFrameDualInput(byte[] img, int texId, int width, int height) { prepareDrawFrame(); FURenderInputData inputData = new FURenderInputData(width, height); /*注释掉Buffer配置,启用单纹理模式,防止Buffer跟纹理存在不对齐造成,美妆偏移*/ - //inputData.setImageBuffer(new FURenderInputData.FUImageBuffer(inputBufferType, img));//设置为单Buffer输入 - inputData.setTexture(new FURenderInputData.FUTexture(inputTextureType, texId)); +// inputData.setImageBuffer(new FURenderInputData.FUImageBuffer(inputBufferType, img));//设置为单Buffer输入 + inputData.setTexture(new FURenderInputData.FUTexture(inputTextureType, texId)); FURenderInputData.FURenderConfig config = inputData.getRenderConfig(); config.setExternalInputType(externalInputType); config.setInputOrientation(inputOrientation); diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/data/FaceBeautyDataFactory.java b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/data/FaceBeautyDataFactory.java index 6e2628f0..a4f4d63a 100644 --- a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/data/FaceBeautyDataFactory.java +++ b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/data/FaceBeautyDataFactory.java @@ -1,8 +1,12 @@ package com.faceunity.nama.data; + + import android.support.annotation.NonNull; +import com.faceunity.FUConfig; import com.faceunity.core.controller.facebeauty.FaceBeautyParam; +import com.faceunity.core.faceunity.FUAIKit; import com.faceunity.core.faceunity.FURenderKit; import com.faceunity.core.model.facebeauty.FaceBeauty; import com.faceunity.nama.entity.FaceBeautyBean; @@ -201,16 +205,17 @@ public void updateFilterIntensity(double intensity) { put(FaceBeautyParam.FACE_SHAPE_INTENSITY, defaultFaceBeauty::setSharpenIntensity); put(FaceBeautyParam.CHEEK_THINNING_INTENSITY, defaultFaceBeauty::setCheekThinningIntensity); put(FaceBeautyParam.CHEEK_V_INTENSITY, defaultFaceBeauty::setCheekVIntensity); - put(FaceBeautyParam.CHEEK_NARROW_INTENSITY, defaultFaceBeauty::setCheekNarrowIntensity); - put(FaceBeautyParam.CHEEK_SMALL_INTENSITY, defaultFaceBeauty::setCheekSmallIntensity); + put(FaceBeautyParam.CHEEK_NARROW_INTENSITY_V2, defaultFaceBeauty::setCheekNarrowIntensityV2); + put(FaceBeautyParam.CHEEK_SHORT_INTENSITY, defaultFaceBeauty::setCheekShortIntensity); + put(FaceBeautyParam.CHEEK_SMALL_INTENSITY_V2, defaultFaceBeauty::setCheekSmallIntensityV2); put(FaceBeautyParam.INTENSITY_CHEEKBONES_INTENSITY, defaultFaceBeauty::setCheekBonesIntensity); put(FaceBeautyParam.INTENSITY_LOW_JAW_INTENSITY, defaultFaceBeauty::setLowerJawIntensity); - put(FaceBeautyParam.EYE_ENLARGING_INTENSITY, defaultFaceBeauty::setEyeEnlargingIntensity); + put(FaceBeautyParam.EYE_ENLARGING_INTENSITY_V2, defaultFaceBeauty::setEyeEnlargingIntensityV2); put(FaceBeautyParam.EYE_CIRCLE_INTENSITY, defaultFaceBeauty::setEyeCircleIntensity); put(FaceBeautyParam.CHIN_INTENSITY, defaultFaceBeauty::setChinIntensity); - put(FaceBeautyParam.FOREHEAD_INTENSITY, defaultFaceBeauty::setForHeadIntensity); - put(FaceBeautyParam.NOSE_INTENSITY, defaultFaceBeauty::setNoseIntensity); - put(FaceBeautyParam.MOUTH_INTENSITY, defaultFaceBeauty::setMouthIntensity); + put(FaceBeautyParam.FOREHEAD_INTENSITY_V2, defaultFaceBeauty::setForHeadIntensityV2); + put(FaceBeautyParam.NOSE_INTENSITY_V2, defaultFaceBeauty::setNoseIntensityV2); + put(FaceBeautyParam.MOUTH_INTENSITY_V2, defaultFaceBeauty::setMouthIntensityV2); put(FaceBeautyParam.CANTHUS_INTENSITY, defaultFaceBeauty::setCanthusIntensity); put(FaceBeautyParam.EYE_SPACE_INTENSITY, defaultFaceBeauty::setEyeSpaceIntensity); put(FaceBeautyParam.EYE_ROTATE_INTENSITY, defaultFaceBeauty::setEyeRotateIntensity); @@ -234,16 +239,17 @@ public void updateFilterIntensity(double intensity) { put(FaceBeautyParam.FACE_SHAPE_INTENSITY, defaultFaceBeauty::getSharpenIntensity); put(FaceBeautyParam.CHEEK_THINNING_INTENSITY, defaultFaceBeauty::getCheekThinningIntensity); put(FaceBeautyParam.CHEEK_V_INTENSITY, defaultFaceBeauty::getCheekVIntensity); - put(FaceBeautyParam.CHEEK_NARROW_INTENSITY, defaultFaceBeauty::getCheekNarrowIntensity); - put(FaceBeautyParam.CHEEK_SMALL_INTENSITY, defaultFaceBeauty::getCheekSmallIntensity); + put(FaceBeautyParam.CHEEK_NARROW_INTENSITY_V2, defaultFaceBeauty::getCheekNarrowIntensityV2); + put(FaceBeautyParam.CHEEK_SHORT_INTENSITY, defaultFaceBeauty::getCheekShortIntensity); + put(FaceBeautyParam.CHEEK_SMALL_INTENSITY_V2, defaultFaceBeauty::getCheekSmallIntensityV2); put(FaceBeautyParam.INTENSITY_CHEEKBONES_INTENSITY, defaultFaceBeauty::getCheekBonesIntensity); put(FaceBeautyParam.INTENSITY_LOW_JAW_INTENSITY, defaultFaceBeauty::getLowerJawIntensity); - put(FaceBeautyParam.EYE_ENLARGING_INTENSITY, defaultFaceBeauty::getEyeEnlargingIntensity); + put(FaceBeautyParam.EYE_ENLARGING_INTENSITY_V2, defaultFaceBeauty::getEyeEnlargingIntensityV2); put(FaceBeautyParam.EYE_CIRCLE_INTENSITY, defaultFaceBeauty::getEyeCircleIntensity); put(FaceBeautyParam.CHIN_INTENSITY, defaultFaceBeauty::getChinIntensity); - put(FaceBeautyParam.FOREHEAD_INTENSITY, defaultFaceBeauty::getForHeadIntensity); - put(FaceBeautyParam.NOSE_INTENSITY, defaultFaceBeauty::getNoseIntensity); - put(FaceBeautyParam.MOUTH_INTENSITY, defaultFaceBeauty::getMouthIntensity); + put(FaceBeautyParam.FOREHEAD_INTENSITY_V2, defaultFaceBeauty::getForHeadIntensityV2); + put(FaceBeautyParam.NOSE_INTENSITY_V2, defaultFaceBeauty::getNoseIntensityV2); + put(FaceBeautyParam.MOUTH_INTENSITY_V2, defaultFaceBeauty::getMouthIntensityV2); put(FaceBeautyParam.CANTHUS_INTENSITY, defaultFaceBeauty::getCanthusIntensity); put(FaceBeautyParam.EYE_SPACE_INTENSITY, defaultFaceBeauty::getEyeSpaceIntensity); put(FaceBeautyParam.EYE_ROTATE_INTENSITY, defaultFaceBeauty::getEyeRotateIntensity); @@ -259,6 +265,7 @@ public void updateFilterIntensity(double intensity) { * FURenderKit加载当前特效 */ public void bindCurrentRenderer() { + FUAIKit.getInstance().faceProcessorSetFaceLandmarkQuality(FUConfig.DEVICE_LEVEL); mFURenderKit.setFaceBeauty(defaultFaceBeauty); } } diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/repo/FaceBeautySource.java b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/repo/FaceBeautySource.java index eb9cdf03..d38f6257 100644 --- a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/repo/FaceBeautySource.java +++ b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/repo/FaceBeautySource.java @@ -35,17 +35,18 @@ public static FaceBeauty getDefaultFaceBeauty() { recommendFaceBeauty.setFilterIntensity(0.4); /*美肤*/ recommendFaceBeauty.setBlurType(FaceBeautyBlurTypeEnum.FineSkin); - recommendFaceBeauty.setBlurIntensity(4.2); + recommendFaceBeauty.setSharpenIntensity(0.2); recommendFaceBeauty.setColorIntensity(0.3); recommendFaceBeauty.setRedIntensity(0.3); - recommendFaceBeauty.setSharpenIntensity(0.2); + recommendFaceBeauty.setBlurIntensity(4.2); /*美型*/ + recommendFaceBeauty.setFaceShapeIntensity(1.0); + recommendFaceBeauty.setEyeEnlargingIntensityV2(0.4); recommendFaceBeauty.setCheekVIntensity(0.5); - recommendFaceBeauty.setEyeEnlargingIntensity(0.4); + recommendFaceBeauty.setNoseIntensityV2(0.5); + recommendFaceBeauty.setForHeadIntensityV2(0.3); + recommendFaceBeauty.setMouthIntensityV2(0.4); recommendFaceBeauty.setChinIntensity(0.3); - recommendFaceBeauty.setForHeadIntensity(0.3); - recommendFaceBeauty.setNoseIntensity(0.5); - recommendFaceBeauty.setMouthIntensity(0.4); return recommendFaceBeauty; } @@ -128,13 +129,19 @@ public static ArrayList buildShapeParams() { ); params.add( new FaceBeautyBean( - FaceBeautyParam.CHEEK_NARROW_INTENSITY, R.string.beauty_box_cheek_narrow, + FaceBeautyParam.CHEEK_NARROW_INTENSITY_V2, R.string.beauty_box_cheek_narrow, R.drawable.icon_beauty_shape_face_narrow_close_selector, R.drawable.icon_beauty_shape_face_narrow_open_selector ) ); params.add( new FaceBeautyBean( - FaceBeautyParam.CHEEK_SMALL_INTENSITY, R.string.beauty_box_cheek_small, + FaceBeautyParam.CHEEK_SHORT_INTENSITY, R.string.beauty_box_cheek_short, + R.drawable.icon_beauty_shape_face_short_close_selector, R.drawable.icon_beauty_shape_face_short_open_selector + ) + ); + params.add( + new FaceBeautyBean( + FaceBeautyParam.CHEEK_SMALL_INTENSITY_V2, R.string.beauty_box_cheek_small, R.drawable.icon_beauty_shape_face_little_close_selector, R.drawable.icon_beauty_shape_face_little_open_selector ) ); @@ -152,7 +159,7 @@ public static ArrayList buildShapeParams() { ); params.add( new FaceBeautyBean( - FaceBeautyParam.EYE_ENLARGING_INTENSITY, R.string.beauty_box_eye_enlarge, + FaceBeautyParam.EYE_ENLARGING_INTENSITY_V2, R.string.beauty_box_eye_enlarge, R.drawable.icon_beauty_shape_enlarge_eye_close_selector, R.drawable.icon_beauty_shape_enlarge_eye_open_selector ) ); @@ -170,19 +177,19 @@ public static ArrayList buildShapeParams() { ); params.add( new FaceBeautyBean( - FaceBeautyParam.FOREHEAD_INTENSITY, R.string.beauty_box_intensity_forehead, + FaceBeautyParam.FOREHEAD_INTENSITY_V2, R.string.beauty_box_intensity_forehead, R.drawable.icon_beauty_shape_forehead_close_selector, R.drawable.icon_beauty_shape_forehead_open_selector ) ); params.add( new FaceBeautyBean( - FaceBeautyParam.NOSE_INTENSITY, R.string.beauty_box_intensity_nose, + FaceBeautyParam.NOSE_INTENSITY_V2, R.string.beauty_box_intensity_nose, R.drawable.icon_beauty_shape_thin_nose_close_selector, R.drawable.icon_beauty_shape_thin_nose_open_selector ) ); params.add( new FaceBeautyBean( - FaceBeautyParam.MOUTH_INTENSITY, R.string.beauty_box_intensity_mouth, + FaceBeautyParam.MOUTH_INTENSITY_V2, R.string.beauty_box_intensity_mouth, R.drawable.icon_beauty_shape_mouth_close_selector, R.drawable.icon_beauty_shape_mouth_open_selector ) ); @@ -244,17 +251,20 @@ public static HashMap buildModelAttributeRange() { /*美型*/ params.put(FaceBeautyParam.FACE_SHAPE_INTENSITY, new ModelAttributeData(1.0, 0.0, 0.0, 1.0)); params.put(FaceBeautyParam.CHEEK_THINNING_INTENSITY, new ModelAttributeData(0.0, 0.0, 0.0, 1.0)); + params.put(FaceBeautyParam.CHEEK_LONG_INTENSITY, new ModelAttributeData(0.0, 0.0, 0.0, 1.0)); + params.put(FaceBeautyParam.CHEEK_CIRCLE_INTENSITY, new ModelAttributeData(0.0, 0.0, 0.0, 1.0)); params.put(FaceBeautyParam.CHEEK_V_INTENSITY, new ModelAttributeData(0.5, 0.0, 0.0, 1.0)); - params.put(FaceBeautyParam.CHEEK_NARROW_INTENSITY, new ModelAttributeData(0.0, 0.0, 0.0, 0.5)); - params.put(FaceBeautyParam.CHEEK_SMALL_INTENSITY, new ModelAttributeData(0.0, 0.0, 0.0, 0.5)); + params.put(FaceBeautyParam.CHEEK_NARROW_INTENSITY_V2, new ModelAttributeData(0.0, 0.0, 0.0, 1.0)); + params.put(FaceBeautyParam.CHEEK_SHORT_INTENSITY, new ModelAttributeData(0.0, 0.0, 0.0, 1.0)); + params.put(FaceBeautyParam.CHEEK_SMALL_INTENSITY_V2, new ModelAttributeData(0.0, 0.0, 0.0, 1.0)); params.put(FaceBeautyParam.INTENSITY_CHEEKBONES_INTENSITY, new ModelAttributeData(0.0, 0.0, 0.0, 1.0)); params.put(FaceBeautyParam.INTENSITY_LOW_JAW_INTENSITY, new ModelAttributeData(0.0, 0.0, 0.0, 1.0)); - params.put(FaceBeautyParam.EYE_ENLARGING_INTENSITY, new ModelAttributeData(0.4, 0.0, 0.0, 1.0)); + params.put(FaceBeautyParam.EYE_ENLARGING_INTENSITY_V2, new ModelAttributeData(0.4, 0.0, 0.0, 1.0)); params.put(FaceBeautyParam.EYE_CIRCLE_INTENSITY, new ModelAttributeData(0.0, 0.0, 0.0, 1.0)); params.put(FaceBeautyParam.CHIN_INTENSITY, new ModelAttributeData(0.3, 0.5, 0.0, 1.0)); - params.put(FaceBeautyParam.FOREHEAD_INTENSITY, new ModelAttributeData(0.3, 0.5, 0.0, 1.0)); - params.put(FaceBeautyParam.NOSE_INTENSITY, new ModelAttributeData(0.5, 0.0, 0.0, 1.0)); - params.put(FaceBeautyParam.MOUTH_INTENSITY, new ModelAttributeData(0.4, 0.5, 0.0, 1.0)); + params.put(FaceBeautyParam.FOREHEAD_INTENSITY_V2, new ModelAttributeData(0.3, 0.5, 0.0, 1.0)); + params.put(FaceBeautyParam.NOSE_INTENSITY_V2, new ModelAttributeData(0.5, 0.0, 0.0, 1.0)); + params.put(FaceBeautyParam.MOUTH_INTENSITY_V2, new ModelAttributeData(0.4, 0.5, 0.0, 1.0)); params.put(FaceBeautyParam.CANTHUS_INTENSITY, new ModelAttributeData(0.0, 0.0, 0.0, 1.0)); params.put(FaceBeautyParam.EYE_SPACE_INTENSITY, new ModelAttributeData(0.5, 0.5, 0.0, 1.0)); params.put(FaceBeautyParam.EYE_ROTATE_INTENSITY, new ModelAttributeData(0.5, 0.5, 0.0, 1.0)); diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/utils/FuDeviceUtils.java b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/utils/FuDeviceUtils.java new file mode 100644 index 00000000..85de3301 --- /dev/null +++ b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/java/com/faceunity/nama/utils/FuDeviceUtils.java @@ -0,0 +1,583 @@ +package com.faceunity.nama.utils; + +import android.annotation.TargetApi; +import android.app.ActivityManager; +import android.content.Context; +import android.os.Build; +import android.text.TextUtils; +import android.util.Log; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class FuDeviceUtils { + + public static final String TAG = "FuDeviceUtils"; + + public static final int DEVICE_LEVEL_HIGH = 2; + public static final int DEVICE_LEVEL_MID = 1; + public static final int DEVICE_LEVEL_LOW = 0; + + /** + * The default return value of any method in this class when an + * error occurs or when processing fails (Currently set to -1). Use this to check if + * the information about the device in question was successfully obtained. + */ + public static final int DEVICEINFO_UNKNOWN = -1; + + private static final FileFilter CPU_FILTER = new FileFilter() { + @Override + public boolean accept(File pathname) { + String path = pathname.getName(); + //regex is slow, so checking char by char. + if (path.startsWith("cpu")) { + for (int i = 3; i < path.length(); i++) { + if (!Character.isDigit(path.charAt(i))) { + return false; + } + } + return true; + } + return false; + } + }; + + + /** + * Calculates the total RAM of the device through Android API or /proc/meminfo. + * + * @param c - Context object for current running activity. + * @return Total RAM that the device has, or DEVICEINFO_UNKNOWN = -1 in the event of an error. + */ + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + public static long getTotalMemory(Context c) { + // memInfo.totalMem not supported in pre-Jelly Bean APIs. + if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN) { + ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo(); + ActivityManager am = (ActivityManager) c.getSystemService(Context.ACTIVITY_SERVICE); + am.getMemoryInfo(memInfo); + if (memInfo != null) { + return memInfo.totalMem; + } else { + return DEVICEINFO_UNKNOWN; + } + } else { + long totalMem = DEVICEINFO_UNKNOWN; + try { + FileInputStream stream = new FileInputStream("/proc/meminfo"); + try { + totalMem = parseFileForValue("MemTotal", stream); + totalMem *= 1024; + } finally { + stream.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return totalMem; + } + } + + /** + * Method for reading the clock speed of a CPU core on the device. Will read from either + * {@code /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq} or {@code /proc/cpuinfo}. + * + * @return Clock speed of a core on the device, or -1 in the event of an error. + */ + public static int getCPUMaxFreqKHz() { + int maxFreq = DEVICEINFO_UNKNOWN; + try { + for (int i = 0; i < getNumberOfCPUCores(); i++) { + String filename = + "/sys/devices/system/cpu/cpu" + i + "/cpufreq/cpuinfo_max_freq"; + File cpuInfoMaxFreqFile = new File(filename); + if (cpuInfoMaxFreqFile.exists() && cpuInfoMaxFreqFile.canRead()) { + byte[] buffer = new byte[128]; + FileInputStream stream = new FileInputStream(cpuInfoMaxFreqFile); + try { + stream.read(buffer); + int endIndex = 0; + //Trim the first number out of the byte buffer. + while (Character.isDigit(buffer[endIndex]) && endIndex < buffer.length) { + endIndex++; + } + String str = new String(buffer, 0, endIndex); + Integer freqBound = Integer.parseInt(str); + if (freqBound> maxFreq) { + maxFreq = freqBound; + } + } catch (NumberFormatException e) { + //Fall through and use /proc/cpuinfo. + } finally { + stream.close(); + } + } + } + if (maxFreq == DEVICEINFO_UNKNOWN) { + FileInputStream stream = new FileInputStream("/proc/cpuinfo"); + try { + int freqBound = parseFileForValue("cpu MHz", stream); + freqBound *= 1024; //MHz -> kHz + if (freqBound> maxFreq) maxFreq = freqBound; + } finally { + stream.close(); + } + } + } catch (IOException e) { + maxFreq = DEVICEINFO_UNKNOWN; //Fall through and return unknown. + } + return maxFreq; + } + + /** + * Reads the number of CPU cores from the first available information from + * {@code /sys/devices/system/cpu/possible}, {@code /sys/devices/system/cpu/present}, + * then {@code /sys/devices/system/cpu/}. + * + * @return Number of CPU cores in the phone, or DEVICEINFO_UKNOWN = -1 in the event of an error. + */ + public static int getNumberOfCPUCores() { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) { + // Gingerbread doesn't support giving a single application access to both cores, but a + // handful of devices (Atrix 4G and Droid X2 for example) were released with a dual-core + // chipset and Gingerbread; that can let an app in the background run without impacting + // the foreground application. But for our purposes, it makes them single core. + return 1; + } + int cores; + try { + cores = getCoresFromFileInfo("/sys/devices/system/cpu/possible"); + if (cores == DEVICEINFO_UNKNOWN) { + cores = getCoresFromFileInfo("/sys/devices/system/cpu/present"); + } + if (cores == DEVICEINFO_UNKNOWN) { + cores = new File("/sys/devices/system/cpu/").listFiles(CPU_FILTER).length; + } + } catch (SecurityException e) { + cores = DEVICEINFO_UNKNOWN; + } catch (NullPointerException e) { + cores = DEVICEINFO_UNKNOWN; + } + return cores; + } + + /** + * Tries to read file contents from the file location to determine the number of cores on device. + * + * @param fileLocation The location of the file with CPU information + * @return Number of CPU cores in the phone, or DEVICEINFO_UKNOWN = -1 in the event of an error. + */ + private static int getCoresFromFileInfo(String fileLocation) { + InputStream is = null; + try { + is = new FileInputStream(fileLocation); + BufferedReader buf = new BufferedReader(new InputStreamReader(is)); + String fileContents = buf.readLine(); + buf.close(); + return getCoresFromFileString(fileContents); + } catch (IOException e) { + return DEVICEINFO_UNKNOWN; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + // Do nothing. + } + } + } + } + + /** + * Converts from a CPU core information format to number of cores. + * + * @param str The CPU core information string, in the format of "0-N" + * @return The number of cores represented by this string + */ + private static int getCoresFromFileString(String str) { + if (str == null || !str.matches("0-[\\d]+$")) { + return DEVICEINFO_UNKNOWN; + } + return Integer.valueOf(str.substring(2)) + 1; + } + + /** + * Helper method for reading values from system files, using a minimised buffer. + * + * @param textToMatch - Text in the system files to read for. + * @param stream - FileInputStream of the system file being read from. + * @return A numerical value following textToMatch in specified the system file. + * -1 in the event of a failure. + */ + private static int parseFileForValue(String textToMatch, FileInputStream stream) { + byte[] buffer = new byte[1024]; + try { + int length = stream.read(buffer); + for (int i = 0; i < length; i++) { + if (buffer[i] == '\n' || i == 0) { + if (buffer[i] == '\n') i++; + for (int j = i; j < length; j++) { + int textIndex = j - i; + //Text doesn't match query at some point. + if (buffer[j] != textToMatch.charAt(textIndex)) { + break; + } + //Text matches query here. + if (textIndex == textToMatch.length() - 1) { + return extractValue(buffer, j); + } + } + } + } + } catch (IOException e) { + //Ignore any exceptions and fall through to return unknown value. + } catch (NumberFormatException e) { + } + return DEVICEINFO_UNKNOWN; + } + + /** + * Helper method used by {@link #parseFileForValue(String, FileInputStream) parseFileForValue}. Parses + * the next available number after the match in the file being read and returns it as an integer. + * + * @param index - The index in the buffer array to begin looking. + * @return The next number on that line in the buffer, returned as an int. Returns + * DEVICEINFO_UNKNOWN = -1 in the event that no more numbers exist on the same line. + */ + private static int extractValue(byte[] buffer, int index) { + while (index < buffer.length && buffer[index] != '\n') { + if (Character.isDigit(buffer[index])) { + int start = index; + index++; + while (index < buffer.length && Character.isDigit(buffer[index])) { + index++; + } + String str = new String(buffer, 0, start, index - start); + return Integer.parseInt(str); + } + index++; + } + return DEVICEINFO_UNKNOWN; + } + + /** + * 获取当前剩余内存(ram) + * + * @param context + * @return + */ + public static long getAvailMemory(Context context) { + ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo(); + am.getMemoryInfo(mi); + return mi.availMem; + } + + /** + * 获取厂商信息 + * + * @return + */ + public static String getBrand() { + return Build.BRAND; + } + + /** + * 获取手机机型 + * + * @return + */ + public static String getModel() { + return Build.MODEL; + } + + /** + * 获取硬件信息(cpu型号) + * + * @return + */ + public static String getHardWare() { + try { + FileReader fr = new FileReader("/proc/cpuinfo"); + BufferedReader br = new BufferedReader(fr); + String text; + String last = ""; + while ((text = br.readLine()) != null) { + last = text; + } + //一般机型的cpu型号都会在cpuinfo文件的最后一行 + if (last.contains("Hardware")) { + String[] hardWare = last.split(":\\s+", 2); + return hardWare[1]; + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return Build.HARDWARE; + } + + + /** + * Level judgement based on current memory and CPU. + * + * @param context - Context object. + * @return + */ + public static int judgeDeviceLevel(Context context) { + int level; + //有一些设备不符合下述的判断规则,则走一个机型判断模式 + int specialDevice = judgeDeviceLevelInDeviceName(); + if (specialDevice>= 0) return specialDevice; + + int ramLevel = judgeMemory(context); + int cpuLevel = judgeCPU(); + if (ramLevel == 0 || ramLevel == 1 || cpuLevel == 0) { + level = DEVICE_LEVEL_LOW; + } else { + if (cpuLevel> 1) { + level = DEVICE_LEVEL_HIGH; + } else { + level = DEVICE_LEVEL_MID; + } + } + Log.d(TAG,"DeviceLevel: " + level); + return level; + } + + /** + * -1 不是特定的高低端机型 + * @return + */ + private static int judgeDeviceLevelInDeviceName() { + String currentDeviceName = getDeviceName(); + for (String deviceName:upscaleDevice) { + if (deviceName.equals(currentDeviceName)) { + return DEVICE_LEVEL_HIGH; + } + } + + for (String deviceName:middleDevice) { + if (deviceName.equals(currentDeviceName)) { + return DEVICE_LEVEL_MID; + } + } + + for (String deviceName:lowDevice) { + if (deviceName.equals(currentDeviceName)) { + return DEVICE_LEVEL_LOW; + } + } + return -1; + } + + public static final String[] upscaleDevice = {"vivo X6S A","MHA-AL00","VKY-AL00","V1838A"}; + public static final String[] lowDevice = {}; + public static final String[] middleDevice = {"OPPO R11s","PAR-AL00","MI 8 Lite","ONEPLUS A6000","PRO 6","PRO 7 Plus"}; + + /** + * 评定内存的等级. + * + * @return + */ + private static int judgeMemory(Context context) { + long ramMB = getTotalMemory(context) / (1024 * 1024); + int level = -1; + if (ramMB <= 2000) { //2G或以下的最低档 + level = 0; + } else if (ramMB <= 3000) { //2-3G + level = 1; + } else if (ramMB <= 4000) { //4G档 2018主流中端机 + level = 2; + } else if (ramMB <= 6000) { //6G档 高端机 + level = 3; + } else { //6G以上 旗舰机配置 + level = 4; + } + return level; + } + + /** + * 评定CPU等级.(按频率和厂商型号综合判断) + * + * @return + */ + private static int judgeCPU() { + int level = 0; + String cpuName = getHardWare(); + int freqMHz = getCPUMaxFreqKHz() / 1024; + + //一个不符合下述规律的高级白名单 + //如果可以获取到CPU型号名称 -> 根据不同的名称走不同判定策略 + if (!TextUtils.isEmpty(cpuName)) { + if (cpuName.contains("qcom") || cpuName.contains("Qualcomm")) { //高通骁龙 + return judgeQualcommCPU(cpuName, freqMHz); + } else if (cpuName.contains("hi") || cpuName.contains("kirin")) { //海思麒麟 + return judgeSkinCPU(cpuName, freqMHz); + } else if (cpuName.contains("MT")) {//联发科 + return judgeMTCPU(cpuName, freqMHz); + } + } + + //cpu型号无法获取的普通规则 + if (freqMHz <= 1600) { //1.5G 低端 + level = 0; + } else if (freqMHz <= 1950) { //2GHz 低中端 + level = 1; + } else if (freqMHz <= 2500) { //2.2 2.3g 中高端 + level = 2; + } else { //高端 + level = 3; + } + return level; + } + + /** + * 联发科芯片等级判定 + * + * @return + */ + private static int judgeMTCPU(String cpuName, int freqMHz) { + //P60之前的全是低端机 MT6771V/C + int level = 0; + int mtCPUVersion = getMTCPUVersion(cpuName); + if (mtCPUVersion == -1) { + //读取不出version 按照一个比较严格的方式来筛选出高端机 + if (freqMHz <= 1600) { //1.5G 低端 + level = 0; + } else if (freqMHz <= 2200) { //2GHz 低中端 + level = 1; + } else if (freqMHz <= 2700) { //2.2 2.3g 中高端 + level = 2; + } else { //高端 + level = 3; + } + } else if (mtCPUVersion < 6771) { + //均为中低端机 + if (freqMHz <= 1600) { //1.5G 低端 + level = 0; + } else { //2GHz 中端 + level = 1; + } + } else { + if (freqMHz <= 1600) { //1.5G 低端 + level = 0; + } else if (freqMHz <= 1900) { //2GHz 低中端 + level = 1; + } else if (freqMHz <= 2500) { //2.2 2.3g 中高端 + level = 2; + } else { //高端 + level = 3; + } + } + + return level; + } + + /** + * 通过联发科CPU型号定义 -> 获取cpu version + * + * @param cpuName + * @return + */ + private static int getMTCPUVersion(String cpuName) { + //截取MT后面的四位数字 + int cpuVersion = -1; + if (cpuName.length()> 5) { + String cpuVersionStr = cpuName.substring(2, 6); + try { + cpuVersion = Integer.valueOf(cpuVersionStr); + } catch (NumberFormatException exception) { + exception.printStackTrace(); + } + } + + return cpuVersion; + } + + /** + * 高通骁龙芯片等级判定 + * + * @return + */ + private static int judgeQualcommCPU(String cpuName, int freqMHz) { + int level = 0; + //xxxx inc MSM8937 比较老的芯片 + //7 8 xxx inc SDM710 + if (cpuName.contains("MSM")) { + //老芯片 + if (freqMHz <= 1600) { //1.5G 低端 + level = 0; + } else { //2GHz 低中端 + level = 1; + } + } else { + //新的芯片 + if (freqMHz <= 1600) { //1.5G 低端 + level = 0; + } else if (freqMHz <= 2000) { //2GHz 低中端 + level = 1; + } else if (freqMHz <= 2500) { //2.2 2.3g 中高端 + level = 2; + } else { //高端 + level = 3; + } + } + + return level; + } + + /** + * 麒麟芯片等级判定 + * + * @param freqMHz + * @return + */ + private static int judgeSkinCPU(String cpuName, int freqMHz) { + //型号 -> kirin710之后 & 最高核心频率 + int level = 0; + if (cpuName.startsWith("hi")) { + //这个是海思的芯片中低端 + if (freqMHz <= 1600) { //1.5G 低端 + level = 0; + } else if (freqMHz <= 2000) { //2GHz 低中端 + level = 1; + } + } else { + //这个是海思麒麟的芯片 + if (freqMHz <= 1600) { //1.5G 低端 + level = 0; + } else if (freqMHz <= 2000) { //2GHz 低中端 + level = 1; + } else if (freqMHz <= 2500) { //2.2 2.3g 中高端 + level = 2; + } else { //高端 + level = 3; + } + } + + return level; + } + + public static final String Nexus_6P = "Nexus 6P"; + + /** + * 获取设备名 + * + * @return + */ + public static String getDeviceName() { + String deviceName = ""; + if (Build.MODEL != null) deviceName = Build.MODEL; + Log.e(TAG,"deviceName: " + deviceName); + return deviceName; + } +} diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/drawable/icon_beauty_shape_face_short_close_selector.xml b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/drawable/icon_beauty_shape_face_short_close_selector.xml new file mode 100644 index 00000000..c0a88e6a --- /dev/null +++ b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/drawable/icon_beauty_shape_face_short_close_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/drawable/icon_beauty_shape_face_short_open_selector.xml b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/drawable/icon_beauty_shape_face_short_open_selector.xml new file mode 100644 index 00000000..fcb3174e --- /dev/null +++ b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/drawable/icon_beauty_shape_face_short_open_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_close_checked.png b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_close_checked.png new file mode 100644 index 00000000..c45df414 Binary files /dev/null and b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_close_checked.png differ diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_close_normal.png b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_close_normal.png new file mode 100644 index 00000000..e7a6b035 Binary files /dev/null and b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_close_normal.png differ diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_open_checked.png b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_open_checked.png new file mode 100644 index 00000000..edd4be9e Binary files /dev/null and b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_open_checked.png differ diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_open_normal.png b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_open_normal.png new file mode 100644 index 00000000..10907c06 Binary files /dev/null and b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/mipmap-xxhdpi/icon_beauty_box_face_short_open_normal.png differ diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/values-zh-rCN/strings.xml b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/values-zh-rCN/strings.xml index 728a1192..3958866f 100644 --- a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/values-zh-rCN/strings.xml +++ b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/values-zh-rCN/strings.xml @@ -37,6 +37,7 @@ 瘦脸 V脸 窄脸 + 短脸 小脸 下巴 额头 diff --git a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/values/strings.xml b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/values/strings.xml index 2f8c5246..8692ac78 100644 --- a/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/values/strings.xml +++ b/Agora-Video-With-FaceUnity-Android/faceunity/src/main/res/values/strings.xml @@ -38,6 +38,7 @@ Cheekbone Jawbone CheekNarrow + Cheek short Cheek small Chin Forehead

AltStyle によって変換されたページ (->オリジナル) /