本篇文档主要介绍在 TUICallKit 中接入美颜特效的方法。
在 Flutter 中完成自定义美颜处理,需要通过 TRTC 自定义视频渲染完成。由于 Flutter 不善于进行大量实时数据传输的特性,涉及 TRTC 的自定义视频渲染部分需要在 Native 部分完成。 具体的方案如下:
接入方案分为 3 步:
第一步:通过 MethodChannel 通道 开启/关闭 TRTC 自定义渲染逻辑;
第二步 :在 TRTC 自定义渲染处理逻辑 onProcessVideoFrame() 中使用
美颜处理模块
对原始视频帧进行处理;
第三步 : 客户的美颜处理模块也需要在 Dart 通过接口设置当前美颜的参数,客户可以通过 MethodChannel 的方式设置美颜参数。这部分客户可根据自己的需求和使用的美颜自行定制。接入第三方美颜特效
步骤1:实现 Dart 层到 Native 的“开始/结束”美颜的控制接口
实现 Dart 层接口:
final channel = MethodChannel('TUICallKitCustomBeauty');void enableTUICallKitCustomBeauty() async {await channel.invokeMethod('enableTUICallKitCustomBeauty');}void disableTUICallKitCustomBeauty() async {await channel.invokeMethod('disableTUICallKitCustomBeauty');}
实现对应 Native 层接口:
public class MainActivity extends FlutterActivity {private static final String channelName = "TUICallKitCustomBeauty";private MethodChannel channel;@Overridepublic void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {super.configureFlutterEngine(flutterEngine);channel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), channelName);channel.setMethodCallHandler(((call, result) -> {switch (call.method) {case "enableTUICallKitCustomBeauty":enableTUICallKitCustomBeauty();break;case "disableTUICallKitCustomBeauty":disableTUICallKitCustomBeauty();break;default:break;}result.success("");}));}public void enableTUICallKitCustomBeauty() {}public void disableTUICallKitCustomBeauty() {}}
@UIApplicationMain@objc class AppDelegate: FlutterAppDelegate {var channel: FlutterMethodChannel?override func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {GeneratedPluginRegistrant.register(with: self)guard let controller = window?.rootViewController as? FlutterViewController else {fatalError("Invalid root view controller")}channel = FlutterMethodChannel(name: "TUICallKitCustomBeauty", binaryMessenger: controller.binaryMessenger)channel?.setMethodCallHandler({ [weak self] call, result inguard let self = self else { return }switch (call.method) {case "enableTUICallKitCustomBeauty":self.enableTUICallKitCustomBeauty()breakcase "disableTUICallKitCustomBeauty":self.disableTUICallKitCustomBeauty()breakdefault:break}})result(nil)return super.application(application, didFinishLaunchingWithOptions: launchOptions)}func enableTUICallKitCustomBeauty() {}func disableTUICallKitCustomBeauty() {}}
步骤2:在 Native 的 TRTC 自定义渲染逻辑中完成美颜处理
注意:
Android 在接入美颜过程中需要先依赖 LiteAVSDK_Professional, 在Android工程的 app/build.gradle中添加一下依赖:
dependencies{
api "com.tencent.liteav:LiteAVSDK_Professional:latest.release"
}
void enableTUICallKitCustomBeauty() {TRTCCloud.sharedInstance(getApplicationContext()).setLocalVideoProcessListener(TRTC_VIDEO_PIXEL_FORMAT_Texture_2D,TRTC_VIDEO_BUFFER_TYPE_TEXTURE, new VideoFrameListerer());}void disableTUICallKitCustomBeauty() {TRTCCloud.sharedInstance(getApplicationContext()).setLocalVideoProcessListener(TRTC_VIDEO_PIXEL_FORMAT_Texture_2D,TRTC_VIDEO_BUFFER_TYPE_TEXTURE, null);}class VideoFrameListerer implements TRTCCloudListener.TRTCVideoFrameListener { private XXXBeautyModel mBeautyModel = XXXBeautyModel.sharedInstance();@Override public int onProcessVideoFrame(TRTCCloudDef.TRTCVideoFrame trtcVideoFrame, TRTCCloudDef.TRTCVideoFrame trtcVideoFrame1) { // 美颜处理逻辑mBeautyModel.process(trtcVideoFrame, trtcVideoFrame1);……return 0; } @Override public void onGLContextCreated() { } @Override public void onGLContextDestory() { } }
let videoFrameListener: TRTCVideoFrameListener = TRTCVideoFrameListener()func enableTUICallKitCustomBeauty() {TRTCCloud.sharedInstance().setLocalVideoProcessDelegete(videoFrameListener, pixelFormat: ._Texture_2D, bufferType: .texture)}func disableTUICallKitCustomBeauty() {TRTCCloud.sharedInstance().setLocalVideoProcessDelegete(nil, pixelFormat: ._Texture_2D, bufferType: .texture)}class TRTCVideoFrameListener: NSObject, TRTCVideoFrameDelegate {let bueutyModel = XXXXBeautyModel.shareIntance()func onProcessVideoFrame(_ srcFrame: TRTCVideoFrame, dstFrame: TRTCVideoFrame) -> UInt32 {// 美颜处理逻辑bueutyModel.onProcessVideoFrame(srcFrame, dstFrame)……return 0}}
步骤3:客户自定义第三方美颜参数控制逻辑
接入腾讯美颜特效
腾讯美颜特效的接入方法也同样遵循上述方法,现在以腾讯美颜特效为例,详细介绍接入方法:
步骤1:美颜资源下载与集成
1. 根据您购买的套餐 下载 SDK。
2. 添加文件到自己的工程中:
1. 在 app 模块下找到 build.gradle 文件,添加您对应套餐的 maven 引用地址,例如您选择的是S1-04套餐,则添加如下:
dependencies {implementation 'com.tencent.mediacloud:TencentEffect_S1-04:latest.release'}
2. 在 app 模块下找到 src/main/assets 文件夹,如果没有则创建,检查下载的 SDK 包中是否有 MotionRes 文件夹,如果有则将此文件夹拷贝到
../src/main/assets
目录下。3. 在 app 模块下找到 AndroidManifest.xml 文件,在 application 表填内添加如下标签。
<uses-native-libraryandroid:name="libOpenCL.so"android:required="true" />//此处的true 表示如果没有此库,则应用将无法正常运行。系统不允许在没有此库的设备上安装应用。//false表示应用可以使用此库(如果存在),但专门在没有此库的情况下运行(如果有必要)。系统允许安装应用,即使不存在此库也是如此。如果您使用 "false",则需要自行负责妥善处理库不存在的情况。
添加后如下图:
4. 混淆配置
如果您在打 release 包时,启用了编译优化(把 minifyEnabled 设置为 true),会裁掉一些未在 java 层调用的代码,而这些代码有可能会被 native 层调用,从而引起
no xxx method
的异常。如果您启用了这样的编译优化,那就要添加这些 keep 规则,防止 xmagic 的代码被裁掉:
-keep class com.tencent.xmagic.** { *;}-keep class org.light.** { *;}-keep class org.libpag.** { *;}-keep class org.extra.** { *;}-keep class com.gyailib.**{ *;}-keep class com.tencent.cloud.iai.lib.** { *;}-keep class com.tencent.beacon.** { *;}-keep class com.tencent.qimei.** { *;}-keep class androidx.exifinterface.** { *;}
1. 添加美颜资源到您的工程。添加后如下图(您的资源种类跟下图不完全一致):
2. 在 demo 中把 demo/lib/producer 里面的4个类:BeautyDataManager、BeautyPropertyProducer、BeautyPropertyProducerAndroid 和 BeautyPropertyProducerIOS 复制添加到自己的 Flutter 工程中,这4个类是用来配置美颜资源,把美颜类型展示在美颜面板中。
步骤2:引用 Flutter 版本 SDK
GitHub 引用:在工程的 pubspec.yaml 文件中添加如下引用:
tencent_effect_flutter:git:url: https://github.com/TencentCloud/tencenteffect-sdk-flutter
本地引用:从tencent_effect_flutter下载最新版本的 tencent_effect_flutter,然后把文件夹
android
、ios
、lib
和文件pubspec.yaml
、tencent_effect_flutter.iml
添加到工程目录下,然后在工程的 pubspec.yaml 文件中添加如下引用:(可参考demo)tencent_effect_flutter:path: ../
tencent_effect_flutter 只是提供一个桥接,里面依赖的 XMagic 默认是最新版的,真正实现美颜是 XMagic。
如果要使用最新版本的美颜 SDK,您可以通过以下步骤进行 SDK 升级:
在工程目录下执行命令:
flutter pub upgrade
或者在 subspec.yaml
页面的右上角单击 Pub upgrade。在工程目录下执行命令:flutter pub upgrade,然后在 iOS 目录下执行命令:
pod update
。步骤3:实现 Dart 层到 Native 的“开始/结束”美颜的控制接口
步骤4:在 Native 的 TRTC 自定义渲染逻辑中完成美颜处理
Android 在接入美颜过程中需要先依赖 LiteAVSDK_Professional, 在Android工程的 app/build.gradle中添加一下依赖:
dependencies{
api "com.tencent.liteav:LiteAVSDK_Professional:latest.release"
}
void enableTUICallKitCustomBeauty() {TRTCCloud.sharedInstance(getApplicationContext()).setLocalVideoProcessListener(TRTC_VIDEO_PIXEL_FORMAT_Texture_2D,TRTC_VIDEO_BUFFER_TYPE_TEXTURE, new VideoFrameListerer());}void disableTUICallKitCustomBeauty() {TRTCCloud.sharedInstance(getApplicationContext()).setLocalVideoProcessListener(TRTC_VIDEO_PIXEL_FORMAT_Texture_2D,TRTC_VIDEO_BUFFER_TYPE_TEXTURE, null);}class VideoFrameListerer implements TRTCCloudListener.TRTCVideoFrameListener {private XXXBeautyModel mBeautyModel = XXXBeautyModel.sharedInstance();@Overridepublic int onProcessVideoFrame(TRTCCloudDef.TRTCVideoFrame trtcVideoFrame,TRTCCloudDef.TRTCVideoFrame trtcVideoFrame1) {trtcVideoFrame1.texture.textureId = XmagicApiManager.getInstance() .process(trtcVideoFrame.texture.textureId, trtcVideoFrame.width, trtcVideoFrame.height);return 0;}@Overridepublic void onGLContextCreated() {}@Overridepublic void onGLContextDestory() {}}
import TXLiteAVSDK_Professionalimport tencent_effect_flutterlet videoFrameListener: TRTCVideoFrameListener = TRTCVideoFrameListener()func enableTUICallKitCustomBeauty() {TRTCCloud.sharedInstance().setLocalVideoProcessDelegete(videoFrameListener, pixelFormat: ._Texture_2D, bufferType: .texture)}func disableTUICallKitCustomBeauty() {TRTCCloud.sharedInstance().setLocalVideoProcessDelegete(nil, pixelFormat: ._Texture_2D, bufferType: .texture)}class TRTCVideoFrameListener: NSObject, TRTCVideoFrameDelegate {func onProcessVideoFrame(_ srcFrame: TRTCVideoFrame, dstFrame: TRTCVideoFrame) -> UInt32 {dstFrame.textureId = GLuint(XmagicApiManager.shareSingleton().getTextureId(ConvertBeautyFrame.convertTRTCVideoFrame(trtcVideoFrame: srcFrame)))return 0}}public class ConvertBeautyFrame: NSObject {public static func convertToTRTCPixelFormat(beautyPixelFormat: ITXCustomBeautyPixelFormat) -> TRTCVideoPixelFormat {switch beautyPixelFormat {case .Unknown:return ._Unknowncase .I420:return ._I420case .Texture2D:return ._Texture_2Dcase .BGRA:return ._32BGRAcase .NV12:return ._NV12}}public static func convertTRTCVideoFrame(trtcVideoFrame: TRTCVideoFrame) -> ITXCustomBeautyVideoFrame {let beautyVideoFrame = ITXCustomBeautyVideoFrame()beautyVideoFrame.data = trtcVideoFrame.databeautyVideoFrame.pixelBuffer = trtcVideoFrame.pixelBufferbeautyVideoFrame.width = UInt(trtcVideoFrame.width)beautyVideoFrame.height = UInt(trtcVideoFrame.height)beautyVideoFrame.textureId = trtcVideoFrame.textureIdswitch trtcVideoFrame.rotation {case ._0:beautyVideoFrame.rotation = .rotation_0case ._90:beautyVideoFrame.rotation = .rotation_90case ._180:beautyVideoFrame.rotation = .rotation_180case ._270:beautyVideoFrame.rotation = .rotation_270default:beautyVideoFrame.rotation = .rotation_0}switch trtcVideoFrame.pixelFormat {case ._Unknown:beautyVideoFrame.pixelFormat = .Unknowncase ._I420:beautyVideoFrame.pixelFormat = .I420case ._Texture_2D:beautyVideoFrame.pixelFormat = .Texture2Dcase ._32BGRA:beautyVideoFrame.pixelFormat = .BGRAcase ._NV12:beautyVideoFrame.pixelFormat = .NV12default:beautyVideoFrame.pixelFormat = .Unknown}beautyVideoFrame.bufferType = ITXCustomBeautyBufferType(rawValue: trtcVideoFrame.bufferType.rawValue) ?? .UnknownbeautyVideoFrame.timestamp = trtcVideoFrame.timestampreturn beautyVideoFrame}}
步骤5:开启美颜并设置美颜参数
完成上述配置后,可以通过
enableTUICallKitCustomBeauty()/disableTUICallKitCustomBeauty()
开启/关闭美颜。可以通过 腾讯特效美颜 Flutter 接口设置美颜参数。