多主播场景下的视频体验优化
- Android
更新时间不可用
了解实时互动 RTC 在不同平台上的多主播场景下的视频体验优化方式,包括接入流程、关键配置和平台差异。
在多主播(4 个或以上)发流的视频场景下,观众端面临着如下挑战和需求:
- 设备性能和下行带宽压力:多路视频流订阅对设备性能和观众端带宽的要求较高,尤其在中低端设备上可能出现卡顿和掉帧问题,容易给观众带来负面体验。
- 灵活布局需求:需要提供自定义视频画面布局的功能,支持观众调整每个主播画面的位置,以满足观众个性化的观看需求。
- 窗口切换与放大需求:在众多主播中,属于每个主播的画面大小有限,灵活切换和调整窗口大小可以实现“千人千面”的观看体验。
该方案可广泛应用于如下场景:
- 团战 PK
- 多人会议
- 在线教育大班课
技术原理
客户端自定义合图布局需要结合云端转码服务一起使用,技术原理如下所示:
当观众端收到已转码的合图视频流后,在本地实现自定义合图布局的技术原理如下所示:
前提条件
-
项目已集成 RTC SDK v4.5.x 以上版本。
-
已经在项目中实现了基本的实时音视频功能。详见实现音视频互动。
-
已实现云端转码,将合图后的视频转发至其他频道,并在调用创建云端转码 API 时设置以下参数:
JSON "outputs": [ { "seiOption":{ "source":{ "agora": { "uidvideoLayout": true } }, "sink":{ "type": 100 } } } ]
实现方法
本节介绍如何实现客户端自定义合图布局,API 调用时序如下图所示。
通过以下步骤,在接收端实现自定义合图布局。
信息
本文的 API 和示例代码均以 Android 平台为例。如目标平台为 iOS,请参考 iOS 的 API 文档。
-
调用
joinChannel[2/2] 加入合图流所在的频道。 -
通过 SDK 触发的
onTranscodedStreamLayoutInfo回调,获取合图视频流的以下信息:- 合图视频流的宽、高,以及发布该视频流的用户 ID。
- 发布合图子视频流的用户 ID。
- 合图子视频流在合图画布上的 x 和 y 坐标。
- 合图子视频流的宽度和高度。
- 合图子视频流在合图画布上的状态:正常渲染、显示为占位符,或显示为黑色图片。
-
接收端调用
setupRemoteVideo方法设置远端视频流在本地的渲染模式,重点参数设置如下所示:uid:将合图视频流转发至当前频道的用户 ID,即在onTranscodedStreamLayoutInfo回调中获取的uid。view:在本地显示的远端视频视图。你可以通过该参数设置每一路子视频流在本地视图中显示的位置。subviewUid:合图视频流中某一路子视频流所对应的用户 ID。
信息
-
当
subviewUid的值不为 0 时,setupMode的默认值为VIEW_SETUP_MODE_REPLACE(增加一个视图)。- 如果设置了
subviewUid,则对rect的设置将不会生效。
- 如果设置了
以下示例代码以多频道场景下调用
setupRemoteVideoEx为例进行介绍,在非多频道场景下调用setupRemoteVideo的方式与之类似。Java mRtcEngine.joinChannelEx(null, connection, mediaOptions, new IRtcEngineEventHandler() { @Override public void onTranscodedStreamLayoutInfo(final int uid, final VideoLayoutInfo info) { super.onTranscodedStreamLayoutInfo(uid, info); runOnUiThread(new Runnable() { @Override public void run() { int size = info.layoutNumber; viewGrids.setChildCount(info.layoutNumber); for (int i = 0; i < size; i++) { if(mUserViews.containsKey(info.layoutList[i].uid)) { continue; } // 设置 view 动态添加 TextureView textureView = new TextureView(VideoChatViewActivity.this); textureView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); users.add(info.layoutList[i].uid); views.add(textureView); mUserViews.put(info.layoutList[i].uid, textureView); viewGrids.addView(textureView); // 设置 VideoCanvas,除 uid 和 subviewUid 以外的其他参数可根据实际需要设置 VideoCanvas canvas = new VideoCanvas(textureView); // 转发合图视频流到当前频道的用户 ID canvas.uid = uid; // 对应某一路合图子视频流的用户 ID canvas.subviewUid = info.layoutList[i].uid; canvas.renderMode = Constants.RENDER_MODE_FIT; mRtcEngine.setupRemoteVideoEx(canvas, connection); // 如果要删除某一路子视频流,则添加以下代码 VideoCanvas canvas = new VideoCanvas(textureView); // 此处的 textureview 设置为需要删除的 view canvas.uid = uid; canvas.subviewUid = info.layoutList[i].uid; canvas.setupMode = VideoCanvas.VIEW_SETUP_MODE_REMOVE; mRtcEngine.setupRemoteVideoEx(canvas); } } }); } }); -
当合图视频流的布局信息发生变化时,
onTranscodedStreamLayoutInfo回调会再次触发。接收端可根据每一次回调上报的具体信息,重新调用setupRemoteVideo调整本地的视图渲染布局。信息
布局信息变化可能存在以下几种情况:
- 合图子视频在合图画布上的坐标变化。
- 合图子视频的宽度或高度变化。
- 合图子视频流的状态变化。当发布该子视频流的主播退出频道时,该路子视频流的
videoState参数会从0(正常) 变为1(该视频流无视频画面)。你可以在调用setupRemoteVideo时,将subviewUid设置为该路子视频流的用户 ID、然后将setupMode设置为VIEW_SETUP_MODE_REMOVE(删除视图),即可停止渲染该主播的视频画面。
-
监听
onUserOffline回调,当转发合图流的用户退出频道时,停止在接收端渲染合图流。
注意事项
- 目前仅支持在移动端实现自定义合图布局功能。
- 当合图视频流被添加了水印时,水印会随所在的区域被渲染,可能会出现被分割的情况。