文章

直播推流组件

介绍直播推流组件的架构和组件设计思路。

直播推流组件

本文转自微信公众号 关键帧Keyframe,推荐您关注来获取音视频、AI 领域的最新技术和产品信息

微信公众号 微信扫码关注我们

您还可以加入知识星球 关键帧的音视频开发圈 来一起交流工作中的技术难题、职场经验

知识星球 微信扫码加入星球

本文中,我们来介绍在实际工作中,我们实现的直播推流组件架构、重点需求技术方案和常见问题解析。

其中,重点需求技术方案包括:

  • 1、码率自适应
  • 2、推流协议对比
  • 3、直播推流支持 H.265
  • 4、退后台保持推流
  • 5、直播连麦
    • 直播连麦客户端合流架构
    • 直播连麦服务端合流架构
    • 连麦时的回声消除

常见问题解析包括:

  • 1、采集的帧率和编码的帧率不一致会有什么影响?
  • 2、当推流中使用 B 帧时,应该怎样处理时间戳?
  • 3、虽然做了 DTS 时间戳偏移,但是有时候还是会遇到 PTS 小于 DTS 的情况,这是为什么?如何解决?
  • 4、推流端有哪些问题可能造成推流直播间发现没有声音?
  • 5、推流时发生退后台,回来后应该如何处理?

1、直播推流组件架构

直播推流器组件包括了采集前处理编码自适应封装传输等模块,这些模块组装成了一个推流的 Pipeline。

采集前处理模块主要是依赖音视频拍摄组件提供的能力来实现音视频的采集和前处理。

编码模块接收采集和前处理后的音视频数据(PCM、RGB/YUV),对其进行编码(AAC、H.264/H.265)。

封装模块则将编码后的音视频数据(AAC、H.264/H.265)封装成 FLV 格式交给传输模块。

传输模块则根据情况使用不同的传输协议(RTMP/KCP/RTP)将封装好的 FLV 数据发送给服务端。

为了能够适应网络情况,在直播推流组件中我们还会增加一个自适应模块来做网络自适应,这个模块会结合传输模块的数据发送情况来进行网络估计从而控制缓冲区的数据量以及数据发送的速度。

2、重点需求技术方案

2.1、码率自适应

推流端的码率自适应主要是通过计算单位时间内编码码率与发送码率来判断网络的实时情况,然后可以根据多次判定的结果进行码率调整。

下面是 RTMP 推流码率自适应的一种示例策略:

  • 网络状况判断:每秒统计当前编码码率发送码率进行对比,统计连续 10 次的对比结果,定义:这 10 次统计中发送码率大于或等于编码码率的次数在 [N, 10] 区间,则判定网络优秀;在 [M, N) 区间,则判定网络一般;在 [0, M) 区间,则判定网络较差。
  • 如果网络优秀:可在不超过设定的码率或帧率最大值的前提下,提高编码码率或帧率。这里需要注意,提升码率需要慢慢来,例如每次幅度增加 25kbps-50kbps 左右。
  • 如果网络一般,则不进行操作。
  • 如果网络较差:1)优先降低帧率,例如认为 FPS >= 12 的流畅度可接受,则可以先将编码前帧率逐渐降低到 12,同时调整实时码率匹配此时的帧率,这样可以保证清晰度不变。2)当帧率降低到最小容忍值后,网络依然较差,则可以继续降码率。这里的策略可以是将码率每次降低 100kbps 左右;或者调整码率为最近连续几次发送码率的平均值。这里需要注意,降低码率需要快速降。3)如果依然发送阻塞,最后可以进行丢帧操作。丢帧的策略可以优先丢非参考帧 B 帧,然后丢 P 帧、I 帧,最后丢 Audio 帧。

下面是 WebRTC 拥塞控制算法 GCC(Google Congestion Control)的策略:

\[A_s(t_k)= \begin{cases} A_s(t_{k-1})(1 - 0.5f_l(t_k)),f_l(t_k) > 0.1\\ 1.05(A_s(t_{k-1})),f_l(t_k) < 0.02\\ A_s(t_{k-1}),otherwise \end{cases}\]
  • 基于丢包计算带宽估计:WebRTC 通过上面公式来估算发送码率,公式中 As(tk) 即为 tk 时刻的带宽估计值,fl(tk) 即为 tk 时刻的接收端的丢包率。接收端的丢包率通过 RTCP 反馈消息发送到发送端,发送端根据丢包多少进行判断网络的拥塞程度,丢包越多认为网络越差则进行降低码率,反之网络越好需要提高码率。
  • 基于延迟梯度带宽估计:WebRTC 新版本带宽估计已经放在了发送端,拥塞的基本检测跟以前没有什么大的差别,且发送端需要从接收端传来的延时信息来估计可用的带宽。RTCP 消息新增了传输反馈信息包,接收端会周期性地将包含有关已接收数据包和包间延时的信息反馈给发送端。接收端根据包间的接收延迟和发送间隔可以计算出延迟梯度,从而估计带宽。在发送端做带宽估计的好处是什么?Google 给出的解释是,这样做的话,所有的决定逻辑都会在一个地方(发送端),而且这会让测试新算法变得更简单,因为你不需要同时依赖于两个端点做决策。

2.2、推流协议对比

推流协议底层的传输协议通常也还是基于常规的 TCP、UDP 协议,常见的基于 TCP 的推流协议有 RTMP,基于 UDP 的推流协议有 RTC、KCP,它们各有各的特点和适用场景,并且为了适应场景优化,对应的底层协议也可以做改造。

  • RTMP 基于 TCP 推流,比较适用于非实时互动场景,比如体育赛事转播、演唱会网络直播等,一般延迟大约在 3-10S 左右。
  • RTC 基于 UDP 推流,是比较成熟的直播推流协议,CDN 服务器也有相应的开源方案,但整体接入成本较高、SDK 代码量很大。
  • KCP 基于 UDP 推流,它的特点是比较轻量,可以自定义重传以及网络自适应算法,适用于弱网、实时互动场景,但缺点是需要自己搭建相关的 CDN 服务器。

2.3、直播推流支持 H.265

直播推流要支持 H.265 需要考虑几个方面:

1)一般直播使用的是 FLV 作为媒体流格式,但是官方的 FLV 协议是不支持 H.265 的,所以需要做一些自定义开发。

FLV 是 Adobe 公司推出的协议,但后续已经没有再维护了,所以 FFmpeg 也没有主动去实现让 FLV 支持 H.265,这样一来就需要各厂商自己做一些自定义开发了。后来金山云实现了一个 FFmpeg 的 hack 版本,从而让 RTMP/HTTP-FLV 协议支持了 H.265 编码。因此,即使标准的解码器(播放器)无法播放金山云的 hack 版本生成的 RTMP/HTTP-FLV 的 H.265 直播流,但是,金山云实现的这个私有的协议也基本上成为了国内直播相关业务的标准协议了。其中对协议的主要改动包括:

1.1)对 FLV 中 VideoTagHeader 的 CodecID 字段扩展 12 表示 H.265。CodecID 是一个 4bit 长度的字段,扩展后的默认值定义如下:

1
2
3
4
5
6
7
2 = Sorenson H.263
3 = Screen video
4 = On2 VP6
5 = On2 VP6 with alpha channel
6 = Screen video version 2
7 = AVC
12 = HEVC // 扩展

1.2)当 CodecID 为 12 时(即 H.265),原来的 AVCPacketType 字段更新为 HEVCPacketType 字段。HEVCPacketType 字段是一个 1byte 长度的字段,扩展后的默认值定义如下:

1
2
3
0 = HEVC sequence header // 扩展,表示 HEVCVIDEOPACKET 中存放的是 HEVC sequence header
1 = HEVC NALU // 扩展,表示 HEVCVIDEOPACKET 中存放的是 HEVC NALU
2 = HEVC end of sequence (lower level NALU sequence ender is not required or supported) // 扩展,表示 HEVCVIDEOPACKET 中存放的是 HEVC end of sequence,即 HEVCDecoderConfiguration

1.3)当 CodecID 为 12 时(即 H.265),同样需要 CompositionTime 字段,该字段定义如下:

1
2
3
4
IF AVCPacketType == 1 OR HVCPacketType == 1
Composition time offset
ELSE
0

1.4)当 CodecID 为 12 时(即 H.265),VideoTagBody 也要支持 H.265,这时候其中存放的就是 H.265 的视频帧内容(即 HVCVIDEOPACKET)。

参考:

2)要考虑推流端设备是否支持 H.265 的编码能力,以及播放端是否支持 H.265 的解码能力。

2.4、退后台保持推流

在主播中,观看端的有一些卡顿是由于主播的行为引起的,比如主播使用手机推流的时候有退后台的操作,这时候推流断流,相当于生产侧的数据断掉了,拉流端没有数据自然会卡顿。对于这种情况,可以支持退后台继续推流,不过有几点需要注意:

  • 1)退后台如果继续采集音频可能涉及到隐私问题。对于这个问题,可以退后台停止采集,但是保持推静音音频数据。当然,如果产品上可以退后台继续采集音频,就使用系统的能力持续采集就好了。
  • 2)退后台无法继续采集视频,这时候如果不推视频数据,那么可能会引起 CDN 和播放器的不兼容的问题。因为有的 CDN 和播放器是需要检查视频数据,以及根据视频数据做一些功能和策略的。对于这个问题,可以推退后台前的最后一帧画面,并且适当降低帧率来降低推流的码率。
  • 3)由于退后台时间较长后,App 的网络请求可能被系统中断,甚至 App 可能被杀死。对于这个问题,可以尝试一些后台保活的方案,比如 iOS 可以在退后台后播放静音音频来保活。

2.5、直播连麦

连麦是直播中很常见的一种业务形式,支持连麦是直播推流端的一项重要功能。

2.5.1、直播连麦客户端合流架构

直播连麦在客户端进行合流时,主播端一方面使用 WebRTC 和远端主播连麦通信,一方面使用推流器进行合流和推流操作。其中需要注意:

  • WebRTC 采集模块、编码模块要提供数据回调接口和推流器对接。
  • WebRTC 回声消除模块要与推流器对接。
  • WebRTC 给推流器回调解码后数据(PCM、YUV/Texture)。这个数据是要和播放效果一致的数据,即已回声消除或倍速,如果上抛 texture,要共用 OpenGL context。
  • WebRTC 解决底层依赖的编译库冲突问题,FFmpeg、OpenSSL 等。
  • 推流器在连麦和非连麦模式切换时,要支持推不同的分辨率和码率,并且刷新 SPS、PPS 信息。
  • 播放端要支持直播流在分辨率变化时能够正常切换画面。这里可以通过探测到 SPS、PPS 中的分辨率信息变化时,来刷新解码器。

2.5.2、直播连麦服务端合流架构

……


全文见我们的知识星球帖子:https://t.zsxq.com/IuDsJ

知识星球 微信扫码加入星球

本文由作者按照 CC BY-NC-ND 4.0 进行授权