700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 元宇宙场景技术实践|虚拟直播间搭建教程

元宇宙场景技术实践|虚拟直播间搭建教程

时间:2024-03-12 04:17:24

相关推荐

元宇宙场景技术实践|虚拟直播间搭建教程

虚拟直播场景为元宇宙社交娱乐模式下的全新直播方式,由虚拟形象替代真人出镜,可以给用户打造不一样的直播体验,还可以加入表情随动、手势识别触发特效等多种玩法,在场景里支持多位虚拟形象视频连麦互动,更容易吸引用户参与连麦互动,提升用户的消费意愿及粘性。

即构虚拟形象引擎(Zego Avatar)支持自定义管理人物的虚拟形象,通过默认的虚拟形象或者自定义生成的专有虚拟形象,以表情随动、声音驱动等方式与真人实时互动,可广泛应用于语聊直播、社交互动、在线培训等多种场景中。(关于虚拟形象Avatar的实现我们下篇文章将进行详细描述)

本篇文章我们将详细介绍下如何使用即构 SDK 实现虚拟直播间的搭建流程

架构设计

虚拟直播场景的主要架构如下图所示(以多人连麦直播互动为例):

虚拟直播场景架构设计图

体验APP源码

ZEGO 针对虚拟直播提供了体验 App 源码(iOS Objective-C 虚拟直播 SDK 体验 App 源码运行指引 - 开发者中心 - ZEGO即构科技),以供开发者进一步了解 ZEGO 虚拟直播方案。

一、开发前的准备工作

在开始正式的开发工作之前,需要先做好以下的准备工作:

已在ZEGO 控制台创建项目,并申请有效的 AppID 和 AppSign,详情请参考控制台 - 项目管理中的“项目信息”;已在项目中集成 ZEGO Express SDK,详情请参考实时音视频 - 快速开始 - 集成 SDK;已在项目中集成 ZEGO Avatar SDK,详情请参考Avatar 虚拟形象 - 快速开始 - 集成 SDK;请联系 ZEGO 商务人员,提供申请到的 AppID,以及自己项目的 Bundle Identifier,并开通 Avatar 服务。

二、具体实现流程

一切准备就绪,首先介绍下虚拟直播场景的整体流程,可以做个初步的了解:

主播进入房间后,给 Avatar 设置虚拟形象,开始采集 Avatar 纹理内容,并进行预览并推流。观众进入房间后,给 Avatar 设置虚拟形象,并进行拉流。主播、观众均通过信令模块进行连接,信令模块可以控制当前业务房间内的直播流程,同步并通知各端当前的直播状态。无论是否有连麦观众, 主播和观众均通过 ZEGO 音视频云服务进行推拉流。观众请求与主播连麦后,信令模块会通知主播,并同步连麦者的个人信息。主播接受连麦申请后,连麦观众开始采集 Avatar 纹理内容并推流,房间内所有成员将会接收到流更新通知,并拉取连麦观众的音视频流。若连麦观众不再需要连麦,则向业务后台发起下麦请求。收到信令模块的下麦通知后,连麦观众停止推流、停止采集 Avatar 纹理内容、停止表情随动,主播和房间内的其他观众停止拉取该观众的流。

详细流程图如下:

接下来我们按照开发顺序,一步步实现我们想要搭建的虚拟直播间:

1、开通Avatar服务

请联系 ZEGO 商务人员为 AppID 开通Avatar服务。

2、初始化 Express Video SDK

在使用 Express Video SDK 进行视频通话之前,需要初始化 SDK。由于初始化操作 SDK 时,内部处理的操作较多,建议开发者在 App 启动的时候进行。

ZegoEngineProfile *profile = [ZegoEngineProfile new];// 请通过官网注册获取,格式为:1234567890profile.appID = appID; //请通过官网注册获取,格式为:@"0123456789012345678901234567890123456789012345678901234567890123"(共64个字符)profile.appSign = appSign; //通用场景接入profile.scenario = ZegoScenarioGeneral; // 创建引擎,并注册 self 为 eventHandler 回调。不需要注册回调的话,eventHandler 参数可以传 nil,后续可调用 "-setEventHandler:" 方法设置回调[ZegoExpressEngine createEngineWithProfile:profile eventHandler:self];

在初始化 Express Video SDK 的时候需要开通 RTC 的自定义采集,Avatar 形象是通过自定义采集推送纹理。由于 Avatar 的数据是相反方向的,所以在初始化的时候需要设置镜像。

//设置 RTC 镜像 (Avatar 推送的镜像相反)[engine setVideoMirrorMode:ZegoVideoMirrorModeBothMirror];// 设置自定义采集推流ZegoCustomVideoCaptureConfig *captureConfig = [[ZegoCustomVideoCaptureConfig alloc] init];captureConfig.bufferType = ZegoVideoBufferTypeCVPixelBuffer;[[ZegoExpressEngine sharedEngine] enableCustomVideoCapture:YES config:captureConfig channel:ZegoPublishChannelMain];// 设置自定义采集回调[[ZegoExpressEngine sharedEngine] setCustomVideoCaptureHandler:self];float scaleScreen = [UIScreen mainScreen].nativeScale;int captureWidth = ([ZGMetaLiveCurrentUser shared].user.userType == ZGMetaLiveUserTypeHost) ? 720 : 360;int captureHeight = ([ZGMetaLiveCurrentUser shared].user.userType == ZGMetaLiveUserTypeHost) ? 1280 : 640;// 配置Avatar采集画布尺寸ZegoVideoConfig *videoConfig = [ZegoVideoConfig configWithPreset:([ZGMetaLiveCurrentUser shared].user.userType == ZGMetaLiveUserTypeHost) ? ZegoVideoConfigPreset720P :ZegoVideoConfigPreset360P];videoConfig.encodeResolution = CGSizeMake(captureWidth, captureHeight );[[ZegoExpressEngine sharedEngine] setVideoConfig:videoConfig];

更多初始化 Express Video SDK 的细节请参考:实时音视频 - 快速开始 - 实现流程的 “3.1 创建引擎”。

3、创建虚拟形象

在使用虚拟直播前,创建自己的个人形象。详情请参考创建虚拟形象。

4、登录直播房间

主播开始直播或观众观看直播前,需要先登录到直播房间。在收到登录房间成功的回调后,可以直接调用 Express Video SDK 的接口进行推拉流操作。

// 创建用户ZegoUser *user = [ZegoUser userWithUserID:userID userName:userName];// 设置为 YES 后才能接受 [onRoomUserUpdate] 回调ZegoRoomConfig *config = [[ZegoRoomConfig alloc] init];config.isUserStatusNotify = YES;// 登录房间[[ZegoExpressEngine sharedEngine] loginRoom:roomID user:user config:config];

更多使用 Express Video SDK 实现登录直播房间的细节请参考:实时音视频 - 快速开始 - 实现视频通话的 “3.2 登录房间”。

5、设置个人虚拟形象

初始化 ZegoCharacterHelper 类,设置已经创建的个人的虚拟形象,用于直播的个人形象展示。

_helper = [[ZegoCharacterHelper alloc] init:assetBundlesPath];NSString *packagePath = [bundlePath stringByAppendingString:@"/ios/Packages/"]; //Resource/ios[_helper setExtendPackagesPath:packagePath];[_helper setDefaultAvatar:((self.currentGender == ZegoGenderType_Female) ? MODEL_ID_FEMALEBODY : MODEL_ID_MALEBODY)];

6、单主播直播

6.1 获取 Avatar 的纹理内容

Avatar 的虚拟形象数据是通过startCaptureAvatar回调到上层通过自定义采集推送出去。由于 Avatar 数据是透明背景,RTC 是没背景的,转换的时候默认黑色,开发者可以自行将背景设置为需要的颜色。

//根据实际需求设置 Avatar 返回内容的宽(captureWidth)和高(captureHeight)AvatarCaptureConfig* config = [[AvatarCaptureConfig alloc] initWithWidth:captureWidth height:captureHeight];@weakify(self);//解决self循环引用[self.helper startCaptureAvatar:config callback:^(unsigned long long texture, int width, int height) {@strongify(self);@autoreleasepool {[self setupBgColorWithTexture:(__bridge id<MTLTexture>)(void*)texture color:GoAvatarHexColor(colorStr) ];}}];// 设置推流背景颜色- (void)setupBgColorWithTexture:(id<MTLTexture>)texture color:(UIColor*)color{@weakify(self);[[MetalTools sharedInstance] setupBgColorWithTexture:texture bgColor:color callback:^(id<MTLTexture> _Nonnull newTexture) {@strongify(self);[self sendCustomerBuffer:newTexture];}];}// 生成完整的 Avatar 纹理数据- (void)sendCustomerBuffer:(id)newTexture{//推流@weakify(self);[self getPixelBufferFromBGRAMTLTexture:(__bridge id<MTLTexture>)(__bridge void*)newTexture result:^(CVPixelBufferRef pixelBuffer) {@strongify(self);//这里的格式是 BGRA,需要转换CMTime time = CMTimeMakeWithSeconds([[NSDate date] timeIntervalSince1970], 1000);CMSampleTimingInfo timingInfo = { kCMTimeInvalid, time, time };CMVideoFormatDescriptionRef desc;CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, pixelBuffer, &desc);CMSampleBufferRef sampleBuffer;CMSampleBufferCreateReadyWithImageBuffer(kCFAllocatorDefault, (CVImageBufferRef)pixelBuffer, desc, &timingInfo, &sampleBuffer);if ([self.captureHandler respondsToSelector:@selector(onAvatarCaptureDeviceDidCapturedData:)]) {[self.captureHandler onAvatarCaptureDeviceDidCapturedData:sampleBuffer];}CFRelease(sampleBuffer);CFRelease(desc);}];}// 把当前纹理数据转换成 pixelBuffer- (void)getPixelBufferFromBGRAMTLTexture:(id<MTLTexture>)texture result:(void(^)(CVPixelBufferRef pixelBuffer))block {CVPixelBufferRef pxbuffer = NULL;NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,[NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey, nil];unsigned long width = texture.width;unsigned long height = texture.height;size_t imageByteCount = width * height * 4;void *imageBytes = malloc(imageByteCount);NSUInteger bytesPerRow = texture.width * 4;MTLRegion region = MTLRegionMake2D(0, 0, texture.width, texture.height);[texture getBytes:imageBytes bytesPerRow:bytesPerRow fromRegion:region mipmapLevel:0];CVPixelBufferCreateWithBytes(kCFAllocatorDefault,texture.width,texture.height,kCVPixelFormatType_32BGRA,imageBytes,bytesPerRow,NULL,NULL,(__bridge CFDictionaryRef)options,&pxbuffer);if (block) {block(pxbuffer);}CVPixelBufferRelease(pxbuffer);free(imageBytes);}

6.2 主播开启预览并推流

主播向 ZEGO 音视频云服务推流,需要自己生成唯一的 StreamID,然后开始预览并推流。

// 根据 view 对象创建待渲染画布ZegoCanvas *canvas = [ZegoCanvas canvasWithView:view];// 设置渲染模式canvas.viewMode = ZegoViewModeAspectFill;// 开始在画布进行本地预览[[ZegoExpressEngine sharedEngine] startPreview:canvas];// 主播开始推流[[ZegoExpressEngine sharedEngine] startPublishingStream:@"hostStreamID"];

更多使用 Express Video SDK 实现预览和推流的细节请参考:实时音视频 - 快速开始 - 实现视频通话的 “3.3 推流”。

6.3 观众拉流

观众进入房间后,会收到 Express Video SDK 的流更新通知,从中筛选出主播流的 StreamID 进行拉流。

// 观众拉主播流// 根据 view 对象创建待渲染画布ZegoCanvas *canvas = [ZegoCanvas canvasWithView:view];// 设置渲染模式canvas.viewMode = ZegoViewModeAspectFill;// 开始拉流并在画布进行渲染[[ZegoExpressEngine sharedEngine] startPlayingStream:@"audienceStreamID" canvas:canvas];

更多使用 SDK 实现拉流的细节请参考:快速开始 - 实现流程的 “3.4 拉流”。

7、观众连麦

7.1 连麦观众推流

观众调用业务后台请求连麦接口,调用成功后,业务后台向主播发送请求连麦自定义信令。主播收到信令后,调用业务后台同意连麦接口,调用成功后,业务后台向房间内所有成员发送连麦成功的广播信令,连麦观众收到信令后,开始推流,观众上台后也是按照6.1 获取 Avatar 的纹理内容的流程,把 Avatar 的内容通过自定义采集推流出去。

// 连麦观众推流[[ZegoExpressEngine sharedEngine] startPublishingStream:@"audienceStreamID"];

7.2 主播拉流

连麦观众推流后,房间内所有成员会收到 Express Video SDK 的流更新通知,主播获取连麦观众流的 StreamID 进行拉流。

房间内其他观众也在收到流更新回调时,获取连麦观众流的 StreamID 进行拉流。

// 主播拉连麦观众流 // 根据 view 对象创建待渲染画布ZegoCanvas *canvas = [ZegoCanvas canvasWithView:view];// 设置渲染模式canvas.viewMode = ZegoViewModeAspectFill;// 开始拉流并在画布进行渲染[[ZegoExpressEngine sharedEngine] startPlayingStream:@"audienceStreamID" canvas:canvas];

7.3 连麦观众下麦

连麦观众调用业务后台的下麦接口,调用成功后,业务后台向房间内所有成员发送该观众下麦的广播信令。连麦观众收到信令后停止推流、停止采集获取 Avatar 纹理内容、停止表情随动检测,房间内其他观众收到信令后停止拉流。

// 观众停止预览[[ZegoExpressEngine sharedEngine] stopPreview];// 观众结束推流[[ZegoExpressEngine sharedEngine] stopPublishingStream];// 房间内其他成员结束拉流 [[ZegoExpressEngine sharedEngine] stopPlayingStream:@"audienceStreamID"];// 停止采集获取 Avatar[[GoAvatarManager shareInstance] stopCaptureAvatar]

更多使用 Express Video SDK 实现停止推拉流的细节请参考:实时音视频 - 快速开始 - 实现流程的 “4.2 停止推拉流”。

三、进阶功能

1、真人和虚拟形象切换

真人和虚拟形象的切换功能,主要是会体验不同视角效果。“真人”就是常规意义上的视频画,“虚拟形象”则是不同人模形象的展示。

设置 RTC 视频采集源当开发者需要从 Avatar 虚拟形象切换到真人形象或者从真人形象切换到 Avatar 虚拟形象的时候,均需要调用 Express SDK 的callExperimentalAPI设置 RTC 视频采集源。

static int const VIDEO_SRC_CAMERA = 2; // 摄像头视频源,在该场景中特指真人画面static int const VIDEO_SRC_EXTERNAL_CAPTURE = 3; // 外部视频源,在该场景中特指虚拟形象NSDictionary *param = @{@"method":@"express.video.set_video_source",@"params":@{// source 表示 RTC 视频采集源;// VIDEO_SRC_CAMERA 为真人形象;@"source":@(VIDEO_SRC_CAMERA),// VIDEO_SRC_EXTERNAL_CAPTURE 为 Avatar 虚拟形象// @"source":@(VIDEO_SRC_EXTERNAL_CAPTURE),@"channel":@(ZegoPublishChannelMain),},};[[ZegoExpressEngine sharedEngine] callExperimentalAPI:[param modelToJSONString]]

停止或者开启采集 Avatar 纹理内容从 Avatar 虚拟形象切换到真人形象时,需要调用stopCaptureAvatar停止采集 Avatar 纹理内容。​​​​​​​

// 停止采集 Avatar 纹理内容[[GoAvatarManager shareInstance] stopCaptureAvatar];// 开始采集 Avatar 纹理内容//[[GoAvatarManager shareInstance] startCaptureAvatar];

从真人形象切换到 Avatar 虚拟形象时,需要调用startCaptureAvatar开始采集 Avatar 纹理内容,详情请参考本篇文章6.1 获取 Avatar 的纹理内容。

2、实时消息互动

ZEGO 支持在虚拟直播中加入实时消息互动功能,实时展示房间内的消息,例如发消息、进退房提示、互动通知等。为便利开发者快速实现此功能,体验 App 源码提供了相关组件,有关在您的项目中接入该组件的流程,请参考实时消息互动 - 组件接入。

四、Demo展示

用虚拟形象代替真人出镜,打造不一样的互动体验,以上就是关于即构虚拟直播间的实现流程,感兴趣的小伙伴可以动手尝试搭建,下方是可以呈现的 demo 截图:

​​​​​​​

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。