2024/08/22 16:35:44
多主播场景下的视频体验优化
在多主播(4 个或以上)发流的视频场景下,观众端面临着如下挑战和需求:
- 设备性能和下行带宽压力:多路视频流订阅对设备性能和观众端带宽的要求较高,尤其在中低端设备上可能出现卡顿和掉帧问题,容易给观众带来负面体验。
- 灵活布局需求:需要提供自定义视频画面布局的功能,支持观众调整每个主播画面的位置,以满足观众个性化的观看需求。
- 窗口切换与放大需求:在众多主播中,属于每个主播的画面大小有限,灵活切换和调整窗口大小可以实现“千人千面”的观看体验。
因此,声网推出了多主播视频场景下的视频体验优化方案,通过客户端自定义合图布局实现,以观众为中心,创造流畅、个性化的视频观看体验。
该方案可广泛应用于如下场景:
- 团战 PK
- 多人会议
- 在线教育大班课
技术原理
客户端自定义合图布局需要结合云端转码服务一起使用,技术原理如下所示:
![图片](/assets/images/tech1-20f2f5138e5dd73b4e93d71905654ad4.png)
当观众端收到已转码的合图视频流后,在本地实现自定义合图布局的技术原理如下所示:
![图片](/assets/images/tech2-4c5d4e9c53eafdd3ecb4241b0e118b75.png)
前提条件
实现方法
本节介绍如何实现客户端自定义合图布局,API 调用时序如下图所示。
![图片](/assets/images/custom-layout-sequence-9ce9516c310ef9fc6b8a151c2a6ae6f3.png)
通过以下步骤,实现在接收端自定义合图布局。
信息
本文的 API 和示例代码均以 Android 平台为例。如目标平台为 iOS,请参考 iOS 的 API 文档。
-
调用
joinChannel
[2/2] 加入合图流所在的频道。 -
通过 SDK 触发的
onTranscodedStreamLayoutInfo
回调,获取合图视频流的以下信息:- 合图视频流的宽、高,以及发布该视频流的用户 ID。
- 发布合图子视频流的用户 ID。
- 合图子视频流在合图画布上的 x 和 y 坐标。
- 合图子视频流的宽度和高度。
- 合图子视频流在合图画布上的状态:正常渲染、显示为占位符,或显示为黑色图片。
-
接收端调用
setupRemoteVideo
方法设置远端视频流在本地的渲染模式,重点参数设置如下所示:sourceType
:设置为VIDEO_SOURCE_TRANSCODED
,表示视频源为转码后的合图视频流。uid
:将合图视频流转发至当前频道的用户 ID,即在onTranscodedStreamLayoutInfo
回调中获取的uid
。view
:在本地显示的远端视频视图。你可以通过该参数设置每一路子视频流在本地视图中显示的位置。subviewUid
:合图视频流中某一路子视频流所对应的用户 ID。
信息- 当
subviewUid
的值不为 0 时,setupMode
的默认值为VIEW_SETUP_MODE_REPLACE
(增加一个视图)。
以下示例代码以多频道场景下调用
setupRemoteVideoEx
为例进行介绍,在非多频道场景下调用setupRemoteVideo
的方式与之类似。JavamRtcEngine.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
回调,当转发合图流的用户退出频道时,停止在接收端渲染合图流。
注意事项
- 目前仅支持在移动端实现自定义合图布局功能。
- 当合图视频流被添加了水印时,水印会随所在的区域被渲染,可能会出现被分割的情况。