Skip to content

Commit

Permalink
Merge pull request #4 from AgoraIO-Community/dev/1.0.2
Browse files Browse the repository at this point in the history
Dev/1.0.2
  • Loading branch information
xgfd3 authored Aug 16, 2023
2 parents 1cad2e2 + a4dc824 commit cfc2947
Show file tree
Hide file tree
Showing 120 changed files with 3,051 additions and 8,568 deletions.
10 changes: 5 additions & 5 deletions Android/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ _English | [中文](README.zh.md)
2. FaceUnity
Put the FaceUnity beauty resources into the corresponding path

| FaceUnity Beauty Resources | Location |
|-------------------------------------|------------------------------------------------------|
| makeup resource(e.g. naicha.bundle) | app/src/main/assets/beauty_faceunity/makeup |
| sticker resource(e.g. fashi.bundle) | app/src/main/assets/beauty_faceunity/sticker |
| authpack.java | app/src/main/java/io/agora/beauty/demo/authpack.java |
| FaceUnity Beauty Resources | Location |
|-------------------------------------|---------------------------------------------------------|
| makeup resource(e.g. naicha.bundle) | app/src/main/assets/beauty_faceunity/makeup |
| sticker resource(e.g. fashi.bundle) | app/src/main/assets/beauty_faceunity/sticker |
| authpack.java | app/src/main/java/io/agora/beautyapi/demo/authpack.java |

3. ByteDance
Unzip the ByteDance beauty resource and copy the following files/directories to the corresponding path
Expand Down
10 changes: 5 additions & 5 deletions Android/README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@
2. 相芯美颜
将相芯美颜资源放入对应路径下

| 美颜资源 | 项目路径 |
|----------------------|-------------------------------------------------------|
| 美妆资源(如naicha.bundle) | app/src/main/assets/beauty_faceunity/makeup |
| 贴纸资源(如fashi.bundle) | app/src/main/assets/beauty_faceunity/sticker |
| 证书authpack.java | app/src/main/java/io/agora/beauty/demo/authpack.java |
| 美颜资源 | 项目路径 |
|----------------------|---------------------------------------------------------|
| 美妆资源(如naicha.bundle) | app/src/main/assets/beauty_faceunity/makeup |
| 贴纸资源(如fashi.bundle) | app/src/main/assets/beauty_faceunity/sticker |
| 证书authpack.java | app/src/main/java/io/agora/beautyapi/demo/authpack.java |

3. 字节/火山美颜
解压字节/火山美颜资源并复制以下文件/目录到对应路径下
Expand Down
13 changes: 11 additions & 2 deletions Android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ android {
applicationId "io.agora.entfull"
minSdkVersion 21
targetSdkVersion 31
versionCode 1
versionName "1.0.0"
versionCode 2
versionName "1.0.2"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
Expand Down Expand Up @@ -58,6 +58,15 @@ android {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}

applicationVariants.all {
variant ->
variant.outputs.all { output ->
outputFileName = new File(rootProject.name + "_" +
"v" + defaultConfig.versionName + "_" +
new Date().format("yyyyMMddHHmm") + ".apk")
}
}
}

dependencies {
Expand Down
189 changes: 146 additions & 43 deletions Android/app/src/main/java/io/agora/beautyapi/demo/ByteDanceActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@ package io.agora.beautyapi.demo

import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.SurfaceView
import android.widget.Toast
import androidx.activity.ComponentActivity
import com.bytedance.labcv.effectsdk.RenderManager
import io.agora.base.VideoFrame
import io.agora.beautyapi.bytedance.BeautyPreset
import io.agora.beautyapi.bytedance.CameraConfig
import io.agora.beautyapi.bytedance.CaptureMode
import io.agora.beautyapi.bytedance.Config
import io.agora.beautyapi.bytedance.ErrorCode
import io.agora.beautyapi.bytedance.EventCallback
import io.agora.beautyapi.bytedance.MirrorMode
import io.agora.beautyapi.bytedance.createByteDanceBeautyAPI
import io.agora.beautyapi.bytedance.utils.AssetsResourcesHelper
import io.agora.beautyapi.bytedance.utils.EffectManager
import io.agora.beautyapi.demo.databinding.BeautyActivityBinding
import io.agora.beautyapi.demo.utils.FileUtils
import io.agora.beautyapi.demo.utils.ReflectUtils
import io.agora.rtc2.ChannelMediaOptions
import io.agora.rtc2.Constants
Expand All @@ -28,10 +32,10 @@ import io.agora.rtc2.video.IVideoFrameObserver
import io.agora.rtc2.video.VideoCanvas
import io.agora.rtc2.video.VideoEncoderConfiguration
import io.agora.rtc2.video.VideoEncoderConfiguration.FRAME_RATE
import java.util.concurrent.Executors

class ByteDanceActivity : ComponentActivity() {
private val TAG = this.javaClass.simpleName
private val LICENSE_NAME = "agora_test_20220805_20230815_io.agora.entfull_4.2.3.licbag"

companion object {
private const val EXTRA_CHANNEL_NAME = "ChannelName"
Expand Down Expand Up @@ -77,6 +81,8 @@ class ByteDanceActivity : ComponentActivity() {
if (mBinding.remoteVideoView.tag == null) {
mBinding.remoteVideoView.tag = uid
val renderView = SurfaceView(this@ByteDanceActivity)
renderView.setZOrderMediaOverlay(true)
renderView.setZOrderOnTop(true)
mBinding.remoteVideoView.addView(renderView)
mRtcEngine.setupRemoteVideo(
VideoCanvas(
Expand Down Expand Up @@ -109,15 +115,6 @@ class ByteDanceActivity : ComponentActivity() {
enableExtension("agora_video_filters_clear_vision", "clear_vision", true)
}
}
private val mEffectManager by lazy {
val resourceHelper =
AssetsResourcesHelper(this, "beauty_bytedance")
EffectManager(
this,
resourceHelper,
resourceHelper.getLicensePath(LICENSE_NAME)
)
}
private val mByteDanceApi by lazy {
createByteDanceBeautyAPI()
}
Expand Down Expand Up @@ -158,30 +155,37 @@ class ByteDanceActivity : ComponentActivity() {
}
}
}
private var cameraConfig = CameraConfig()
private val renderManager = ByteDanceBeautySDK.renderManager


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(mBinding.root)
window.decorView.keepScreenOn = true
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

val isCustomCaptureMode =
intent.getStringExtra(EXTRA_CAPTURE_MODE) == getString(R.string.beauty_capture_custom)

mByteDanceApi.initialize(
Config(
applicationContext,
mRtcEngine,
mEffectManager,
renderManager,
captureMode = if (isCustomCaptureMode) CaptureMode.Custom else CaptureMode.Agora,
statsEnable = true,
cameraConfig = cameraConfig,
eventCallback = EventCallback(
onBeautyStats = {stats ->
Log.d(TAG, "BeautyStats stats = $stats")
},
onEffectInitialized = {
ByteDanceBeautySDK.initEffect(applicationContext)
Log.d(TAG, "onEffectInitialized")
},
onEffectDestroyed = {
ByteDanceBeautySDK.unInitEffect()
Log.d(TAG, "onEffectInitialized")
}
)
Expand All @@ -207,30 +211,13 @@ class ByteDanceActivity : ComponentActivity() {

if (isCustomCaptureMode) {
mRtcEngine.registerVideoFrameObserver(object : IVideoFrameObserver {
private var shouldMirror = true

override fun onCaptureVideoFrame(
sourceType: Int,
videoFrame: VideoFrame?
) : Boolean {
when(mByteDanceApi.onFrame(videoFrame!!)){
ErrorCode.ERROR_OK.value -> {
shouldMirror = false
return true
}
ErrorCode.ERROR_FRAME_SKIPPED.value ->{
shouldMirror = false
return false
}
else -> {
val mirror = videoFrame.sourceType == VideoFrame.SourceType.kFrontCamera
if(shouldMirror != mirror){
shouldMirror = mirror
return false
}
return true
}
}
) = when (mByteDanceApi.onFrame(videoFrame!!)) {
ErrorCode.ERROR_FRAME_SKIPPED.value -> false
else -> true
}

override fun onPreEncodeVideoFrame(
Expand All @@ -255,7 +242,7 @@ class ByteDanceActivity : ComponentActivity() {

override fun getRotationApplied() = false

override fun getMirrorApplied() = shouldMirror
override fun getMirrorApplied() = mByteDanceApi.getMirrorApplied()

override fun getObservedFramePosition() = IVideoFrameObserver.POSITION_POST_CAPTURER
})
Expand Down Expand Up @@ -295,19 +282,27 @@ class ByteDanceActivity : ComponentActivity() {
mBinding.ctvFaceBeauty.setOnClickListener {
val enable = !mBinding.ctvFaceBeauty.isChecked
mBinding.ctvFaceBeauty.isChecked = enable
mByteDanceApi.setBeautyPreset(if (enable) BeautyPreset.DEFAULT else BeautyPreset.CUSTOM)
mByteDanceApi.setBeautyPreset(
if (enable) BeautyPreset.DEFAULT else BeautyPreset.CUSTOM,
ByteDanceBeautySDK.beautyNodePath,
ByteDanceBeautySDK.beauty4ItemsNodePath,
ByteDanceBeautySDK.reSharpNodePath
)
}
mBinding.ctvMarkup.setOnClickListener {
val enable = !mBinding.ctvMarkup.isChecked
mBinding.ctvMarkup.isChecked = enable
mEffectManager.appendComposeNodes(arrayOf("style_makeup/tianmei"))
mEffectManager.updateComposerNodeIntensity(
"style_makeup/tianmei",

val tianmeiNode = ByteDanceBeautySDK.makeupTianmeiNodePath
renderManager.appendComposerNodes(arrayOf(tianmeiNode))
renderManager.loadResourceWithTimeout(-1)
renderManager.updateComposerNodes(
tianmeiNode,
"Filter_ALL",
if (enable) 0.5f else 0f
)
mEffectManager.updateComposerNodeIntensity(
"style_makeup/tianmei",
renderManager.updateComposerNodes(
tianmeiNode,
"Makeup_ALL",
if (enable) 0.5f else 0f
)
Expand All @@ -316,20 +311,128 @@ class ByteDanceActivity : ComponentActivity() {
val enable = !mBinding.ctvSticker.isChecked
mBinding.ctvSticker.isChecked = enable
if(enable){
mEffectManager.setSticker("wochaotian")
renderManager.setSticker("${ByteDanceBeautySDK.stickerPath}/wochaotian")
}else{
mEffectManager.setSticker(null)
renderManager.setSticker(null)
}
}
mBinding.ivMirror.setOnClickListener {
val isFront = mByteDanceApi.isFrontCamera()
if(isFront){
cameraConfig = CameraConfig(
frontMirror = when (cameraConfig.frontMirror) {
MirrorMode.MIRROR_LOCAL_REMOTE -> MirrorMode.MIRROR_LOCAL_ONLY
MirrorMode.MIRROR_LOCAL_ONLY -> MirrorMode.MIRROR_REMOTE_ONLY
MirrorMode.MIRROR_REMOTE_ONLY -> MirrorMode.MIRROR_NONE
MirrorMode.MIRROR_NONE -> MirrorMode.MIRROR_LOCAL_REMOTE
},
backMirror = cameraConfig.backMirror
)
Toast.makeText(this, "frontMirror=${cameraConfig.frontMirror}", Toast.LENGTH_SHORT).show()
} else {
cameraConfig =CameraConfig(
frontMirror = cameraConfig.frontMirror,
backMirror = when (cameraConfig.backMirror) {
MirrorMode.MIRROR_NONE -> MirrorMode.MIRROR_LOCAL_REMOTE
MirrorMode.MIRROR_LOCAL_REMOTE -> MirrorMode.MIRROR_LOCAL_ONLY
MirrorMode.MIRROR_LOCAL_ONLY -> MirrorMode.MIRROR_REMOTE_ONLY
MirrorMode.MIRROR_REMOTE_ONLY -> MirrorMode.MIRROR_NONE
}
)
Toast.makeText(this, "backMirror=${cameraConfig.backMirror}", Toast.LENGTH_SHORT).show()
}
mByteDanceApi.updateCameraConfig(cameraConfig)
}
}

override fun onDestroy() {
super.onDestroy()
mRtcEngine.leaveChannel()
mByteDanceApi.release()
mEffectManager.destroy()
RtcEngine.destroy()
}


}

object ByteDanceBeautySDK {
private val TAG = "ByteDanceBeautySDK"

private val LICENSE_NAME = "agora_test_20220805_20230815_io.agora.entfull_4.2.3.licbag"
private val workerThread = Executors.newSingleThreadExecutor()

val renderManager = RenderManager()
var licensePath = ""
var modelsPath = ""
var beautyNodePath = ""
var beauty4ItemsNodePath = ""
var reSharpNodePath = ""
var makeupTianmeiNodePath = ""
var stickerPath = ""



fun initBeautySDK(context: Context){
val storagePath = context.getExternalFilesDir("")?.absolutePath ?: return
val assetsPath = "beauty_bytedance"

workerThread.execute {
// copy license
licensePath = "$storagePath/beauty_bytedance/LicenseBag.bundle/$LICENSE_NAME"
FileUtils.copyAssets(context, "$assetsPath/LicenseBag.bundle/$LICENSE_NAME", licensePath)

// copy models
modelsPath = "$storagePath/beauty_bytedance/ModelResource.bundle"
FileUtils.copyAssets(context, "$assetsPath/ModelResource.bundle", modelsPath)

// copy beauty node
beautyNodePath = "$storagePath/beauty_bytedance/ComposeMakeup.bundle/ComposeMakeup/beauty_Android_lite"
FileUtils.copyAssets(context, "$assetsPath/ComposeMakeup.bundle/ComposeMakeup/beauty_Android_lite", beautyNodePath)

// copy beauty 4items node
beauty4ItemsNodePath = "$storagePath/beauty_bytedance/ComposeMakeup.bundle/ComposeMakeup/beauty_4Items"
FileUtils.copyAssets(context, "$assetsPath/ComposeMakeup.bundle/ComposeMakeup/beauty_4Items", beauty4ItemsNodePath)

// copy resharp node
reSharpNodePath = "$storagePath/beauty_bytedance/ComposeMakeup.bundle/ComposeMakeup/reshape_lite"
FileUtils.copyAssets(context, "$assetsPath/ComposeMakeup.bundle/ComposeMakeup/reshape_lite", reSharpNodePath)

// copy makeup node
makeupTianmeiNodePath = "$storagePath/beauty_bytedance/ComposeMakeup.bundle/ComposeMakeup/style_makeup/tianmei"
FileUtils.copyAssets(context, "$assetsPath/ComposeMakeup.bundle/ComposeMakeup/style_makeup/tianmei", makeupTianmeiNodePath)

// copy stickers
stickerPath = "$storagePath/beauty_bytedance/StickerResource.bundle/stickers"
FileUtils.copyAssets(context, "$assetsPath/StickerResource.bundle/stickers", stickerPath)
}
}

// GL Thread
fun initEffect(context: Context){
val ret = renderManager.init(
context,
modelsPath, licensePath, false, false, 0
)
if(!checkResult("RenderManager init ", ret)){
return
}
renderManager.useBuiltinSensor(true)
renderManager.set3Buffer(false)
renderManager.appendComposerNodes(arrayOf(beautyNodePath, beauty4ItemsNodePath, reSharpNodePath))
renderManager.loadResourceWithTimeout(-1)
}

// GL Thread
fun unInitEffect(){
renderManager.release()
}

private fun checkResult(msg: String, ret: Int): Boolean {
if (ret != 0 && ret != -11 && ret != 1) {
val log = "$msg error: $ret"
Log.e(TAG, log)
return false
}
return true
}
}
Loading

0 comments on commit cfc2947

Please sign in to comment.