主体分割是 Express SDK 提供的增值能力,通过 AI 算法识别视频画面中的内容,对每一个像素点设置透明度信息
。其中,主体部分的像素点会被设置为“不透明”,主体部分之外的像素点会被设置为“透明”。开发者可以利用这些像素点的透明度信息,对画面中的主体和非主体部分做不同的处理,从而实现不同的功能。
对身处不同环境的用户,ZEGO 提供“绿幕背景分割”和“任意背景分割”两种分割能力。
分割类型 | 绿幕背景分割 | 任意背景分割 |
---|---|---|
能力描述 | 在用户自行架设了绿幕的情况下,可以将非绿幕区域的主体保留。 适用于电商直播、在线考试等场景。 |
多数用户不具备架设绿幕的条件,可以通过 ZEGO 提供的任意背景分割能力,在没有绿幕的情况下,识别画面中的主体。 适用于在线教育、视频会议等场景。 |
图示 |
基于主体分割能力,开发者可以实现背景虚化、虚拟背景、演讲模式、多人实时同台互动等业务场景,打造更多样的互动体验。
功能点 | 背景虚化 | 虚拟背景 | 背景透明 | 主体分割与传输 |
---|---|---|---|---|
功能描述 | 将主体外的画面做模糊处理。 |
将主体外的画面替换为自定义的图片、视频、颜色。 |
将主体的画面渲染在本端的其他视频内容上。 例如在屏幕共享或正在播放的视频等内容上,实现演讲模式等功能。 |
结合 Express SDK 提供的 Alpha 通道数据传输能力,将画面中分割出的主体传输到拉流端,在拉流端做主体渲染,实现多人异地实时同处于一个场景中的视觉效果 |
图示 |
平台 | 硬件要求 |
---|---|
Android |
|
iOS |
A 系列芯片:Apple A9 及以上,例如 iPhone 6s |
macOS |
M 系列芯片:Apple M1 及以上 |
Windows |
Intel Core i5 及以上 |
请参考 下载示例源码 获取源码。
相关源码请查看 “/ZegoExpressExample/Others/src/main/java/com/example/others/videoobjectsegmentation” 目录下的文件。
在使用主体分割功能前,请确保:
已联系 ZEGO 技术支持进行特殊编包。
处理器为 M1 及以上。
已在 ZEGO 控制台 创建项目,并申请有效的 AppID 和 AppSign,详情请参考 控制台 - 项目信息。
已在项目中集成 ZEGO Express SDK,并实现了基本的音视频推拉流功能,详情请参考 快速开始 - 集成 和 快速开始 - 实现流程。
请注意,开发者可根据自己的业务场景需要,选择是否实现上图中的 (可选) 步骤。如需实现,请参考下文中的具体说明。
初始化和登录房间的具体流程,请参考实现视频通话文档中的 “3.1 创建引擎”及“3.2 登录房间”。
监听自定义渲染数据回调。
- (void)onRemoteVideoFrameRawData:(unsigned char * _Nonnull *)data dataLength:(unsigned int *)dataLength param:(ZegoVideoFrameParam *)param streamID:(NSString *)streamID
{
}
对原始视频帧数据进行缓存。
auto video_frame = std::make_shared<ZegoVideoFrameBuffer>();
video_frame->data = std::make_unique<uint8_t[]>(dataLength[0]);
video_frame->data_length =dataLength[0];
video_frame->format = param.format;
video_frame->width = (int)param.size.width;
video_frame->height = (int)param.size.height;
video_frame->bitsPerPixel = param.strides[0];
memcpy(video_frame->data.get(), data[0], dataLength[0]);
{
// 缓存一帧
std::lock_guard<std::mutex> lock(play_video_frame_mutex_);
play_video_frames_[[streamID UTF8String]] = video_frame;
}
定时将位图绘制到渲染视图上。
dispatch_async(dispatch_get_main_queue(), ^{
std::shared_ptr<ZegoVideoFrameBuffer> frame;
{
std::lock_guard<std::mutex> lock(self->play_video_frame_mutex_);
frame = self->play_video_frames_[[streamID UTF8String]];
if (!frame) {
return;
}
self->play_video_frames_[[streamID UTF8String]].reset();
}
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, frame->data.get(), frame->data_length, NULL);
CGImageRef cgImageFromBytes = CGImageCreate(frame->width, frame->height, 8, 32, frame->bitsPerPixel, colorSpace, kCGImageByteOrder32Little|kCGImageAlphaFirst, dataProvider, NULL, NO, kCGRenderingIntentDefault);
NSImage *finalImage = [[NSImage alloc]initWithCGImage:cgImageFromBytes size:NSMakeSize(frame->width, frame->height)];
CGDataProviderRelease(dataProvider);
CGImageRelease(cgImageFromBytes);
self.playView1.layer.contentsGravity = kCAGravityResizeAspect;
self.playView1.layer.contents = finalImage;
});
调用 enableCustomVideoRender 接口,设置引擎进阶配置并开启自定义渲染,同时调用 setCustomVideoRenderHandler 接口设置自定义视频渲染回调,详情请参考 自定义视频渲染。
使用自定义渲染进行主体分割时,bufferType 仅支持 ZegoVideoBufferType.RAW_DATA
类型。
ZegoCustomVideoRenderConfig *renderConfig = [[ZegoCustomVideoRenderConfig alloc] init];
renderConfig.bufferType = ZegoVideoBufferTypeRawData;// 选择 RAW_DATA 类型视频帧数据
renderConfig.frameFormatSeries = ZegoVideoFrameFormatSeriesRGB;// 选择 RGB 色系数据格式
[[ZegoExpressEngine sharedEngine] enableCustomVideoRender:YES config:renderConfig];//开始自定义视频渲染
[[ZegoExpressEngine sharedEngine] setCustomVideoRenderHandler:self];//设置自定义视频渲染回调
调用 onVideoObjectSegmentationStateChanged 接口,监听主体分割状态回调。
主体分割的状态回调依赖于开启预览或者推流,即如需监听 onVideoObjectSegmentationStateChanged 回调,需要调用预览 startPreview 或推流 startPublishingStream。
-(void)onVideoObjectSegmentationStateChanged:(ZegoObjectSegmentationState)state channel:(ZegoPublishChannel)channel errorCode:(int)errorCode{
if(state == ZegoObjectSegmentationStateOn){
//主体分割开启
}else{
//主体分割关闭
//异常关闭,请查看错误码
}
}
开发者如需更新主体分割类型、背景处理类型,需要修改 ZegoObjectSegmentationConfig 的配置,并再次调用 enableVideoObjectSegmentation 接口开启主体分割,即可更新主体分割效果;更新结果将通过 onVideoObjectSegmentationStateChanged 回调通知给开发者。
调用 enableVideoObjectSegmentation 接口,开启主体分割,并设置背景处理类型为“虚化”。
ZegoObjectSegmentationConfig *config = [[ZegoObjectSegmentationConfig alloc]init];
config.objectSegmentationType = ZegoObjectSegmentationTypeAnyBackground;//根据实际情况选择需要开启的主体分割类型
config.backgroundConfig.processType = ZegoBackgroundProcessTypeBlur;//设置背景处理方式为虚化
config.backgroundConfig.blurLevel = ZegoBackgroundBlurLevelMedium;//设置背景虚化级别为中
[[ZegoExpressEngine sharedEngine]enableVideoObjectSegmentation:YES config:config channel:ZegoPublishChannelMain];//开启主体分割
虚拟背景支持两种类型素材:
开发者在使用本功能时,请注意自定义图片、视频素材的宽高比,否则超出视图的部分会被裁减。
调用 enableVideoObjectSegmentation 接口,开启主体分割,并设置背景处理类型为“图片”或“视频”。
ZegoObjectSegmentationConfig *config = [[ZegoObjectSegmentationConfig alloc]init];
config.objectSegmentationType = ZegoObjectSegmentationTypeAnyBackground;//根据实际情况选择需要开启的主体分割类型
//设置背景处理方式为 图片
config.backgroundConfig.processType = ZegoBackgroundProcessTypeImage;
config.backgroundConfig.imageUrl= @"<image_path>";//设置背景图片路径
[[ZegoExpressEngine sharedEngine]enableVideoObjectSegmentation:YES config:config channel:ZegoPublishChannelMain];//开启主体分割
//设置背景处理方式为 视频
config.backgroundConfig.processType = ZegoBackgroundProcessTypeVideo;
config.backgroundConfig.videoURL= @"<video_path>";//设置背景视频路径
[[ZegoExpressEngine sharedEngine]enableVideoObjectSegmentation:YES config:config channel:ZegoPublishChannelMain];//开启主体分割
如果开发者需要实现类似“演讲模式”的业务功能,需要在业务侧将“主体画面”与“要混合的视频源内容”混为一条视频流。
调用 enableVideoObjectSegmentation 接口,开启主体分割,并设置背景处理类型为“透明”。
ZegoObjectSegmentationConfig *config = [[ZegoObjectSegmentationConfig alloc]init];
config.objectSegmentationType = ZegoObjectSegmentationTypeAnyBackground;//根据实际情况选择需要开启的主体分割类型
config.backgroundConfig.processType = ZegoBackgroundProcessTypeTransparent;//设置背景处理方式为透明
[[ZegoExpressEngine sharedEngine]enableVideoObjectSegmentation:YES config:config channel:ZegoPublishChannelMain];//开启主体分割
如果推流端需要把分割后的主体画面通过 Alpha 通道传输到拉流端,在拉流端做主体渲染,需要先调用 enableAlphaChannelVideoEncoder 接口,设置编码器支持透明通道,然后调用 startPublishingStream 接口推流,使其顺利传输至拉流端。
目前仅支持透明通道数据排列在 RGB 或 YUV 数据下方。
开启 Alpha 通道数据传输:
ZegoAlphaLayoutType layoutType = ZegoAlphaLayoutTypeBottom; // 透明通道数据排列在 RGB 或 YUV 数据下方
[[ZegoExpressEngine sharedEngine]enableAlphaChannelVideoEncoder:YES alphaLayout:layoutType channel:ZegoPublishChannelMain]; // 设置编码器支持透明通道
关闭 Alpha 通道数据传输:
ZegoAlphaLayoutType layoutType = ZegoAlphaLayoutTypeBottom; // 透明通道数据排列在 RGB 或 YUV 数据下方
[[ZegoExpressEngine sharedEngine]enableAlphaChannelVideoEncoder:NO alphaLayout:layoutType channel:ZegoPublishChannelMain]; // 设置编码器支持透明通道
通过 enableVideoObjectSegmentation 接口开启主体分割功能后,可以进行预览。
开发者也可以先开启预览,再开启主体分割。本文以先开启主体分割,再进行预览为例进行介绍。
方式 1:使用内部渲染
若使用内部渲染,开启预览前,请设置 alphaBlend 为 YES。
ZegoCanvas *previewCanvas = [ZegoCanvas canvasWithView:self.previewView];
previewCanvas.alphaBlend = YES;//开启内部渲染 Alpha 混合,开启后支持分割后的主体与背景图层进行 Alpha 混合
[[ZegoExpressEngine sharedEngine]startPreview:previewCanvas];
方式 2:使用自定义渲染
若使用自定义渲染,可直接进行预览和推流。
[[ZegoExpressEngine sharedEngine] startPreview:nil];
[[ZegoExpressEngine sharedEngine] startPublishingStream:streamID];
推流端开启了 Alpha 通道传输的情况下,才需要在拉流端开启 Alpha 通道渲染。
方式 1:使用内部渲染
如果使用内部渲染,拉流端在调用 startPlayingStream 接口开启拉流前,需要将 ZegoCanvas 的 alphaBlend 属性设置为 YES。
ZegoCanvas *playCanvas = [ZegoCanvas canvasWithView:self.playView1];
playCanvas.alphaBlend = YES;//开启内部渲染 Alpha 混合,开启后支持分割后的主体与背景图层进行 Alpha 混合
[[ZegoExpressEngine sharedEngine]startPlayingStream:streamID canvas:playCanvas];
方式 2:使用自定义渲染
若使用自定义渲染,可直接进行拉流。
[[ZegoExpressEngine sharedEngine]startPlayingStream:streamID canvas:nil];
调用 enableVideoObjectSegmentation 接口,关闭主体分割。
ZegoObjectSegmentationType objectType = ZegoObjectSegmentationTypeAnyBackground;//根据实际情况选择需要关闭的主体分割类型
[[ZegoExpressEngine sharedEngine]enableVideoObjectSegmentation:NO type:objectType channel:ZegoPublishChannelMain];//关闭主体分割
调用 destroyEngine 接口,销毁引擎。
[ZegoExpressEngine destroyEngine:nil];
联系我们
文档反馈