火山美颜
更新时间: 2025/06/30 18:26:46
网易云信 NERTC SDK 支持接入字节跳动火山引擎智能美化特效 SDK(下文简称火山美颜 SDK),实现美颜、美妆、滤镜、贴纸等丰富美颜特效。在视频社交、在线教育、直播互动等场景中,您可以快速构建具备专业美颜能力的应用,提升用户在视频通话或直播过程中的形象表现力。
功能概述
通过集成火山美颜 SDK,您可以在 NERTC 音视频通话中实现以下功能:
- 美化滤镜:支持美颜、滤镜、美妆、微整形、美体特效等多种技术。
- 贴纸道具:抖音同款上万款爆款特效贴纸,效果逼真、创新有趣。
- 特效创作工具:简单易操作,支持 2D、3D 多种特效能力,为企业设计师提供可视化特效制作工具。
- 端上智能算法:200+ 自研视觉算法,低能耗、高精度、高召回。
工作原理

- NERTC SDK 通过视频采集回调接口
onNERtcEngineVideoFrameCaptured
将采集到的视频帧数据回调给应用层。 - 应用层将视频帧传递给火山美颜 SDK 进行美颜处理。
- 火山美颜 SDK 处理完成后,将美颜后的视频帧返回给应用层。
- 应用层将美颜后的视频帧返回给 NERTC SDK 进行编码和传输。
注意事项
- OpenGL 上下文:火山美颜 SDK 全程依赖 OpenGL 环境,必须保证所有 SDK 的函数调用都处于同一个
context
下。在每次调用火山美颜 SDK 接口之前,必须设置正确的 OpenGL 上下文。 - 像素格式转换:NERTC SDK 采集的像素格式可能与火山美颜 SDK 所需的格式不一致,需要进行格式转换。
- 图像旋转:火山美颜 SDK 接收的纹理必须是正向的,可能需要在调用 SDK 前调整图像旋转角度。
- 内存管理:在处理过程中创建的临时
pixelBuffer
需要手动管理内存,防止内存泄漏。
前提条件
在集成火山美颜 SDK 前,请确保您已完成以下准备工作:
- iOS 9.0 或更高版本
- Xcode 11.0 或更高版本
- 已获取网易云信 AppKey
- 已集成 NERTC SDK 到您的项目中
- 已实现基础音视频通话功能
- 已从火山引擎获取以下资源:
- 火山美颜 SDK 及相关资源文件(4.1.0.0 及以上版本)
- 火山美颜 SDK 的证书文件
第一步:集成 SDK
-
集成网易云信 NERTC SDK。如果您已完成本步骤,请跳过此步。
-
根据 更新日志 选择 NERTC SDK 版本号。
-
使用 CocoaPods 集成 NERTC SDK:
Ruby
pod 'NERtcSDK', '~> 5.8.20' # 请使用您项目中的实际版本
-
-
集成火山美颜 SDK。
若您的项目使用 CocoaPods 管理依赖,请按以下步骤操作:
-
打开
iossample_static
文件夹,拷贝BytedEffectSDK.podspec
、libeffect-sdk.a
和include
文件夹到您的项目根目录(与Podfile
同级)。 -
在
Podfile
中添加依赖:Ruby
pod 'BytedEffectSDK', :path => './'
-
执行以下命令安装依赖:
bash
pod install
-
打开
项目名.xcworkspace
,确认Pods/Development Pods
目录下已包含BytedEffectSDK
。
-
第二步:准备资源
-
添加美颜素材资源。
将火山美颜提供的素材包(通常是
resource
文件夹)添加到您的 Xcode 工程中,详细介绍请参考《火山美颜官网》素材包结构说明(4.2.1 及以上),常见的资源包括:- LicenseBag.bundle
- ModelResource.bundle
- ComposeMakeup.bundle
- StickerResource.bundle
- FilterResource.bundle
-
配置
Core
模块。-
将
iossample_static
文件夹中的Core/Core
目录拷贝至您的工程中并引入项目。 -
修改
BELicenseHelper.mm
中的LICENSE_MODE
为OFFLINE_LICENSE
。 -
修改
Config.h
中的LICENSE_NAME
为您获取的绑定了应用包名的证书文件名。
-
第三步:初始化
-
引入必要的头文件。
Objective-C
#import "BEImageUtils.h" #import "BEEffectManager.h" #import "BEEffectResourceHelper.h" #import "BELicenseHelper.h"
-
创建 OpenGL 上下文。
Objective-C
@property (nonatomic, strong) EAGLContext *glContext; // 初始化 OpenGL 上下文 // 创建 OpenGL ES 3.0 上下文 self.glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3]; // 设置上下文 if ([EAGLContext currentContext] != self.glContext) { [EAGLContext setCurrentContext:self.glContext]; }
-
初始化火山美颜 SDK。
Objective-C
@property (nonatomic, strong) BEEffectManager *beEffectManager; @property (nonatomic, strong) BEImageUtils *imageUtils; ... // 初始化图像工具类 self.imageUtils = [[BEImageUtils alloc] init]; // 初始化特效管理器 self.beEffectManager = [[BEEffectManager alloc] initWithResourceProvider:[BEEffectResourceHelper new] licenseProvider:[BELicenseHelper shareInstance]]; // 初始化 SDK int ret = [self.beEffectManager initTask]; if (ret == BEF_RESULT_SUC) { NSLog(@"火山美颜 SDK 初始化成功"); } else { NSLog(@"火山美颜 SDK 初始化失败,错误码: %d", ret); }
-
加载美颜资源包。
代码以美颜和微整形为例,其余资源请参考
ComposeMakeup.bundle/ComposeMakeup
目录。Objective-C
// 加载美颜和微整形资源 NSArray *nodes = @[@"/beauty_4Items", @"/beauty_IOS_lite", @"/reshape_lite"]; [self.beEffectManager updateComposerNodes:nodes];
第四步:视频处理流程
-
开启 NERTC SDK 的视频采集回调。
在加入房间之前,需要开启 NERTC SDK 的视频采集回调功能:
Objective-C
NSDictionary *params = @{kNERtcKeyVideoCaptureObserverEnabled : @YES}; [[NERtcEngine sharedEngine] setParameters:params];
-
实现 NERTC 视频帧捕获回调。
在
onNERtcEngineVideoFrameCaptured
协议的回调方法中处理视频帧:Objective-C
// 注意: // * OpenGLES 上下文 // * rotateCVPixelBuffer 方法输出的 pixelBuffer 需要手动释放 // * processTexture 方法得到的 outTexture.pixelBuffer 等同于 transforCVPixelBufferToTexture 输入的 pixelBuffer - (void)onNERtcEngineVideoFrameCaptured:(CVPixelBufferRef)pixelBuffer rotation:(NERtcVideoRotationType)rotation contentHint:(NERtcVideoContentHint)contentHint { // 确保正确的 OpenGL 上下文 if ([EAGLContext currentContext] != self.glContext) { [EAGLContext setCurrentContext:self.glContext]; } // 参数准备 double timeStamp = [[NSDate date] timeIntervalSince1970]; CVPixelBufferRef srcPixelBuffer = pixelBuffer; CVPixelBufferRef dstPixelBuffer = pixelBuffer; CVPixelBufferRef rotatedPixelBuffer = NULL; // 格式转换:NV12 -> BGRA BEPixelBufferInfo *pixelBufferInfo = [self.imageUtils getCVPixelBufferInfo:srcPixelBuffer]; if (pixelBufferInfo.format != BE_BGRA) { dstPixelBuffer = [self.imageUtils transforCVPixelBufferToCVPixelBuffer:srcPixelBuffer outputFormat:BE_BGRA]; } // 旋转图像至 0 度 if (rotation != kNERtcVideoRotation_0) { rotatedPixelBuffer = [self.imageUtils rotateCVPixelBuffer:dstPixelBuffer rotation:rotation]; dstPixelBuffer = rotatedPixelBuffer; } // 准备纹理 id<BEGLTexture> texture = [self.imageUtils transforCVPixelBufferToTexture:dstPixelBuffer]; BEPixelBufferGLTexture *outTexture = [self.imageUtils getOutputPixelBufferGLTextureWithWidth:texture.width height:texture.height format:BE_BGRA]; // 处理纹理(应用美颜) int ret = [self.beEffectManager processTexture:texture.texture outputTexture:outTexture.texture width:texture.width height:texture.height rotate:[self getDeviceOrientation] timeStamp:timeStamp]; if (ret != BEF_RESULT_SUC) { outTexture = texture; } // 旋转图像回到原始角度 if (rotation != kNERtcVideoRotation_0) { CVPixelBufferRef newPixelBuffer = [self.imageUtils rotateCVPixelBuffer:outTexture.pixelBuffer rotation:(360 - (int)rotation)]; CFRelease(rotatedPixelBuffer); rotatedPixelBuffer = newPixelBuffer; dstPixelBuffer = rotatedPixelBuffer; } else { dstPixelBuffer = outTexture.pixelBuffer; } // 格式转换:BGRA -> NV12 CVPixelBufferRef finalPixelBuffer = [self.imageUtils transforCVPixelBufferToCVPixelBuffer:dstPixelBuffer outputFormat:BE_YUV420F]; // 将处理后的数据复制回原始 PixelBuffer [self copyPixelBuffer:finalPixelBuffer toPixelBuffer:srcPixelBuffer]; // 释放临时创建的 PixelBuffer if (rotatedPixelBuffer) { CFRelease(rotatedPixelBuffer); } }
-
设备方向获取辅助方法。
Objective-C
- (bef_ai_rotate_type)getDeviceOrientation { UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; switch (orientation) { case UIDeviceOrientationPortrait: return BEF_AI_CLOCKWISE_ROTATE_0; case UIDeviceOrientationPortraitUpsideDown: return BEF_AI_CLOCKWISE_ROTATE_180; case UIDeviceOrientationLandscapeLeft: return BEF_AI_CLOCKWISE_ROTATE_270; case UIDeviceOrientationLandscapeRight: return BEF_AI_CLOCKWISE_ROTATE_90; default: return BEF_AI_CLOCKWISE_ROTATE_0; } }
-
PixelBuffer
复制辅助方法。Objective-C
- (void)copyPixelBuffer:(CVPixelBufferRef)srcPixelBuffer toPixelBuffer:(CVPixelBufferRef)outPixelBuffer { if (!srcPixelBuffer || !outPixelBuffer) { NSLog(@"%s, buffer is invalid", __func__); return; } OSType srcType = CVPixelBufferGetPixelFormatType(srcPixelBuffer); OSType dstType = CVPixelBufferGetPixelFormatType(outPixelBuffer); if ((srcType != kCVPixelFormatType_420YpCbCr8BiPlanarFullRange && srcType != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange) || (dstType != kCVPixelFormatType_420YpCbCr8BiPlanarFullRange && dstType != kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange)) { NSLog(@"%s, format is not supported", __func__); return; } CVPixelBufferLockBaseAddress(srcPixelBuffer, 0); CVPixelBufferLockBaseAddress(outPixelBuffer, 0); size_t height = CVPixelBufferGetHeight(srcPixelBuffer); // Y 分量 void *yBaseAddress = CVPixelBufferGetBaseAddressOfPlane(srcPixelBuffer, 0); size_t yBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(srcPixelBuffer, 0); size_t yLength = yBytesPerRow * height; // UV 分量 void *uvBaseAddress = CVPixelBufferGetBaseAddressOfPlane(srcPixelBuffer, 1); size_t uvBytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(srcPixelBuffer, 1); size_t uvLength = uvBytesPerRow * height / 2; void *yBaseAddressOut = CVPixelBufferGetBaseAddressOfPlane(outPixelBuffer, 0); memcpy(yBaseAddressOut, yBaseAddress, yLength); void *uvBaseAddressOut = CVPixelBufferGetBaseAddressOfPlane(outPixelBuffer, 1); memcpy(uvBaseAddressOut, uvBaseAddress, uvLength); CVPixelBufferUnlockBaseAddress(outPixelBuffer, 0); CVPixelBufferUnlockBaseAddress(srcPixelBuffer, 0); }
第五步:设置美颜特效
火山美颜 SDK 提供丰富的美颜特效功能,您可以根据需求设置不同的美颜效果:
-
设置美颜参数。参数分类和
key
名称请参考《火山美颜官网》素材 key 对应说明(4.2.1 及以上)。Objective-C
// 确保正确的 OpenGL 上下文 if ([EAGLContext currentContext] != self.glContext) { [EAGLContext setCurrentContext:self.glContext]; } float value = 0.8; // 美白 [self.beEffectManager updateComposerNodeIntensity:@"/beauty_IOS_lite" key:@"whiten" intensity:value]; // 亮眼 [self.beEffectManager updateComposerNodeIntensity:@"/beauty_4Items" key:@"BEF_BEAUTY_BRIGHTEN_EYE" intensity:value]; // 瘦脸 [self.beEffectManager updateComposerNodeIntensity:@"/reshape_lite" key:@"Internal_Deform_Overall" intensity:value]; // 更多美颜参数设置...
-
设置滤镜,滤镜的名称请参考
FilterResource.bundle/Filter
目录下的内容。Objective-C
// 确保正确的 OpenGL 上下文 if ([EAGLContext currentContext] != self.glContext) { [EAGLContext setCurrentContext:self.glContext]; } // 设置滤镜,path 为相对 FilterResource.bundle/Filter 的路径 [self.beEffectManager setFilterPath:@"/Filter_27_Po5"]; [self.beEffectManager setFilterIntensity:0.8]; // 关闭滤镜 [self.beEffectManager setFilterPath:@""]; [self.beEffectManager setFilterIntensity:0];
第六步:资源释放
释放相关资源:
Objective-C- (void)cleanUp {
// 释放火山美颜资源
[self.beEffectManager destroyTask];
self.beEffectManager = nil;
}
参考文档
以下为本文涉及的火山美颜 SDK 官网文档: