旁路推流画面布局
更新时间: 2024/08/05 15:02:55
配置旁路推流任务时,您可以自定义房间画面的各路视频布局方式,例如调整整体画布大小和颜色、各路视频的图像大小、位置等。本文档为您介绍视频布局的设置方式和推荐设置。
限制说明
- 用户窗口边界不能超出整体画布。
- 视频互动的画面布局中,最多 7 人参与;纯语音互动最多 21 人。
设置画面布局
您可以选择通过客户端的旁路推流相关接口的 layout
参数或者服务端 RESTful API 设置旁路推流的画面布局,服务端设置旁路推流画面布局的方法请参考旁路推流画面布局。移动客户端受限于网络状况,为保证直播的稳定性,建议通过服务端实现旁路推流。本文档为您展示通过客户端设置旁路推流画面布局的实现方式。
背景画布
通过 NERtcLiveStreamLayout
类的 width
等字段设置混流视频的背景画布属性,包括背景画布的高度、宽度和颜色。
相关字段的具体说明如下:
参数名称 |
类型 |
描述 |
---|---|---|
width | int | 整体画布的宽度,单位为 px。 取值范围为 0 ~ 1920,若设置为奇数值,会自动向下取偶。 |
height | int | 整体画布的高度,单位为 px。 取值范围为 0 ~ 1920。若设置为奇数值,会自动向下取偶。 |
background_color |
int |
画面背景颜色,默认为 0,即黑色。支持以下格式的颜色码:
|
用户画面
通过 NERtcLiveStreamLayout
类的 user_count
和 users
参数设置混流视频中的参与者人数、每个参与者对应的画面属性。
users
参数相关字段的具体说明如下:
参数名称 |
类型 |
描述 |
---|---|---|
uid | uint64_t | 将指定 uid 对应用户的视频流拉入直播。 如果添加多个 users,则 uid 不能重复。 |
x | int | 通过 x 和 y 指定画布坐标中的一个点,该点将作为用户图像的左上角。 x 参数用于设置画布的横轴坐标值。 取值范围为 0 ~ 1920,若设置为奇数值,会自动向下取偶。 |
y | int | 通过 x 和 y 指定画布坐标中的一个点,该点将作为用户图像的左上角。 y 参数用于设置画布的纵轴坐标值。 取值范围为 0 ~ 1920,若设置为奇数值,会自动向下取偶。 |
z_order |
int |
直播视频上用户视频帧的图层编号。取值范围为 0 ~ 100。
|
width | int | 该用户图像在画布中的宽度。 取值范围为 0 ~ 1920,若设置为奇数值,会自动向下取偶。 |
height | int | 该用户图像在画布中的高度。 取值范围为 0 ~ 1920,若设置为奇数值,会自动向下取偶。 |
adaption |
int |
用于设置占位图片和指定区域的适应属性。可设置为:
|
audio_push |
bool |
是否在直播中混流该用户的对应音频流。可设置为:
|
video_push |
bool |
是否在直播中向观看者播放该用户的对应视频流。可设置为:
|
占位图片
通过 NERtcLiveStreamLayout
类的 bg_image_count
和 bg_image
参数设置占位图个数、每张占位图对应的画面属性。
- 支持设置最多 6 张图片。
- 您可以通过
NERtcLiveConfig
的interrupted_place_image
字段选择是否开启此功能;若设置为关闭,则此设置无效。
bg_image
参数相关字段的具体说明如下:
参数名称 | 类型 | 描述 |
---|---|---|
url | char | 占位图片的 URL。 |
x | int | 通过 x 和 y 指定画布坐标中的一个点,该点将作为占位图片的左上角。 x 参数用于设置画布的横轴坐标值。 取值范围为 0 ~ 1920,若设置为奇数值,会自动向下取偶。 |
y | int | 通过 x 和 y 指定画布坐标中的一个点,该点将作为占位图片的左上角。 y 参数用于设置画布的纵轴坐标值。 取值范围为 0 ~ 1920,若设置为奇数值,会自动向下取偶。 |
width | int | 该占位图片在画布中的宽度。 取值范围为 0 ~ 1920,若设置为奇数值,会自动向下取偶。 |
height | int | 该占位图片在画布中的高度。 取值范围为 0 ~ 1920,若设置为奇数值,会自动向下取偶。 |
z_order |
int |
占位图的图层编号。取值范围为 0 ~ 100。
|
布局示例
本文档以服务端 API 创建推流任务为例,为您展示通过服务端 API 接口 layout 参数设置旁路推流画面布局的方式。
请求示例
在本示例中,音视频房间中有两位主播/连麦者,其推流画面布局为横向左右均分布局,原始画布为深灰色,其中一人掉线后显示占位图片。
示例代码如下:
C++//加入房间前设置直播模式
NERtcChannelProfileType channelProfileType = kNERtcChannelProfileLiveBroadcasting;
rtc_engine_->setChannelProfile(channelProfileType);
//加入房间后创建推流任务
//添加推流任务的异步callback,更多错误码请参考onAddLiveStreamTask的API文档
void onAddLiveStreamTask(const char* task_id, const char* url, int error_code){
if (code == kNERtcNoError) {
showToast("添加推流任务成功 : taskId " + taskId);
} else {
showToast("添加推流任务失败 : taskId " + taskId + " , code : " + code);
}
};
//推流任务数据结构
NERtcLiveStreamTaskInfo ls_task_info_;
strncpy(ls_task_info_.task_id, task_id.c_str(), kNERtcMaxTaskIDLength);
strncpy(ls_task_info_.stream_url, url.c_str(), kNERtcMaxURILength);
ls_task_info_.ls_mode = kNERtcLsModeVideo;
ls_task_info_.server_record_enabled = false;
//设置音视频编码参数
ls_task_info_.config.interrupted_place_image = true;
ls_task_info_.config.single_video_passthrough = true;
ls_task_info_.config.audio_bitrate = 64;
ls_task_info_.config.sampleRate = kNERtcLiveStreamAudioSampleRate48000;
ls_task_info_.config.audioCodecProfile = NERtcLiveStreamAudioCodecProfileLCAAC;
ls_task_info_.config.channels = 2;
//设置整体布局
ls_task_info_.layout.background_color = 0x808080;
ls_task_info_.layout.width = 720;
ls_task_info_.layout.height = 640;
//设置直播成员布局
ls_task_info_.layout.user_count = 2;
ls_task_info_.layout.users = new NERtcLiveStreamUserTranscoding[2];
ls_task_info_.layout.users[0].uid = 66601;
ls_task_info_.layout.users[1].uid = 66602;
for (int i = 0; i < ls_task_info_.layout.user_count; i++)
{
ls_task_info_.layout.users[i].adaption = kNERtcLsModeVideoScaleFit;
ls_task_info_.layout.users[i].video_push = true;
ls_task_info_.layout.users[i].x = 360 * i;
ls_task_info_.layout.users[i].y = 0;
ls_task_info_.layout.users[i].width = 360;
ls_task_info_.layout.users[i].height = 640;
ls_task_info_.layout.users[i].audio_push = true;
ls_task_info_.layout.users[i].zorder = 1;
}
//设置占位图布局
ls_task_info_.layout.bg_image_count = 1;
ls_task_info_.layout.bg_image = new NERtcLiveStreamImageInfo;
std::string url = "www.163.com/test.jpg";
memset(ls_task_info_.layout.bg_image, 0, sizeof(NERtcLiveStreamImageInfo));
memcpy(ls_task_info_.layout.bg_image.url, url.data(), url.size());
ls_task_info_.layout.bg_image->x =360;
ls_task_info_.layout.bg_image->y = 0;
ls_task_info_.layout.bg_image->width = 360;
ls_task_info_.layout.bg_image->height = 640;
ls_task_info_.layout.bg_image->zorder = 0;
// 之后用户以配置了的uid进入房间,开启推流开关即可推流
int ret = addLiveStreamTask(ls_task_info_);
if (ret != 0) {
showToast("调用添加推流任务失败 , ret : " + ret);
}
效果展示
-
原始画布:
-
增加占位图片:
-
正常显示画面:
-
右侧用户断线:
-
左侧用户断线:
常用布局设置
互动直播支持自定义配置视频布局,您也可以参考以下典型的常用布局配置,优化您的自定义布局。
双人横向平铺
-
显示效果
-
layout
参数配置示例
//设置整体布局
ls_task_info_.layout.background_color = 0x808080;
ls_task_info_.layout.width = 640;
ls_task_info_.layout.height = 360;
//设置直播成员布局
ls_task_info_.layout.user_count = 2;
ls_task_info_.layout.users = new NERtcLiveStreamUserTranscoding[2];
ls_task_info_.layout.users[0].uid = 66601;
ls_task_info_.layout.users[1].uid = 66602;
for (int i = 0; i < ls_task_info_.layout.user_count; i++)
{
ls_task_info_.layout.users[i].adaption = kNERtcLsModeVideoScaleFit;
ls_task_info_.layout.users[i].video_push = true;
ls_task_info_.layout.users[i].x = 320 * i;
ls_task_info_.layout.users[i].y = 0;
ls_task_info_.layout.users[i].width = 320;
ls_task_info_.layout.users[i].height = 360;
ls_task_info_.layout.users[i].audio_push = true;
ls_task_info_.layout.users[i].zorder = 1;
}
三人纵向平铺
-
显示效果
-
layout
参数配置示例
//设置整体布局
ls_task_info_.layout.background_color = 0x808080;
ls_task_info_.layout.width = 360;
ls_task_info_.layout.height = 640;
//设置直播成员布局
ls_task_info_.layout.user_count = 3;
ls_task_info_.layout.users = new NERtcLiveStreamUserTranscoding[3];
//设置上方成员布局
ls_task_info_.layout.users[0].uid = 123;
ls_task_info_.layout.users[0].adaption = kNERtcLsModeVideoScaleFit;
ls_task_info_.layout.users[0].video_push = true;
ls_task_info_.layout.users[0].x = 0;
ls_task_info_.layout.users[0].y = 0;
ls_task_info_.layout.users[0].width = 360;
ls_task_info_.layout.users[0].height = 320;
ls_task_info_.layout.users[0].audio_push = true;
ls_task_info_.layout.users[0].zorder = 1;
//设置左下角成员布局
ls_task_info_.layout.users[1].uid = 456;
ls_task_info_.layout.users[1].adaption = kNERtcLsModeVideoScaleFit;
ls_task_info_.layout.users[1].video_push = true;
ls_task_info_.layout.users[1].x = 0;
ls_task_info_.layout.users[1].y = 320;
ls_task_info_.layout.users[1].width = 180;
ls_task_info_.layout.users[1].height = 320;
ls_task_info_.layout.users[1].audio_push = true;
ls_task_info_.layout.users[1].zorder = 1;
//设置右下角成员布局
ls_task_info_.layout.users[2].uid = 789;
ls_task_info_.layout.users[2].adaption = kNERtcLsModeVideoScaleFit;
ls_task_info_.layout.users[2].video_push = true;
ls_task_info_.layout.users[2].x = 180;
ls_task_info_.layout.users[2].y = 320;
ls_task_info_.layout.users[2].width = 180;
ls_task_info_.layout.users[2].height = 320;
ls_task_info_.layout.users[2].audio_push = true;
ls_task_info_.layout.users[2].zorder = 1;
1 + N 悬浮布局
-
显示效果
-
layout
参数配置示例
//设置整体布局
ls_task_info_.layout.background_color = 0x808080;
ls_task_info_.layout.width = 360;
ls_task_info_.layout.height = 640;
//设置直播成员布局
ls_task_info_.layout.user_count = 3;
ls_task_info_.layout.users = new NERtcLiveStreamUserTranscoding[3];
//设置上方成员布局
ls_task_info_.layout.users[0].uid = 123;
ls_task_info_.layout.users[0].adaption = kNERtcLsModeVideoScaleFit;
ls_task_info_.layout.users[0].video_push = true;
ls_task_info_.layout.users[0].x = 0;
ls_task_info_.layout.users[0].y = 0;
ls_task_info_.layout.users[0].width = 360;
ls_task_info_.layout.users[0].height = 640;
ls_task_info_.layout.users[0].audio_push = true;
ls_task_info_.layout.users[0].zorder = 1;
//设置左下角成员布局
ls_task_info_.layout.users[1].uid = 456;
ls_task_info_.layout.users[1].adaption = kNERtcLsModeVideoScaleFit;
ls_task_info_.layout.users[1].video_push = true;
ls_task_info_.layout.users[1].x = 45;
ls_task_info_.layout.users[1].y = 390;
ls_task_info_.layout.users[1].width = 110;
ls_task_info_.layout.users[1].height = 213;
ls_task_info_.layout.users[1].audio_push = true;
ls_task_info_.layout.users[1].zorder = 1;
//设置右下角成员布局
ls_task_info_.layout.users[2].uid = 789;
ls_task_info_.layout.users[2].adaption = kNERtcLsModeVideoScaleFit;
ls_task_info_.layout.users[2].video_push = true;
ls_task_info_.layout.users[2].x = 185;
ls_task_info_.layout.users[2].y = 390;
ls_task_info_.layout.users[2].width = 110;
ls_task_info_.layout.users[2].height = 213;
ls_task_info_.layout.users[2].audio_push = true;
ls_task_info_.layout.users[2].zorder = 1;