说明:本文转自@高可用架构,写的很详细,故拿来分享 作者:徐立,七牛创始合伙人兼产品副总裁,负责七牛直播云的整体研发,是国内 Go / Docker / Container 技术早期布道者,Go / Containers / Distributed Systems 技术的忠实爱好者和实践者。曾合著国内第一本 Go 语言图书《Go 语言编程》,翻译《Go 语言程序设计》。 现今移动直播技术上的挑战要远远难于传统设备或电脑直播,其完整的处理环节包括但不限于:音视频采集、美颜/滤镜/特效处理、编码、封包、推流、转码、分发、解码/渲染/播放等。 直播常见的问题包括: 主播在不稳定的网络环境下如何稳定推流? 偏远地区的观众如何高清流畅观看直播? 直播卡顿时如何智能切换线路? 如何精确度量直播质量指标并实时调整? 移动设备上不同的芯片平台如何高性能编码和渲染视频? 美颜等滤镜特效处理怎么做? 如何实现播放秒开? 如何保障直播持续播放流畅不卡顿? 本次分享将为大家揭开移动直播核心技术的神秘面纱。 视频、直播等基础知识 什么是视频? 首先我们需要理解一个最基本的概念:视频。从感性的角度来看,视频就是一部充满趣味的影片,可以是电影,可以是短片,是一连贯的视觉冲击力表现丰富的画面和音频。但从理性的角度来看,视频是一种有结构的数据,用工程的语言解释,我们可以把视频剖析成如下结构: 内容元素 ( Content ) 图像 ( Image ) 音频 ( Audio ) 元信息 ( Metadata ) 编码格式 ( Codec ) Video : H.264,H.265, … Audio : AAC, HE-AAC, … 容器封装 (Container) MP4,MOV,FLV,RM,RMVB,AVI,… 任何一个视频 Video 文件,从结构上讲,都是这样一种组成方式: 由图像和音频构成最基本的内容元素 图像经过视频编码压缩格式处理(通常是 H.264) 音频经过音频编码压缩格式处理(例如 AAC) 注明相应的元信息(Metadata) 最后经过一遍容器(Container)封装打包(例如 MP4),构成一个完整的视频文件。 如果觉得难以理解,可以想象成一瓶番茄酱。最外层的瓶子好比这个容器封装(Container),瓶子上注明的原材料和加工厂地等信息好比元信息(Metadata),瓶盖打开(解封装)后,番茄酱本身好比经过压缩处理过后的编码内容,番茄和调料加工成番茄酱的过程就好比编码(Codec),而原材料番茄和调料则好比最原本的内容元素(Content)。 视频的实时传输 简而言之,理性的认知视频的结构后,有助于我们理解视频直播。如果视频是一种“有结构的数据”,那么视频直播无疑是实时传输这种“有结构的数据”(视频)的方式。 那么一个显而易见的问题是:如何实时(Real-Time)传输这种“有结构的数据”(视频)呢? 这里边一个悖论是:一个经过容器(Container)封装后的视频,一定是不可变的 ( Immutable ) 视频文件,不可变的 ( Immutable ) 的视频文件已经是一个生产结果,根据“相对论”,而这个生产结果显然不可能精确到实时的程度,它已经是一段时空的记忆。 因此视频直播,一定是一个 “边生产,边传输,边消费”的过程。这意味着,我们需要更近一步了解视频从原始的内容元素 ( 图像和音频 ) 到成品 ( 视频文件 ) 之前的中间过程 ( 编码 )。 视频编码压缩 不妨让我们来深入浅出理解视频编码压缩技术。 为了便于视频内容的存储和传输,通常需要减少视频内容的体积,也就是需要将原始的内容元素(图像和音频)经过压缩,压缩算法也简称编码格式。例如视频里边的原始图像数据会采用 H.264 编码格式进行压缩,音频采样数据会采用 AAC 编码格式进行压缩。 视频内容经过编码压缩后,确实有利于存储和传输; 不过当要观看播放时,相应地也需要解码过程。因此编码和解码之间,显然需要约定一种编码器和解码器都可以理解的约定。就视频图像编码和解码而言,这种约定很简单: 编码器将多张图像进行编码后生产成一段一段的 GOP ( Group of Pictures ) , 解码器在播放时则是读取一段一段的 GOP 进行解码后读取画面再渲染显示。 GOP ( Group of Pictures ) 是一组连续的画面,由一张 I 帧和数张 B / P 帧组成,是视频图像编码器和解码器存取的基本单位,它的排列顺序将会一直重复到影像结束。 I 帧是内部编码帧(也称为关键帧),P 帧是前向预测帧(前向参考帧),B 帧是双向内插帧(双向参考帧)。简单地讲,I 帧是一个完整的画面,而 P 帧和 B 帧记录的是相对于 I 帧的变化。 如果没有 I 帧,P 帧和 B 帧就无法解码。 小结一下,一个视频 ( Video ) ,其图像部分的数据是一组 GOP 的集合, 而单个 GOP 则是一组 I / P / B 帧图像的集合。 在这样的一种几何关系中,Video 好比一个 “物体”,GOP 好比 “分子”,I / P / B 帧的图像则好比 “原子”。 想象一下,如果我们把传输一个 “物体”,改成传输一个一个的 “原子”,将最小颗粒以光速传送,那么以人的生物肉眼来感知,将是一种怎样的体验? 什么是视频直播? 不难脑洞大开一下,直播就是这样的一种体验。视频直播技术,就是将视频内容的最小颗粒 ( I / P / B 帧,…),基于时间序列,以光速进行传送的一种技术。 简而言之,直播就是将每一帧数据 ( Video / Audio / Data Frame ),打上时序标签 ( Timestamp ) 后进行流式传输的过程。发送端源源不断的采集音视频数据,经过编码、封包、推流,再经过中继分发网络进行扩散传播,播放端再源源不断地下载数据并按时序进行解码播放。如此就实现了 “边生产、边传输、边消费” 的直播过程。 理解以上两个关于 视频 和 直播 两个基础概念后,接下来我们就可以一窥直播的业务逻辑了。 直播的业务逻辑 如下是一个最精简的一对多直播业务模型,以及各个层级之间的协议。 各协议差异对比如下 以上就是关于直播技术的一些基础概念。下面我们进一步了解下影响人们视觉体验的直播性能指标。 影响视觉体验的直播性能指标 直播第一个性能指标是延迟,延迟是数据从信息源发送到目的地所需的时间。 根据爱因斯坦的狭义相对论,光速是所有能量、物质和信息运动所能达到的最高速度,这个结论给传播速度设定了上限。因此,即便我们肉眼感觉到的实时,实际上也是有一定的延迟。 由于 RTMP/HLS 是基于 TCP 之上的应用层协议,TCP 三次握手,四次挥手,慢启动过程中的每一次往返来回,都会加上一次往返耗时 ( RTT ),这些交互过程都会增加延迟。 其次根据 TCP 丢包重传特性,网络抖动可能导致丢包重传,也会间接导致延迟加大。 一个完整的直播过程,包括但不限于以下环节:采集、处理、编码、封包、推流、传输、转码、分发、拉流、解码、播放。从推流到播放,再经过中间转发环节,延迟越低,则用户体验越好。 第二个直播性能指标卡顿,是指视频播放过程中出现画面滞帧,让人们明显感觉到“卡”。单位时间内的播放卡顿次数统计称之为卡顿率。 造成卡顿的因素有可能是推流端发送数据中断,也有可能是公网传输拥塞或网络抖动异常,也有可能是终端设备的解码性能太差。卡顿频次越少或没有,则说明用户体验越好。 第三个直播性能指标首屏耗时,指第一次点击播放后,肉眼看到画面所等待的时间。技术上指播放器解码第一帧渲染显示画面所花的耗时。通常说的 “秒开”,指点击播放后,一秒内即可看到播放画面。首屏打开越快,说明用户体验越好。 如上三个直播性能指标,分别对应一个低延迟、高清流畅、极速秒开 的用户体验诉求。了解这三个性能指标,对优化移动直播 APP 的用户体验至关重要。 那么移动直播场景下具体而言有哪些常见的坑呢? 根据实践总结下来的经验,移动平台上视频直播的坑主要可以总结为两方面:设备差异,以及网络环境这些场景下带来的技术考验。 移动直播场景的坑与规避措施 不同芯片平台上的编码差异 iOS 平台上无论硬编还是软编,由于是 Apple 一家公司出厂,几乎不存在因为芯片平台不同而导致的编码差异。 然而,在 Android 平台上,Android Framework SDK 提供的 MediaCodec 编码器,在不同的芯片平台上,差异表现很大, 不同的厂家使用不同的芯片,而不同的芯片平台上 Android MediaCodec 表现略有差异,通常实现全平台兼容的成本不低。 另外就是 Android MediaCodec 硬编层面的 H.264 编码画质参数是固定的…