实现商汤美颜
本文介绍如何通过声网美颜场景化 API (Beauty API) 集成商汤美颜到实时音视频互动中。
示例项目
声网在 GitHub 上提供开源 BeautyAPI
示例项目供你参考。
准备开发环境
前提条件
开始前,请确保满足以下前提条件:
- Git
- Java Development Kit 11
- Android Studio 3.5 及以上
- Android 手机,版本 Android 5.0(API Level 21)及以上
- 开通服务
- 已联系商汤技术获取最新的美颜 SDK、美颜资源、美颜证书
- 已在项目中添加 Kotlin 插件
创建项目并集成 SDK
按照如下步骤准备开发环境:
-
如需创建新项目,在 Android Studio 里,依次选择 Phone and Tablet > Empty Activity,创建 Android 项目。
注意创建项目后,Android Studio 会自动开始同步 gradle, 稍等片刻至同步成功后再进行下一步操作。
-
使用 Maven Central 将声网 RTC SDK 集成到你的项目中。
-
在
/Gradle Scripts/build.gradle(Project: <projectname>)
文件中添加如下代码,添加 Maven Central 依赖:Kotlinbuildscript {
repositories {
...
mavenCentral()
}
...
}
allprojects {
repositories {
...
mavenCentral()
}
}注意如果你的 Android 项目设置了 dependencyResolutionManagement,添加 Maven Central 依赖的方式可能存在差异。
-
在
/Gradle Scripts/build.gradle(Module: <projectname>.app)
文件中添加如下代码,将声网 RTC SDK 集成到你的 Android 项目中:Kotlin...
dependencies {
...
// x.y.z,请填写具体的 RTC SDK 版本号,如:4.0.0 或 4.1.0-1
// 通过实时互动产品发版说明获取最新版本号
implementation 'io.agora.rtc:full-sdk:x.y.z'
}
-
-
将商汤美颜 SDK 复制到你的项目中:请联系商汤技术支持获取美颜 SDK、美颜资源、证书等文件。下载并解压文件,然后添加到美颜项目对应的文件路径下:
文件 项目路径 Android/models
app/src/main/assets/beauty_sensetime/models
Android/sample/SenseMeEffects/app/src/main/assets/sticker_face_shape
app/src/main/assets/beauty_sensetime/sticker_face_shape
Android/sample/SenseMeEffects/app/src/main/assets/style_lightly
app/src/main/assets/beauty_sensetime/style_lightly
Android/sample/SenseMeEffects/app/src/main/assets/makeup_lip
app/src/main/assets/beauty_sensetime/makeup_lip
SenseME.lic
app/src/main/assets/beauty_sensetime/license/SenseME.lic
-
将声网美颜场景化 API 集成到你的项目中。添加 Android/lib_sensetime/src/main/java/io/agora/beautyapi/sensetime 目录下的文件到项目中,具体文件如下:
utils
文件夹SenseTimeBeautyAPI.kt
文件SenseTimeBeautyAPIImpl.kt
文件
注意为方便后续代码升级,请不要修改你添加的这些文件的名称和路径。
-
添加网络及设备权限。
在
/app/Manifests/AndroidManifest.xml
文件中,在</application>
后面添加如下权限:XML<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<!-- 对于 Android 12.0 及以上且集成 v4.1.0 以下声网 RTC SDK 的设备,还需要添加以下权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<!-- 对于 Android 12.0 及以上设备,还需要添加以下权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/> -
在
/Gradle Scripts/proguard-rules.pro
文件中添加如下行,以防止声网 RTC SDK 的代码被混淆:Kotlin-keep class io.agora.**{*;}
-dontwarn javax.**
-dontwarn com.google.devtools.build.android.**
实现美颜
本节展示如何在直播间内实现美颜功能,参考 API 时序图可查看总览。声网 RTC SDK 承担实时音视频的业务,商汤美颜 SDK 提供美颜功能,声网 Beauty API 封装了两个 SDK 中的 API 调用逻辑以简化你需要实现的代码逻辑。通过 Beauty API,你可以实现基础美颜功能,但是如果你还需要更丰富的美颜效果,例如贴纸、美妆风格,请直接调用美颜 SDK 中的 API。
1. 初始化 RtcEngine
调用声网 RTC SDK 中的 create
创建并初始化 RtcEngine
对象。
// 初始化声网 RtcEngine
private val mRtcEngine by lazy {
RtcEngine.create(RtcEngineConfig().apply {
mContext = applicationContext
// 传入你从控制台获取的声网项目的 APP ID
mAppId = BuildConfig.AGORA_APP_ID
mEventHandler = object : IRtcEngineEventHandler() {}
})
}
2. 初始化美颜 SDK
创建来自美颜 SDK 的 STRenderKit
实例。
private val mSTRenderKit by lazy {
STRenderKit(
this,
"beauty_sensetime"
)
}
3. 初始化 Beauty API
调用 createSenseTimeBeautyAPI
创建 Beauty API 对象。Beauty API 对象基于 STRenderKit
对象封装。
// 创建 Beauty API 对象
private val mSenseTimeApi by lazy {
createSenseTimeBeautyAPI()
}
调用 initialize
初始化 Beauty API 对象。你需要在 config
参数中传入如下字段:
mRtcEngine
:传入之前初始化的RtcEngine
对象。mSTRenderKit
:传入之前初始化的STRenderKit
对象。captureMode
:视频的采集模式:- 如果你使用声网模块采集视频,请传入
CaptureMode.Agora
。 - 如果自定义采集视频,请传入
CaptureMode.Custom
。
- 如果你使用声网模块采集视频,请传入
statsEnable
:是否开启美颜统计数据回调。true
代表开启,false
代表不开启。开启后,会有周期性的onBeautyStats
回调事件。statsDuration
:美颜统计数据回调的周期。单位为毫秒。eventCallback
:你希望监听的回调事件。
// 初始化 Beauty API 对象
mSenseTimeApi.initialize(
Config(
// RtcEngine
mRtcEngine,
// STRenderKit
mSTRenderKit,
// 设置视频采集模式
// CaptureMode.Agora 意味着使用声网模块采集视频
// CaptureMode.Custom 意味着使用开发者自定义采集视频
captureMode = if (isCustomCaptureMode) CaptureMode.Custom else CaptureMode.Agora,
// 是否开启美颜统计数据
// 开启后,会有周期性的 onBeautyStats 回调事件
statsEnable = true,
// 设置美颜统计数据的统计区间为 1000 毫秒(默认)
statsDuration = 1000,
// 用于监听 Beauty API 的回调事件
eventCallback = object: IEventCallback{
override fun onBeautyStats(stats: BeautyStats) {
Log.d(TAG, "BeautyStats stats = $stats")
}
}
)
)
4. 开启美颜
调用 Beauty API 的 enable
方法并将参数设为 true
开启美颜。
mSenseTimeApi.enable(true)
5. 开启视频采集
开发者可以使用声网模块采集视频,也可以自定义采集视频。本节介绍在这两种场景下如何开启视频采集。
使用声网模块采集视频
使用声网模块采集视频视频时,你需要先调用 RtcEngine
类的 enableVideo
开启声网 RTC SDK 的视频模块,然后调用 Beauty API 的 setupLocalVideo
开启本地视图。
// 开启视频模块
mRtcEngine.enableVideo()
// 设置本地视图
mSenseTimeApi.setupLocalVideo(mBinding.localVideoView, Constants.RENDER_MODE_FIT)
自定义视频采集
使用自定义视频采集时,你需要进行如下操作:
- 调用
RtcEngine
类的enableVideo
开启声网 RTC SDK 的视频模块。 - 开启自定义视频采集。可以使用声网 RTC SDK 的 API 开启视频自采集,也可以使用第三方视频自采集。如下示例代码展示通过声网 RTC SDK 的 API 进行的自定义视频采集,具体逻辑为通过
RtcEngine
类的registerVideoFrameObserver
注册原始视频数据观测器并在其中实现onCaptureVideoFrame
函数。 - 完成视频自采集后,通过 Beauty API 的
onFrame
函数将外部自采集的视频数据包装成VideoFrame
传入并进行处理。当处理结果不为SKIPPED
(忽略)时,VideoFrame
里的视频 Buffer 数据会被替换成美颜处理过后的数据,你可以取出处理后的 Buffer 数据传入声网 RTC SDK。
// 开启视频模块
mRtcEngine.enableVideo()
// 注册原始视频数据观测器
// 自定义视频采集时,即 CaptureMode 为 Custom 时,你需要注册原始视频观测器
mRtcEngine.registerVideoFrameObserver(object : IVideoFrameObserver {
private var shouldMirror = true
override fun onCaptureVideoFrame(
sourceType: Int,
videoFrame: VideoFrame?
) : Boolean {
when(mSenseTimeApi.onFrame(videoFrame!!)){
// 当处理结果为 SKIPPED(忽略)时,代表你丢帧,即外部自采集的视频数据不传入声网 RTC SDK
// 当处理结果为其他时,外部自采集的视频数据传入声网 RTC SDK
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
}
}
}
// 设置是否对原始视频数据作镜像处理
override fun getMirrorApplied() = shouldMirror
// 设置观测点为本地采集时的视频数据
override fun getObservedFramePosition() = IVideoFrameObserver.POSITION_POST_CAPTURER
// override 视频观测器中的其他回调函数
...
})
6. 加入频道
调用 RtcEngine
类的 joinChannel
加入频道,同时传入如下参数:
token
:用于鉴权的动态密钥。如果在创建声网项目时启用调试模式,那么将token
参数传空。如果启用安全模式,那么你先参考使用 Token 鉴权在你的业务服务端生成 Token,然后将生成的 Token 传入该参数。channelId
:频道名。options
:频道媒体设置选项。
mRtcEngine.joinChannel(null, mChannelName, 0, ChannelMediaOptions().apply {
// 设置频道场景为直播
channelProfile = Constants.CHANNEL_PROFILE_LIVE_BROADCASTING
// 设置用户角色为主播,主播可以在频道里发布和订阅音视频流
clientRoleType = Constants.CLIENT_ROLE_BROADCASTER
// 设置是否发布摄像头采集的视频流(适用于使用声网模块采集视频的情况)
publishCameraTrack = true
// 设置是否发布自定义采集的视频流(适用于自定义采集视频的情况)
publishCustomVideoTrack = false
// 设置是否发布麦克风采集的音频流
publishMicrophoneTrack = false
// 设置进入频道时是否自动订阅频道内其他用户的音频流
autoSubscribeAudio = false
// 设置进入频道时是否自动订阅频道内其他用户的视频流
autoSubscribeVideo = true
})
7.(可选)更新摄像头配置
Beauty API 默认的镜像行为如下:
- 使用设备前置摄像头时,本地和远端视图都使用镜像。
- 使用设别后置摄像头时,本地和远端视图都不使用镜像。
如果默认的摄像头配置不满足你的业务需求,你可以参考本节更新摄像头配置。具体步骤如下:
调用 Beauty API 的 updateCameraConfig
并通过 cameraConfig
配置前置和后置摄像头的镜像效果。所有镜像类型包含如下:
MIRROR_LOCAL_REMOTE
:本地和远端视图都使用镜像。前置摄像头默认使用该配置。MIRROR_LOCAL_ONLY
:本地视图使用镜像,远端视图不使用镜像。建议在直播画面中会出现告示牌或者文字的情况下使用该配置。MIRROR_REMOTE_ONLY
:本地视图不使用镜像,远端视图使用镜像。MIRROR_NONE
:本地和远端视图都不使用镜像。后置摄像头默认使用该配置。
val isFront = mSenseTimeApi.isFrontCamera()
// 判断 isFrontCamera
if (isFront) {
cameraConfig = CameraConfig(
// 通过 frontMirror 配置前置摄像头
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
)
} else {
cameraConfig = CameraConfig(
frontMirror = cameraConfig.frontMirror,
// 通过 backMirror 配置后置摄像头
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
}
)
}
// 更新摄像头配置
mSenseTimeApi.updateCameraConfig(cameraConfig)
8. 离开频道
调用 RtcEngine
类的 leaveChannel
离开频道。
mRtcEngine.leaveChannel()
9. 销毁资源
调用 Beauty API 的 release
销毁 Beauty API。
mSenseTimeApi.release()
调用美颜 SDK 的 release
销毁 STRenderKit
。
mSTRenderKit.release()
调用 RtcEngine
的 destroy
销毁 RtcEngine
。
RtcEngine.destroy()