文档中心
ZegoAvatar Avatar 虚拟形象
文档中心
体验 App
SDK 中心
API 中心
常见问题
代码市场
进入控制台
立即注册
登录
中文站 English
  • 文档中心
  • Avatar 虚拟形象
  • 最佳实践
  • 在 RTC 视频流中使用 Avatar

在 RTC 视频流中使用 Avatar

更新时间:2023-11-16 23:35

使用导读

简介

ZEGO Avatar SDK 提供了导出 Avatar 纹理功能,支持用户把 Avatar 虚拟形象渲染结果输出。开发者可以对该渲染结果做自定义后处理,将渲染结果用于 RTC 推流中。

概念解释

  • Zego Express SDK:ZEGO 实时音视频的 SDK,提供基础的实时音视频功能,包括直播推拉流、直播连麦等,以下使用 Express SDK 简写表示。
  • Zego Avatar SDK:ZEGO Avatar 虚拟形象的 SDK,支持自定义管理人物的虚拟形象,通过默认的虚拟形象或者自定义生成的专有虚拟形象,以表情随动、声音驱动等方式与真人实时互动,以下使用 Avatar SDK 简写表示。

前提条件

  • 已在 ZEGO 控制台 创建项目,并申请有效的 AppID 和 AppSign,详情请参考 控制台 - 项目管理 中的“项目信息”。
  • 已在项目中集成 Express SDK,实现基本的实时音视频功能,详情请参考 快速开始 - 集成 和 快速开始 - 实现视频通话。
  • 已在项目中集成了 Avatar SDK,详情请参考 快速开始 - 集成 SDK。
  • 已联系 ZEGO 技术支持,提供自己项目的包名,开通相关权限。

使用原理

ZEGO Avatar SDK 和 Express SDK 搭配使用,采集虚拟形象、输出纹理,并推流出去的原理,如下图:

/Pics/ZegoAvatar/common/Avatar_RTC_texture.png

通过以上流程,具体的实现步骤,如下图:

实现流程

1 初始化 ZegoAvatarService

请参考 创建虚拟形象 的 “鉴权并初始化 SDK”。

2 设置推流数据采集类型

2.1 初始化 Express SDK,登录房间

请参考 快速开始 - 实现视频通话 的 “3.1 初始化”(建议开发者在 App 启动时进行)和 “3.2 登录房间”。

2.2 设置推流数据采集类型,开启自定义视频采集

  1. 通过 ZegoCustomVideoCaptureConfig,自定义 Express SDK 的视频采集配置;调用 enableCustomVideoCapture 接口,开启自定义视频采集功能。
  2. 调用 setCustomVideoCaptureHandler 接口设置自定义视频采集回调。
  3. 最后再调用 setVideoConfig 接口设置视频配置。

调用 setVideoConfig 接口设置视频配置时,请和 4 导出 Avatar 纹理 中的 Avatar 纹理宽、高等信息保持一致。

// engine 为 ZegoExpress 示例
// 自定义视频采集
ZegoCustomVideoCaptureConfig videoCaptureConfig = new ZegoCustomVideoCaptureConfig();
// 选择 GL_TEXTURE_2D 类型视频帧数据
videoCaptureConfig.bufferType = ZegoVideoBufferType.GL_TEXTURE_2D;
// 启动自定义视频采集
engine.enableCustomVideoCapture(true, videoCaptureConfig, ZegoPublishChannel.MAIN);

// 设置自定义视频采集回调
engine.setCustomVideoCaptureHandler(mCustomVideoCaptureHandler);

// 设置视频配置, 要和 Avatar 的输出尺寸保持一致
ZegoVideoConfig videoConfig = new ZegoVideoConfig(ZegoVideoConfigPreset.PRESET_720P);
// 输出纹理是正方形的, 可以自定义宽、高
videoConfig.setEncodeResolution(mVideoWidth, mVideoHeight);
engine.setVideoConfig(videoConfig);

// 初始化 Express SDK 时使用
private final IZegoEventHandler mZegoEventHandler = new IZegoEventHandler() {
    // nothing
    @Override
    public void onDebugError(int errorCode, String funcName, String info) {
        Log.e("Avatar", "error: " + errorCode + ", info: " + info);
    }
};

// Express SDK 开始 RTC 推流时的 handler 回调,可以在此回调中,启动、停止 Avatar 检测,以及开始、停止导出纹理
private final IZegoCustomVideoCaptureHandler mCustomVideoCaptureHandler = new IZegoCustomVideoCaptureHandler() {

    @Override
    public void onStart(ZegoPublishChannel channel) {
        // 收到回调后,开发者需要执行启动视频采集相关的业务逻辑,例如开启摄像头等
        AvatarCaptureConfig config = new AvatarCaptureConfig(mVideoWidth, mVideoHeight);
        // 开始捕获纹理
        // 开始捕获纹理
        zegoAvatarView.setTextureUpdateListener(AvatarStream2Activity.this::onCaptureAvatar);
        // 启动表情随动
        startExpression();
    }

    @Override
    public void onStop(ZegoPublishChannel channel) {
        // 收到回调后,开发者需要执行停止视频采集相关的业务逻辑,例如关闭摄像头等
        // 停止捕获纹理
        // !!!! 注意:有可能不被执行!!! 用户在退出应用时,也需要退出,请注意调用此接口。
        zegoAvatarView.removeTextureUpdateListener();
        stopExpression();
    }
};

3 创建虚拟形象,开始检测表情

  1. 初始化 AvatarService 后,创建一个虚拟形象。
  2. 搭建出基本的虚拟人物形象后,调用 startDetectExpression 接口,设置驱动模式为 ZegoExpressionDetectModeCamera,通过前置摄像头,开始检测表情;然后可以直接通过 ZegoCharacter 的 setExpression 接口设置表情,驱动当前虚拟人物的面部表情变化。
  • 开启表情检测前,请确认已开启摄像头权限。
void initAvatar() {
    String girlPath = AvatarHumanPath.getHumanPath(AvatarType.Girl,getFilesDir().getAbsolutePath());
    //创建人模
    mCharacter = ZegoAvatarService.createCharacter(girlPath);
    //人模上屏
    zegoAvatarView.setCharacter(mCharacter, new IZegoAvatarCharacterCallback() {
        @Override
        public void onShow() {
            //动画关闭
            mCharacter.enableAnimation(false);
            //开启表情随动
            startExpression();
            //设置几个妆容
            mCharacter.setPackage(AvatarHumanPath.getPackagePath(getFilesDir().getAbsolutePath())+"ZEGOQ_Share_Coat_0002_0001");
            mCharacter.setPackage(AvatarHumanPath.getPackagePath(getFilesDir().getAbsolutePath())+"ZEGOQ_Share_Pants_0007_0001");
            mCharacter.setPackage(AvatarHumanPath.getPackagePath(getFilesDir().getAbsolutePath())+"ZEGOQ_Share_Hair_0001_0001");
        }
    });
    //设置半身模式
    zegoAvatarView.setCamera(ZegoAvatarViewState.half.id);
}

// 启动表情检测
void startExpression() {
    // 启动表情检测前要申请摄像头权限, 
    ZegoAvatarService.getInteractEngine().startDetectExpression(ZegoExpressionDetectMode.Camera, expression -> {
        // 表情直接塞给 avatar 驱动
        mCharacter.setExpression(expression);
    });
}

4 导出 Avatar 纹理

调用 setTextureUpdateListener 接口,监听 Avatar 纹理并进行自定义处理。

// 开始导出纹理
// 根据实际需求设置 Avatar 返回内容的宽(captureWidth)和高(captureHeight)
zegoAvatarView.setTextureUpdateListener(new IAvatarViewTextureUpdateListener() {
            @Override
            public void onTextureUpdate(int i, int i1, int i2) {
                //纹理的自定义处理
            }
        });

(可选)自定义后处理

通过 startCaptureAvatar 导出 OpenGL 纹理数据后,您可以注册 onAvatarCaptureCallback 的 onAvatarTextureAvailable 回调,监听导出纹理操作的结果,其中包含 GL_TEXTURE_2D 格式的纹理 ID、长、宽等信息。

您可以对该“纹理”数据自定义后处理,例如,添加背景(Avatar 虚拟形象的默认背景是透明的)。设置完成后,调用 sendCustomVideoCaptureTextureData 进行推流,向 SDK 发送视频帧数据。

您可以参考 下载 中获取到的示例源码 example,来设置背景颜色。

// 获取到 Avatar 纹理后的处理
// 配置Avatar 的 OpenGL 纹理, 纹理大小跟 Express SDK 配置保持一致
public void onCaptureAvatar(int textureId/*GL_TEXTURE_2D 格式*/, int width, int height) {

    // Avatar 出来的纹理里是 RGBA, 背景是透明的, 但是 Express SDK 编码成 YUV 格式,会丢失 Alpha 通道
    // 所以发送给 Express SDK 之前, 可以定义一个背景颜色或背景图, 您可以直接使用 OpenGL 或者一些封装好的 OpenGL 库
    if (mAddAvatarBackground) {
        boolean useFBO = true;
        if (mBgRender == null) {
            mBgRender = new TextureBgRender(textureId, useFBO, width, height, Texture2dProgram.ProgramType.TEXTURE_2D_BG);
        }
        mBgRender.setInputTexture(textureId);
        mBgRender.setBgColor(mColor.red(), mColor.green(), mColor.blue() , mColor.alpha());
        mBgRender.draw(useFBO); // 绘制到 fbo 上时需要反向
        //把自定义处理后的纹理发送给 Express SDK
        ZegoExpressEngine.getEngine().sendCustomVideoCaptureTextureData(mBgRender.getOutputTextureID(), width, height, System.currentTimeMillis());
    } else {
        // 直接发送给 Express SDK
        ZegoExpressEngine.getEngine().sendCustomVideoCaptureTextureData(textureId, width, height, System.currentTimeMillis());
    }
}

5 Express RTC预览画面并推流

Avatar SDK 仅支持导出 GL_TEXTURE_2D 格式的纹理数据,使用 Express SDK 推流时,开发者可直接推流、或增加自定义处理后进行推流。

您需要自行实现数据类型的转换,或参考 (可选)自定义后处理 中的示例代码实现数据类型转换。

在用户调用 loginRoom 接口后,可以直接调用 startPublishingStream 接口,传入 streamID(由您的业务生成,且全局唯一),将 Avatar 纹理视频流推送到 ZEGO 音视频云。您可通过监听 onPublisherStateUpdate 回调知晓推流是否成功。

// 开始推流
ZegoExpressEngine.getEngine().startPublishingStream(streamId);
// 开始预览
ZegoExpressEngine.getEngine().startPreview(new ZegoCanvas(mLocalPreview));

6.本地预览

ZegoAvatarView 在调用 setCharacter 接口后,可以直接实现本地预览。

常用功能

1. 停止表情检测

将应用切换到后台运行、或退出当前页面时,需要调用 stopDetectExpression 接口,停止表情检测。

// 停止表情检测
void stopExpression() {
    // 如果不需要时,请记得停止
    ZegoAvatarService.getInteractEngine().stopDetectExpression();
}

2. 停止导出纹理

调用 stopCaptureAvatar 接口,停止导出 Avatar 纹理。

// 停止导出纹理
zegoAvatarView.removeTextureUpdateListener();

3. 停止推流,停止预览,退出房间

调用 stopPublishingStream 接口停止向远端用户发送本端的音视频流。

如果启用了本地预览,调用 stopPreview 接口停止预览。

调用 logoutRoom 接口退出房间。

ZegoExpressEngine engine = ZegoExpressEngine.getEngine();
if (engine != null) {
    engine.stopPreview();
    engine.stopPublishingStream();
    engine.logoutRoom();
}

4. 销毁引擎

如果用户彻底不使用音视频功能时,可调用 destroyEngine 接口销毁引擎,释放麦克风、摄像头、内存、CPU 等资源。

ZegoExpressEngine.destroyEngine(null);
本篇目录
  • 免费试用
  • 提交工单
    咨询集成、功能及报价等问题
    电话咨询
    400 1006 604
    咨询客服
    微信扫码,24h在线

    联系我们

  • 文档反馈