ZEGO Avatar SDK 提供了导出 Avatar 纹理功能,支持用户把 Avatar 虚拟形象渲染结果输出。开发者可以对该渲染结果做自定义后处理,将渲染结果用于 RTC 推流中。
ZEGO Avatar SDK 和 Express SDK 搭配使用,采集虚拟形象、输出纹理,并推流出去的原理,如下图:
通过以上流程,具体的实现步骤,如下图:
请参考 创建虚拟形象 的 “鉴权并初始化 SDK”。
请参考 快速开始 - 实现视频通话 的 “3.1 初始化”(建议开发者在 App 启动时进行)和 “3.2 登录房间”。
调用 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();
}
};
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);
});
}
调用 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());
}
}
Avatar SDK 仅支持导出 GL_TEXTURE_2D 格式的纹理数据,使用 Express SDK 推流时,开发者可直接推流、或增加自定义处理后进行推流。
您需要自行实现数据类型的转换,或参考 (可选)自定义后处理 中的示例代码实现数据类型转换。
在用户调用 loginRoom 接口后,可以直接调用 startPublishingStream 接口,传入 streamID(由您的业务生成,且全局唯一),将 Avatar 纹理视频流推送到 ZEGO 音视频云。您可通过监听 onPublisherStateUpdate 回调知晓推流是否成功。
// 开始推流
ZegoExpressEngine.getEngine().startPublishingStream(streamId);
// 开始预览
ZegoExpressEngine.getEngine().startPreview(new ZegoCanvas(mLocalPreview));
ZegoAvatarView 在调用 setCharacter 接口后,可以直接实现本地预览。
将应用切换到后台运行、或退出当前页面时,需要调用 stopDetectExpression 接口,停止表情检测。
// 停止表情检测
void stopExpression() {
// 如果不需要时,请记得停止
ZegoAvatarService.getInteractEngine().stopDetectExpression();
}
调用 stopCaptureAvatar 接口,停止导出 Avatar 纹理。
// 停止导出纹理
zegoAvatarView.removeTextureUpdateListener();
调用 stopPublishingStream 接口停止向远端用户发送本端的音视频流。
如果启用了本地预览,调用 stopPreview 接口停止预览。
调用 logoutRoom 接口退出房间。
ZegoExpressEngine engine = ZegoExpressEngine.getEngine();
if (engine != null) {
engine.stopPreview();
engine.stopPublishingStream();
engine.logoutRoom();
}
如果用户彻底不使用音视频功能时,可调用 destroyEngine 接口销毁引擎,释放麦克风、摄像头、内存、CPU 等资源。
ZegoExpressEngine.destroyEngine(null);
联系我们
文档反馈