夏眠鱼

Jun 21, 2020

Android 连麦云端合图实践

连麦合图有两个方案,一是云端合图,二是 App 端合图,一般推荐使用云端合图,因为 App 端合图要多路播放,对手机性能要求较高。

连麦的界面布局一般是大小屏,如下图:
guestlive-stream1

这里有两个问题需要解决:

  1. 手机分辨率碎片化严重,合图会被裁剪,怎么避免连麦用户被裁剪?
  2. 连麦用户和连麦UI窗口如何吻合?

从友盟全域罗盘中了解到,Android 手机分辨率高宽比在 1.7 ~ 2.1 之间,未来手机分辨率高宽比呈增大趋势。连麦用户放置在右下角时,其右边比底部更容易被裁剪,所以在旁路推流参数中,主播宽高比应该接近 2.1。在实践中发现,将主播的分辨率设为 960x480,连麦用户的分辨率设为 200x160,再调整连麦用户的左边距和上边距就可以解决问题一。
guestlive-stream2

1
2
3
4
5
6
int aw = 480; // 主播的宽度
int ah = 960; // 主播的高度
int gw = 160; // 连麦用户的宽度
int gh = 200; // 连麦用户的高度
int leftMargin = aw / 2 + 5 * (aw / 2 - gw) / 6; // 连麦用户的左边距
int topMargin = ah / 2 + 2 * (ah / 2 - gh) / 5; // 连麦用户的上边距

接下来看看问题二,合图被裁剪有两种情况:

  1. 合图高宽比大于屏幕高宽比,基于屏幕宽等比例拉伸,垂直方向裁剪;
    guestlive-adapter-vertical

  2. 合图高宽比小于屏幕高宽比,基于屏幕高等比例拉伸,水平方向被裁剪。
    guestlive-adapter-horizontal

基于旁路推流参数和合图被裁剪的分析,可以得出连麦用户和连麦UI窗口的吻合参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
float aRatio = (float) ah / aw; // 合图高宽比
float sRatio = (float) sh / sw; // 屏幕高宽比
int leftMargin; // 连麦UI窗口的左边距
int topMargin; // 连麦UI窗口的上边距
int scaleGw; // 拉伸后的连麦UI窗口宽度
int scaleGh; // 拉伸后的连麦UI窗口高度
if (aRatio > sRatio) { // 合图高宽比大于屏幕高宽比
float scaleRatio = (float) sw / aw;
int scaleAw = (int) (scaleRatio * aw);
int scaleAh = (int) (scaleRatio * ah);
scaleGw = (int) (scaleRatio * gw);
scaleGh = (int) (scaleRatio * gh);
leftMargin = scaleAw / 2 + 5 * (scaleAw / 2 - scaleGw) / 6;
topMargin = scaleAh / 2 + 2 * (scaleAh / 2 - scaleGh) / 5 - (scaleAh - sh) / 2;
} else if (aRatio < sRatio) { // 合图高宽比小于屏幕高宽比
float scaleRatio = (float) sh / ah; // 小窗口缩放比
int scaleAw = (int) (scaleRatio * aw);
int scaleAh = (int) (scaleRatio * ah);
scaleGw = (int) (scaleRatio * gw);
scaleGh = (int) (scaleRatio * gh);
leftMargin = scaleAw / 2 + 5 * (scaleAw / 2 - scaleGw) / 6 - (scaleAw - sw) / 2;
topMargin = scaleAh / 2 + 2 * (scaleAh / 2 - scaleGh) / 5;
} else { // 合图高宽比等于屏幕高宽比
float scaleRatio = (float) sw / aw;
int scaleAw = (int) (scaleRatio * aw);
int scaleAh = (int) (scaleRatio * ah);
scaleGw = (int) (scaleRatio * gw);
scaleGh = (int) (scaleRatio * gh);
leftMargin = scaleAw / 2 + 5 * (scaleAw / 2 - scaleGw) / 6;
topMargin = scaleAh / 2 + 2 * (scaleAh / 2 - scaleGh) / 5;
}
OLDER > < NEWER