Flutter

本篇文档主要介绍在 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 层接口:
Java
Swift
public class MainActivity extends FlutterActivity {
private static final String channelName = "TUICallKitCustomBeauty";
private MethodChannel channel;
@Override
public 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() {
}
}J
@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 in
guard let self = self else { return }
switch (call.method) {
case "enableTUICallKitCustomBeauty":
self.enableTUICallKitCustomBeauty()
break
case "disableTUICallKitCustomBeauty":
self.disableTUICallKitCustomBeauty()
break
default:
break
}
})
result(nil)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func enableTUICallKitCustomBeauty() {
}
func disableTUICallKitCustomBeauty() {
}
}S

步骤2:在 Native 的 TRTC 自定义渲染逻辑中完成美颜处理

注意:
Android 在接入美颜过程中需要先依赖 LiteAVSDK_Professional, 在 Android 工程的 app/build.gradle 中添加一下依赖: dependencies{ api "com.tencent.liteav:LiteAVSDK_Professional:latest.release" }
Java
Swift
Jvoid 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
}
}S

步骤3:客户自定义第三方美颜参数控制逻辑

此部分客户可以根据自己的需求使用具体的美颜模块,参见 步骤1 实现美颜参数的设置功能,具体实现根据具体使用情况决定。

接入腾讯美颜特效

腾讯美颜特效的接入方法也同样遵循上述方法,现在以腾讯美颜特效为例,详细介绍接入方法:

步骤1:美颜资源下载与集成

1. 根据您购买的套餐下载 SDK
2. 添加文件到自己的工程中:
Android
iOS
1. 在 app 模块下找到 build.gradle 文件,添加您对应套餐的 maven 引用地址,例如您选择的是 S1-04 套餐,则添加如下代码:
dependencies {
implementation 'com.tencent.mediacloud:TencentEffect_S1-04:latest.release'
}
各套餐对应的 maven 地址,请参见文档
2. 在 app 模块下找到 src/main/assets 文件夹,如果没有则创建,检查下载的 SDK 包中是否有 MotionRes 文件夹,如果有则将此文件夹拷贝到 ../src/main/assets 目录下。
3. 在 app 模块下找到 AndroidManifest.xml 文件,在 application 表填内添加如下标签。
<uses-native-library
android: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,然后把文件夹 androidioslib和文件pubspec.yamltencent_effect_flutter.iml添加到工程目录下,然后在工程的 pubspec.yaml 文件中添加如下引用:(可参考demo )
tencent_effect_flutter:
path: ../
tencent_effect_flutter 只是提供一个桥接,里面依赖的 XMagic 默认是最新版的,真正实现美颜是 XMagic。
如果要使用最新版本的美颜 SDK,您可以通过以下步骤进行 SDK 升级:
Android
iOS
在工程目录下执行命令:flutter pub upgrade 或者在 subspec.yaml 页面的右上角单击 Pub upgrade。
在工程目录下执行命令:flutter pub upgrade,然后在 iOS 目录下执行命令:pod update

步骤3:实现 Dart 层到 Native 开始/关闭美颜的控制接口

此部分可以参见 接入第三方美颜特效-步骤1

步骤4:在 Native 的 TRTC 自定义渲染逻辑中完成美颜处理

Android
iOS
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) {
trtcVideoFrame1.texture.textureId = XmagicApiManager.getInstance() .process(trtcVideoFrame.texture.textureId, trtcVideoFrame.width, trtcVideoFrame.height);
return 0;
}

@Override
public void onGLContextCreated() {
}

@Override
public void onGLContextDestory() {
}
}
import TXLiteAVSDK_Professional
import tencent_effect_flutter

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 {
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 ._Unknown
case .I420:
return ._I420
case .Texture2D:
return ._Texture_2D
case .BGRA:
return ._32BGRA
case .NV12:
return ._NV12
}
}

public static func convertTRTCVideoFrame(trtcVideoFrame: TRTCVideoFrame) -> ITXCustomBeautyVideoFrame {
let beautyVideoFrame = ITXCustomBeautyVideoFrame()
beautyVideoFrame.data = trtcVideoFrame.data
beautyVideoFrame.pixelBuffer = trtcVideoFrame.pixelBuffer
beautyVideoFrame.width = UInt(trtcVideoFrame.width)
beautyVideoFrame.height = UInt(trtcVideoFrame.height)
beautyVideoFrame.textureId = trtcVideoFrame.textureId
switch trtcVideoFrame.rotation {
case ._0:
beautyVideoFrame.rotation = .rotation_0
case ._90:
beautyVideoFrame.rotation = .rotation_90
case ._180:
beautyVideoFrame.rotation = .rotation_180
case ._270:
beautyVideoFrame.rotation = .rotation_270
default:
beautyVideoFrame.rotation = .rotation_0
}
switch trtcVideoFrame.pixelFormat {
case ._Unknown:
beautyVideoFrame.pixelFormat = .Unknown
case ._I420:
beautyVideoFrame.pixelFormat = .I420
case ._Texture_2D:
beautyVideoFrame.pixelFormat = .Texture2D
case ._32BGRA:
beautyVideoFrame.pixelFormat = .BGRA
case ._NV12:
beautyVideoFrame.pixelFormat = .NV12
default:
beautyVideoFrame.pixelFormat = .Unknown
}
beautyVideoFrame.bufferType = ITXCustomBeautyBufferType(rawValue: trtcVideoFrame.bufferType.rawValue) ?? .Unknown
beautyVideoFrame.timestamp = trtcVideoFrame.timestamp
return beautyVideoFrame
}
}

步骤5:开启美颜并设置美颜参数

完成上述配置后,可以通过 enableTUICallKitCustomBeauty()/disableTUICallKitCustomBeauty() 开启/关闭美颜。可以通过腾讯特效美颜 Flutter 接口设置美颜参数。