腾讯美颜
更新时间: 2025/06/20 15:39:55
网易云信 NERTC SDK 支持接入腾讯美颜(TEBeautyKit)SDK,实现美颜、美妆、滤镜、贴纸等丰富美颜特效。在视频社交、在线教育、直播互动等场景中,您可以快速构建具备专业美颜能力的应用,提升用户在视频通话或直播过程中的形象表现力。
功能概述
通过集成腾讯美颜 SDK,您可以在 NERTC 音视频通话中实现以下功能:
- 智能美颜:磨皮、美白等基础美颜,以及大眼、瘦脸、V 脸、下巴调整等面部微调
- 美妆特效:口红、眼影、腮红等美妆效果
- 特效滤镜:多种风格滤镜,满足不同场景需求
- 贴纸道具:丰富的 2D、3D 贴纸,增强互动趣味性
工作原理

- NERTC SDK 通过
onNERtcEngineVideoFrameCaptured
回调方法将采集到的视频帧数据传递给应用层,应用层将视频帧传递给腾讯美颜 SDK 进行美颜处理。 - 腾讯美颜 SDK 处理完成后,将美颜后的视频帧返回给应用层。
- 应用层将美颜后的视频帧数据回写到原始的
pixelBuffer
中。 - NERTC SDK 将美颜后的视频帧进行编码和传输。
注意事项
- 图像格式转换:腾讯美颜 SDK 处理后的数据格式可能与原始格式不同,需要进行适当的格式转换。
- 图像方向:在设备旋转时,需要重新设置腾讯美颜的图像方向。建议在收到设备方向变化通知时,及时更新美颜 SDK 的图像方向设置。
- 内存管理:处理视频帧时需要注意内存的锁定和解锁,避免内存访问错误。
- 系统版本:腾讯美颜 SDK 支持的最低系统版本为 iOS 12.2,请确保您的应用适配该版本。
- 资源释放:在退出通话或应用退出时,需要正确释放美颜相关资源,避免内存泄漏。
- 避免黑屏:在美颜处理过程中,可能会出现黑屏的情况。请确保检查美颜资源是否正确加载,以及图像方向设置是否正确。同时确保 CVPixelBuffer 格式转换过程正确无误。
前提条件
在集成腾讯美颜 SDK 前,请确保您已完成以下准备工作:
- 已获取网易云信 AppKey
- 已集成 NERTC SDK 到您的项目中
- 已实现基础音视频通话功能
- 已从腾讯云获取以下资源:
第一步:环境集成
-
集成网易云信 NERTC SDK。如果您已完成本步骤,请跳过此步。
-
根据 更新日志 选择 NERTC SDK 版本号。
-
使用 CocoaPods 集成 NERTC SDK:
Ruby
pod 'NERtcSDK', '~> 5.8.20' # 请使用您项目中的实际版本
-
-
集成腾讯美颜 SDK。详细步骤请参考《腾讯美颜 SDK》集成文档。建议使用 TEBeautyKit 组件,可以更便捷地接入腾讯美颜功能。
-
下载并解压 TEBeautyKit.zip,文件由腾讯美颜官方提供。
-
把
TEBeautyKit
文件夹拷贝到自己的工程中,和podfile
同级目录。 -
编辑
podfile
文件,添加下面的代码:Ruby
pod 'TEBeautyKit',:path => 'TEBeautyKit/TEBeautyKit.podspec'
-
执行
pod install
。
-
第二步:初始化 SDK
建议在网易云信 RTC SDK 加入房间前完成腾讯美颜 SDK 的相关初始化和设置。
-
腾讯美颜 License 配置,确保鉴权成功。
Objective-C
[TEBeautyKit setTELicense:@"your_tencent_license" key:@"your_tencent_key" completion:^(NSInteger authresult, NSString * _Nullable errorMsg) { NSLog(@"----------result: %zd %@",authresult,errorMsg); }];
-
配置美颜素材路径。
如果 JSON 文件中配置的素材是本地的,您需要将美颜素材添加到工程中。
Objective-C
- (void)initBeautyJson{ [[TEUIConfig shareInstance] setPanelLevel:S1_07]; //根据美颜套餐选择 }
-
初始化并添加
TEPanelView
。Objective-C
-(TEPanelView *)tePanelView{ if (!_tePanelView) { _tePanelView = [[TEPanelView alloc] init:nil comboType:nil]; _tePanelView.delegate = self; } return _tePanelView; } [self.view addSubview:self.tePanelView]; [self.tePanelView mas_makeConstraints:^(MASConstraintMaker *make) { make.width.mas_equalTo(self.view); make.centerX.mas_equalTo(self.view); make.height.mas_equalTo(220); make.bottom.mas_equalTo(self.view.mas_bottom); }];
第三步:视频处理流程
-
创建视频数据转换工具类和美颜处理所需对象。
Objective-C
@interface YourClassName () <NERtcEngineDelegateEx> @property (nonatomic, strong) XMagic *xMagicKit; @property (nonatomic, strong) TEBeautyKit *teBeautyKit; @property (nonatomic, strong) TEImageTransform *transForm; @end @implementation YourClassName - (void)setupVideoProcessing { // 创建数据转换工具对象 self.transForm = [[TEImageTransform alloc] init]; // 创建腾讯美颜对象 self.teBeautyKit = [[TEBeautyKit alloc] init]; __weak __typeof(self)weakSelf = self; [TEBeautyKit create:^(XMagic * _Nullable api) { __strong typeof(self) strongSelf = weakSelf; strongSelf.xMagicKit = api; [strongSelf.teBeautyKit setXMagicApi:api]; strongSelf.tePanelView.teBeautyKit = strongSelf.teBeautyKit; [strongSelf.teBeautyKit setTePanelView:strongSelf.tePanelView]; [strongSelf.teBeautyKit setLogLevel:YT_SDK_ERROR_LEVEL]; strongSelf.tePanelView.beautyKitApi = api; [strongSelf.xMagicKit registerSDKEventListener:strongSelf]; }]; }
-
实现 NERTC SDK 的视频帧回调。
Objective-C
// NERTC SDK 视频采集数据回调 - (void)onNERtcEngineVideoFrameCaptured:(CVPixelBufferRef)pixelBuffer rotation:(NERtcVideoRotationType)rotation { // 美颜对象检查 if (!self.teBeautyKit || !self.xMagicKit || !self.transForm) { // 检查美颜 SDK 对象是否已初始化 return; } // ⚠️ 转换 NERTC 的旋转角度为腾讯美颜 SDK 的旋转角度 YtLightDeviceCameraOrientation teOrientation = YtLightCameraRotation0; switch (rotation) { case kNERtcVideoRotation_0: teOrientation = YtLightCameraRotation0; break; case kNERtcVideoRotation_90: teOrientation = YtLightCameraRotation90; break; case kNERtcVideoRotation_180: teOrientation = YtLightCameraRotation180; break; case kNERtcVideoRotation_270: teOrientation = YtLightCameraRotation270; break; default: break; } // ⚠️ 设置图像方向 [self.xMagicKit setImageOrientation:teOrientation]; // 处理视频帧 YTProcessOutput *output = [self.teBeautyKit processPixelData:pixelBuffer withOrigin:YtLightImageOriginTopLeft withOrientation:YtLightCameraRotationAuto]; if (output.pixelData.data == NULL) { return; } // 确定网易云信 RTC SDK 数据的像素格式类型 OSType pixelType = CVPixelBufferGetPixelFormatType(pixelBuffer); TEPixelFormatType destFormatType = TE_NV12V; switch (pixelType) { case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: destFormatType = TE_NV12V; break; case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange: destFormatType = TE_NV12F; break; case kCVPixelFormatType_32BGRA: destFormatType = TE_BGRA; break; default: break; } // 腾讯美颜处理完后的数据格式与网易云信 RTC SDK 回调数据的原始格式不相同,需要将格式转换回去 CVPixelBufferRef destBuffer = [self.transForm transformCVPixelBufferToBuffer:output.pixelData.data outputFormat:destFormatType]; // 将美颜处理过的数据,填充回 NERTC SDK 采集数据回调的内存地址中 [self.class ConvertPixBuffer:destBuffer toDestPixBuffer:pixelBuffer]; } // 像素数据拷贝方法 + (void)ConvertPixBuffer:(CVPixelBufferRef)srcPixelBuffer toDestPixBuffer:(CVPixelBufferRef)outPixelBuffer { size_t width = CVPixelBufferGetWidth(srcPixelBuffer); size_t height = CVPixelBufferGetHeight(srcPixelBuffer); size_t bytesPerRow = CVPixelBufferGetBytesPerRow(srcPixelBuffer); OSType pixelType = CVPixelBufferGetPixelFormatType(srcPixelBuffer); size_t destWidth = CVPixelBufferGetWidth(outPixelBuffer); size_t destHeight = CVPixelBufferGetHeight(outPixelBuffer); size_t destBytesPerRow = CVPixelBufferGetBytesPerRow(outPixelBuffer); OSType destPixelType = CVPixelBufferGetPixelFormatType(outPixelBuffer); // 检查源缓冲区和目标缓冲区的参数是否一致 if (width != destWidth || height != destHeight || bytesPerRow != destBytesPerRow || pixelType != destPixelType) { return; } BOOL isPlanar = CVPixelBufferIsPlanar(srcPixelBuffer); if (isPlanar) { size_t srcCount = CVPixelBufferGetPlaneCount(srcPixelBuffer); CVPixelBufferLockBaseAddress(srcPixelBuffer, 0); CVPixelBufferLockBaseAddress(outPixelBuffer, 0); for (size_t i = 0; i < srcCount; i++) { void *srcBaseAddress = CVPixelBufferGetBaseAddressOfPlane(srcPixelBuffer, i); size_t srcBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(srcPixelBuffer, i); size_t srcHeight = CVPixelBufferGetHeightOfPlane(srcPixelBuffer, i); size_t srcLength = srcBytesPerRow * srcHeight; void *destBaseAddress = CVPixelBufferGetBaseAddressOfPlane(outPixelBuffer, i); memcpy(destBaseAddress, srcBaseAddress, srcLength); } CVPixelBufferUnlockBaseAddress(outPixelBuffer, 0); CVPixelBufferUnlockBaseAddress(srcPixelBuffer, 0); } else { CVPixelBufferLockBaseAddress(srcPixelBuffer, 0); CVPixelBufferLockBaseAddress(outPixelBuffer, 0); void *srcBaseAddress = CVPixelBufferGetBaseAddress(srcPixelBuffer); size_t srcLength = bytesPerRow * height; void *destBaseAddress = CVPixelBufferGetBaseAddress(outPixelBuffer); memcpy(destBaseAddress, srcBaseAddress, srcLength); CVPixelBufferUnlockBaseAddress(outPixelBuffer, 0); CVPixelBufferUnlockBaseAddress(srcPixelBuffer, 0); } }
-
启用 NERTC SDK 的视频采集:
Objective-C
// 在加入房间之前,设置参数开启摄像头采集数据的回调 NSDictionary *params = @{kNERtcKeyVideoCaptureObserverEnabled : @YES}; [[NERtcEngine sharedEngine] setParameters:params]; // 设置代理以接收视频帧回调 [engine setDelegate:self]; // 启用视频功能 [engine enableLocalVideo:YES];
第四步:资源释放
在退出通话或应用退出时,需要正确释放美颜相关资源:
Objective-C- (void)dealloc {
//释放美颜资源
[self.teBeautyKit onDestroy];
// 释放其他资源
self.transForm = nil;
self.teBeautyKit = nil;
self.xMagicKit = nil;
}
此文档是否对你有帮助?