首页
学习
活动
专区
工具
TVP
发布

携程移动直播探索

一、背景

直播行业大概在 10 年前就开始兴起了,秀场直播和游戏直播是 pc 时代比较成功的应用场景。现阶段,移动互联网的大规模普及,流量价格越来越便宜,移动视频直播异常火爆,随着各行各业的不断融合,直播带货超高的营业额,明星艺人、销售、秀场网红的涌入,直播行业迎来了空前的繁荣发展。从 pc 直播到渐渐火爆的移动直播,直播技术也在不断地更新迭代,趋于成熟。

本文从直播流的选择、交互优化、快速迭代等方面介绍携程直播技术。

二、直播原理

视频直播流程如下图。简单来说,推流端通过视频采集功能,把采集到的视频画面经过一系列的业务特效处理后,进行视频编码推送。拉流端使用流播放器把视频画面播放出来。

  • 采集:视频采集的主要采集源:摄像头、屏幕录制、视频文件推流
  • 处理:视频采集后得到原始数据,为了增强一些现场效果,需要在编码前进行处理(logo、美颜、变声)
  • 编码:编码性能、编码速率和编码压缩比直接影响整个流媒体传送的用户体验和传送成本
  • 推流:推流是直播的第一步。推流协议的选择会直接影响到观看的用户体验,常见的流协议(RTMP、HLS)
  • 分发:流媒体服务器负责直播流的发布和转播分发功能
  • 播放:直播终端的展示

前四步我们通常情况下称为推流操作,第五步称为服务分发或者 cdn 分发,第六步称为拉流操作。简化图如下:

推流操作中比较重要的两步是编码和推流。

2.1 编码

1)编码是什么

视频编码是压缩和可能改变视频内容格式的过程。

2)编码能做什么

a. 减少占用空间;

b. 兼容性;

在减少占用空间方面:

(数据来源于网络)

在兼容性方面,有时内容已经被压缩到足够的大小,但仍然需要进行编码以实现兼容性。这通常被更准确地描述为代码转换。兼容可能涉及某些服务或程序,这些服务或程序需要某些编码规范。

国内常见的编解码器是 H.265、H.264。

2.2 推流

常见的流协议为以下几种:

1)RTMP

RTMP(Real Time MessagingProtocol):实时消息传输协议,是 Adobe 公司为 flash 播放器和服务器之间实现音频、视频和数据传输开发的实时消息传输协议。在 RTMP 协议中,视频必须是 H264 编码,音频必须是 AAC 或者 MP3 编码,且多以 Flv 格式封包。

RTMP 的优势在于:

  • RTMP 是专为流媒体开发的协议,对底层的优化比其它协议更加优秀,同时它 Adobe Flash 支持好,基本上所有的编码器(摄像头之类)都支持 RTMP 输出。
  • RTMP适合长时间播放。因为RTMP支持的很完善,所以能做到flash播放RTMP流长时间不断流。当时的测试时长是100万秒,即10天多可以连续播放。(数据来源于网络)
  • RTMP 的延迟相对较低,一般延时在 1-5s 之间,一般的视频会议,互动式直播,完全是够用的。

RTMP 的劣势是:RTMP 是基于 TCP 协议,不会丢包。所以当网络状态差时,服务器会将包缓存起来,导致累积的延迟;待网络状况好了,就一起发给客户端。

2)HLS

HLS(HTTPLive Straming): 是苹果公司实现的基于 HTTP 的流媒体传输协议。它将整个流分为多个小文件来下载,客户端只要不停的按顺序播放从服务器获取的文件,就实现了直播。

HLS 的优势是:客户端支持简单,只需要支持 HTTP 请求即可。并且 HTTP 协议很方便通过防火墙或者代理服务器。CDN 支持良好。由于是苹果公司提出的,所以在苹果的全系列产品都支持。

HLS 的劣势:相比 RTMP 这类长连接协议,HLS 的延时较高, 难以用到互动直播场景。

3)WebRTC

WebRTC(Web Real TimeCommunication):是一个支持浏览器进行实时语音、视频对话的开源协议。基于 UDP,即使在网络信号一般的情况下也具备较好的稳定性。

WebRTC 的优点:开发者使用简单的 HTML 标签和 JavaScriptAPI 就能够实现 Web 音/视频通信的功能。

WebRTC 的缺点:WebRTC 中很多的参数都是由 GIPS 公司的工程师们依靠经验所设定的值,这就会出现卡顿、延时、回声、丢包、多人视频不稳定等问题。WebRTC 缺乏服务器方案的设计和部署。对 Native 开发支持不够。

4)HTTP-Flv

HTTP-Flv:是一种将直播流模拟成 flv 文件,通过 http 协议进行下载的模式实现流媒体传输的协议。

它结合了 RTMP 的低延时,以及可以复用现有 HTTP 分发资源的流式协议。优势在于可以在一定程度上避免防火墙的干扰,可以使用 HTTPS 做加密通道,很好的支持移动端。

缺点在于由于它的传输特性,会让流媒体资源缓存在本地客户端,在保密性方面不够好。因为网络流量较大,它也不适合做拉流协议。

协议

http-flv

RTMP

HLS

WebRTC

传输方式

HTTP长连接

Tcp

http短连接

UDP

视频封装格式

FLV

FLV

TS文件

Track分片

原理

同RTMP,使用HTTP协议

每个时刻的数据收到后立即转发

集合一段时间的数据,生产TS切片并更新m3u8索引

Udp 传输协议,保证低延时和及时性。Client-client之间传输,要解决NAT 穿透问题。

延时

低 1-5s

低 1-5s

高 10-20秒

低1-2s

数据分段

连续流

连续流

切片文件

P2P数据交换

Html5

支持

不支持

支持

支持

其他

需要Flash技术支持,

网络质量要求高

要解决NAT,socket建立等问题

我们选择 RTMP 作为主要的流协议的原因有:

1)RTMP 是编码器输入的工业标准协议,基本上所有的编码器(摄像头等)都支持 RTMP 输出。

2)RTMP 适合长时间播放的优势,可以保证尽可能的减少用户重连的次数。

3)直播场景互动性交高,对时延要求高。RTMP 通常情况下可以做到 3 秒延迟,满足大多数场景(hls 大概 10 秒)。

4)WebRTC 对浏览器支持较好,对 native 支持不够,需要做大量的开发工作。

5)由于开源软件和开源库的支持稳定完整(OBS 软件,开源的 librtmp 库,服务端有 nginx-rtmp 插件),RTMP 在国内流行度很高,技术相对成熟。

目前市面上有很多云直播厂商。可以综合考虑推流协议,时延要求、推拉流费用,SDK 的 size 以及扩展直播场景等方面来选择适合自己的 sdk。

三、直播前端框架

当我们需要建立一个直播的时候,我们需要做什么呢?

简单的来说分 3 步。

第一步:从 sdk 中拿出推流 Manager,设置预览 View,设置推流地址。


@Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.live_push);
    livePusher = new LivePusher();
    videoView = findViewById(R.id. live_video_preview);
        livePusher. startCameraPreview(videoView);
        String pushUrl = "rtmp://...";
    livePusher.startPusher(PushUrl);
    }

第二步:使用拉流 Manager,设置播放预览 view,设置拉流地址和流类型(RTMP、flv 等)。

@Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.live_pull);
    livePlayer = new LivePlayer();
    playerView = findViewById(R.id.live_video_view);
        String pullURl = "rtmp://...";
    livePlayer.setPlayerView(playerView)
    livePlayer.startPlay(pullURl, PLAY_TYPE_LIVE_RTMP)

}

第三步就可以愉快地观看直播了。

携程直播就是在这个基础之上,进行了复杂的业务开发。视频推流和拉流是需要调用 Native 直播 sdk 的方法,所以需要保留在 Native 中。页面上的互动区域需要更快速的迭代方式,所以选择了 RN。

携程直播作出以下的分层结构:

视频直播前端框架图

1)Lib

这一层主要放置整个直播项目通用的类。

ClientProxy:网络请求的通用字段封装和返回的常规错误码处理、序列化处理、通用 Log 日志控制等。

PushManger 和 PullManger 使用了 Proxy 设计模式用于减少 sdk 和业务代码的耦合。使用单例模式保证多个直播的配置统一。

Event:跨平台事件传递类(EventBus),RN、Hybrid 的事件都最终调用 native 的 Event 方法发送事件来保证多平台事件传递的可能。

RN:

Event.sendEvent("EventName",{ params: 0 });

Native:

CtripEventCenter.getInstance().sendMessage(EventName,jsonObject)

底层都是调用 Native 的 EventBus。

IMManger:消息的管理类。控制直播间的弹幕消息,开始结束消息以及礼物等消息的分发。

2)Page

把推流和拉流页面称为 Page。主要作用有两个,首先调用 SDK 做推拉流。其次,在页面中对 RN 和 Native 进行交互,例如从消息中获取流状态、礼物或者其他的消息。然后给 RN 发 Event 事件或者调用 Native 方法来完成相关消息的后续动作。

Page 中注册消息监听。

interface CTLiveChatMessageListener {
       fun startLive()
}
Page.registerCTLiveChatMessageListener(listener)

在 listener 中使用 Event 分发事件。

3)View 层

Page 上挂载了一个透明的 RNView 作为直播中交互 View。主要负责渲染业务交互 view,比如头像名称、评论列表、礼物动画、商品卡片、分享等。

在 page 的 onCreate 的时候把 view 挂载上去。

manager.beginTransaction().add(R.id.live_crn_fragment, rnFragment,
        "livePage").commitAllowingStateLoss()

然后页面和逻辑放到 RN 中。

效果图上,摄像头的内容为原生 Native,其他的可见为 RNVIew。

四、遇到的问题和解决的办法

在 Native-RN 混合开发过程中,我们遇到了一些棘手的问题:

1)在多次唤醒直播间,或者同时打开多个直播间时,会存在画面和声音对不上,或者出现多个声道的问题。为了解决这个问题我们把直播间做成单例,保证整个 app 的运行过程中只存在一个直播间。

2)覆盖在直播预览页面上面的交互 RNView 设置为透明背景不生效问题。我们在 RN 的 render 返回一个透明 View,但是在页面上还是出现了白色的底色。这个时候需要检查一下 fragment 是否挂载在一个白色 View 上。

3)在 Page 初始化的时候发送 Event 事件,但是 RN 没有收到的问题。这个时候 RN 容器可能还没有创建完成,我们需要保证发送事件的时机在 RN 容器创建完成之后。

五、总结

视频直播在近几年是一个比较火爆的技术点。直播的场景每年都在迅速地更新中。我们需要使用一种更快速的迭代方式,所以需要在优化时把稳定的东西使用 native 封装成基础页面,在保证底层稳定的前提下,选择跨平台的技术栈进行快速的页面迭代开发。ReactNative 或者 Flutter 等跨平台开发语言都是不错的选择。

作者介绍

鹏程,携程 Android 开发工程师,Android google jetpack 和 kotlin 语言的拥护者。

本文转载自公众号携程技术(ID:ctriptech)。

原文链接

携程移动直播探索

  • 发表于:
  • 本文为 InfoQ 中文站特供稿件
  • 首发地址https://www.infoq.cn/article/PLf9GbskCVBcUDur9xZz
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券