观看全文:充分利用移动平台上的实时视频



在移动设备上播放视频的最简单方法是打开与系统上现有播放器的链接,但这并不总是有效的。

您可以使用ExoPlayer对其进行优化,甚至可以只使用编解码器和套接字编写自己的视频播放器。 本文将讨论流媒体和视频播放的工作,以及如何减少视频启动的延迟,如何减少流媒体和观众之间的响应时间以及优化功耗和铁负载。

我们将以特定的应用程序为例对此进行分析:Odnoklassniki移动客户端(用于播放视频)和OK Live(用于将广播从手机流传输到1080p)。 关于如何通过引用播放视频以及代码示例,将没有大师班。 故事将着重介绍视频从内部的外观以及了解视频播放器和视频流的一般体系结构后,您可以了解任何系统并使其变得更好。

该材料基于Mobius会议的Alexander Tobol@alatobol )和Ivan Grigoriev@ivan_a )的报告抄本。




参赛作品


对于初学者-有关Odnoklassniki中视频的一些数字。

每日平均最高VOD(视频点播)流量每秒超过一个半兆兆比特,而对于实时广播,则超过每秒3兆兆兆比特。

现在,每天可以观看超过8.7亿次视频,其中一半以上来自移动设备。



如果您看一下流媒体的历史,那么2007年YouTube上就出现了移动视频。 后来我们跳上了这列火车,但是在2014-2015年间,我们已经在移动设备上播放了4K视频,近年来,我们一直在积极开发播放器。 关于此事,对话将进行。

Periscope于2015年出现的第二个趋势是通过电话进行广播。 我们启动了OK Live应用程序,该应用程序允许您通过移动网络流式传输甚至是Full HD视频。 在材料的后半部分,我们还将讨论流媒体。

我们不会详细介绍用于处理视频的API,但现在请深入研究并尝试找出内部发生了什么。



当您在相机上拍摄视频时,它会到达编解码器,再从那里到套接字,再到服务器(无论是VOD还是Live)。 然后服务器以相反的顺序将其分发给受众。

让我们从KPI播放器开始。 我们要他做什么?

  • 快速的第一帧。 用户不想等待播放开始。
  • 缺乏缓冲。 没有人喜欢碰到躯干。
  • 高品质。 在几乎没有4K内容的情况下,我们已经使4K支持“增长”:如果您关闭播放器并确定性能,那么即使在较弱的设备上,1080p也可以完美播放。
  • 用户体验要求。 我们需要在滚动时在录像带中播放视频,对于录像带,我们需要预取视频。


这种方式存在很多问题。 4K视频流很大,我们在移动设备上工作,这些设备存在网络问题,视频格式和容器上的视频格式各不相同,并且设备本身也可能成为问题。

您认为在iOS或Android上,视频在哪里播放更快?

实际上,任何答案都是正确的:它取决于什么,在哪里玩和如何玩。 如果我们将俄罗斯地区的网络做得不太好,我们将看到AVPlayer的启动时间约为800毫秒。 但是使用相同的网络,Android上的ExoPlayer播放不同的格式将在660毫秒内启动它。 而且,如果您在iOS上制作播放器,那么它将能够更快地运行。



有一个细微的差别,我们衡量的是用户的平均值,而iOS设备的平均功能高于Android。

资料的第一部分将是理论性的:我们将学习什么是视频以及任何Live播放器的结构。 在第二部分中,让我们比较玩家并讨论何时编写自己的游戏。

第一部分


什么是视频


让我们从最基本的开始。 视频是每秒60或24张图片。

显然,将其与全套图片一起存储非常昂贵。 因此,它们以这种方式存储:有些帧称为参考帧(I帧),而另一些帧(B帧和P帧)称为“差异”。 实际上,您有一个jpg文件以及对其进行的一组特定更改。



还有GOP(图片组)的概念-这是一组独立的帧,从参考帧开始,以一组差异开始。 它可以独立播放,解压缩等。 同时,如果您在小组中丢了一个opornik,那么其余的帧将不再相关。

有很多编码算法,变换矩阵,运动搜索等-这就是编解码器的不同之处。

编解码器性能





经典的H.264自2003年以来广为人知,并且发展良好。 我们将以其有效性为基础。 他在任何地方工作和娱乐。 它具有对CPU / GPU的硬件支持(在iOS和Android上均如此)。 这意味着,或者有某种特殊的协处理器可以对其进行编码,或者有内置的指令集可以让您快速地做到这一点。 平均而言,硬件支持可将性能提高多达10倍,并可以节省电池寿命。

2010年,来自Google的VP8出现了。 在效率方面,它与H.264没有区别。 好吧,实际上编解码器的有效性是一个很有争议的事情。 在额头上,它是以原始视频与压缩后视频的比率来衡量的,但是很明显,存在着不同的视频伪像。 因此,我们提供了指向莫斯科国立大学编解码器的详细比较的链接 。 但是在这里,我们将自己限制在VP8专注于软件组织这一事实上,您可以将其随身携带到任何地方,如果不提供本地H.264支持,通常将其用作备用。

2013年,出现了新一代编解码器-H.265(HEVC)和VP9。 H.265编解码器的效率提高了50%,但在Android视频上无法对其进行编码,解码器仅在Android 5.0+上出现。 但是在iOS上有支持。

H.265-VP9可以替代。 都一样,但是得到了Google的支持。 好吧,V9是YouTube,H.265是Netflix。 因此,每个都有其独特之处:一个在iOS上不起作用,另一个在Android上有问题。 最后,许多仍然保留在H.264上。

将来,我们有望获得AV1编解码器,它已经具有软件实现,并且其效率比2013编解码器高35%。 现在可以在Chrome和Firefox中使用,并且Google承诺在2020年提供硬件支持-我认为,我们很可能会全力以赴。

最后,他们最近宣布了H.266 / JVEC编解码器,并表示一切都会越来越好。

主要模式:编解码器的效率越高,设备需要的计算资源就越多。

通常,默认情况下,每个人都使用H.264,然后对于特定设备它可能会很复杂。

质量,分辨率和比特率


在2019年,您不会感到任何人具有自适应质量:用户以一种质量上传或流式传输视频,我们削减了一系列不同质量并将最适合的质量发送给设备。

在这种情况下,视频分辨率必须与比特率相关。 如果分辨率加倍,则比特率也应加倍:



显然,如果您以较低的比特率压缩高分辨率,反之亦然,那么比特率就会出现失真或无用的燃烧现象。

编码视频的比特率与原始信息量如何比较? 在4K屏幕上,我们可以播放近6 Gb / s的信息(如果您以每秒60帧的速度计算所有像素及其频率),而编解码器的比特率可以是50 Mb / s。 也就是说,编解码器最多可将视频压缩100倍。

输送技术


您有一些编解码器包装的音频和视频。 如果您只是将其放在家里,则可以通过添加一个小的索引来添加所有音频和视频,该索引可以告诉您音频和视频从几秒钟开始。 但是视频无法传送到电话,并且要在线流向观看者,有两种主要的协议类别:流和分段。



流协议意味着您在服务器(客户端)上也有某种状态,并且它发送数据。 服务器可以调整例如质量。 通常这是UDP连接。

这样的协议对于服务器而言非常复杂,并且难以交付。 对于繁重的翻译,我们使用基于HTTP的分段协议,可以由nginx和CDN缓存,并且它们更容易分发。 服务器不承担任何责任,在这种情况下,服务器不承担任何责任。

分段交付的方式是什么样的:我们将现有视频切成分段,并伴随它们附带音频和视频的标题,MPEG-TS和MP4作为传输示例。 在电话上,我们提供了清单,其中包含有关该段的位置和质量的信息,并且该清单可以定期更新。

从历史上看,Apple通过HLS交付产品,并通过DASH交付Android产品。 让我们看看它们有何不同。

让我们从较旧的HLS开始,它具有一个清单,该清单描述了所有可用的质量-低,中,高等。 这些品质都有比特率,因此玩家可以立即选择合适的品质。 他选择了质量,并获得了一个嵌套清单,其中包含到段的链接列表。 还指示了这些段的持续时间。



这里有一个有趣的功能:要开始播放第一帧,您将不得不进行两次额外的往返。 您的第一个请求将获得主清单,第二个是嵌套的清单,然后才访问数据本身,这不是很好。



第二个困难:HLS旨在通过HTTP在Internet上工作,但是传统的MPEG-2传输流被选择作为视频数据的容器,而视频数据的开发目的则是完全不同的:在嘈杂的信道中从卫星发送信号。 结果,我们获得了额外的标头,在HLS的情况下,这些标头完全没有用,只会增加开销。



增加网络开销和解析复杂性:如果您尝试在DASH中播放4K,在Chrome中播放HLS,则当计算机通过HLS数据包“起飞”时,您会感到与众不同。

苹果正试图解决这一问题。 在2016年,他们宣布可以使用Fragmented MPEG-4,HLS中对DASH有一些支持,但是额外的RTT及其功能并未消失。



DASH看起来更简单:您有一个清单,里面包含所有特质,每个特质都是一组细分。 您可以播放一个片段以一种品质播放,然后理解速度已经提高,从下一个片段切换到另一个片段。 所有段始终以参考帧开头,从而可以进行切换。

这是一小盘有关选择的内容:



在HLS中,历史上受支持的视频编解码器仅为H.264,在MPEG-DASH中,您可以推任何人。 HLS的主要问题是在开始时需要进行额外的往返,它在iOS和Android 4.0上都可以正常运行。 DASH主要受Google(Chrome和Android)支持,无法在iOS上播放。

播放器架构


我们或多或少地整理了视频,现在让我们看看任何播放器的外观。



让我们从网络部分开始:开始播放视频时,播放器遵循清单,以某种方式选择质量,然后遵循片段,下载它,然后需要对帧进行解码,了解缓冲区中有足够的帧要播放,然后开始播放。

播放器的一般架构:



有一个网络部分,一个套接字,数据是从那里来的。

之后-解复用器或某种从传输(HLS / DASH)获取音频和视频流的东西。 她将它们发送到适当的编解码器。

编解码器解码视频和音频,然后发生最有趣的事情:它们需要同步,以便同时播放视频和音频。 为此,有多种基于时间戳的机制。

然后,您需要将其渲染到任何地方-在纹理,表面,GL或金属中的任何地方。

在输入处有一个加载控件,该控件加载数据并控制缓冲区。

所有玩家的负载控制看起来如何? 有一些数据需要下载。 播放器会一直等到它们被下载,然后开始播放,然后我们进一步下载。 我们有最大的缓冲区限制,达到该限制后下载将停止。 之后,在播放过程中,缓冲区中的数据量下降-并且有一个最小边界开始加载。 因此,所有这些都还存在:



主循环线程是什么样的? 玩家似乎熟悉“滴答线”的概念。 网络的一部分负责将所有内容堆叠到一个缓冲区中。 有一个提取器将其解压缩并将其发送到编解码器,然后在其中提取中间缓冲区,然后将其渲染。 然后您可以移动并控制它们,处理同步。



在外部,您有一个应用程序,该应用程序通过消息队列发送一些命令,并通过侦听器接收一些信息。 有时可能会出现反压,这会降低画质-例如,在缓冲区用尽或渲染无法应付的情况下(例如,出现掉帧)。

估算器


进行调整时,播放器依赖于2个主要参数:网络速度和数据缓冲区。

外观:首先,再现某种质量,例如720p。 您的缓冲区越来越大,越来越多地缓存。 然后速度增加,您了解您可以下载更多,缓冲区增加。 现在,您了解可以尝试以下质量时,您正在跨入最小缓冲区的某些边界。



显然,您需要仔细尝试:还有一个估算器,它说您是否可以在网络速度方面达到这种质量。 如果您符合此评估要求,并且缓冲液允许,则可以切换到1080p,然后继续播放。

过压保护


随着时间的推移,她通过反复试验出现了。 当您的设备稍微过载时,就需要使用它。

在某些情况下,网络会在播放过程中变钝,或者后端的资源会用完。 当播放器恢复播放时,它开始追赶。

此刻,玩家的清单中已经积累了很多细分,可以迅速将它们一次全部下载下来,这给我们带来了“流量打击”。 如果客户端发生超时,并且播放器开始重新查询数据,则情况可能会加剧。 因此,有必要在系统中提供背压。

当然,我们使用的第一种简单方法是服务器上的调节器。 他知道流量会终止,降低质量,并故意放慢客户的速度,以免受到太大的打击。



但这并不能很好地影响估计量。 他们可以产生相同的“扭曲”。 因此,如果可能,请支持从清单中删除质量。 为此,您必须定期更新清单,或者如果有反馈渠道,则发出删除质量的命令,播放器将自动切换到另一个较低的质量。

玩家们


在iOS中,只有本机AVPlayer,但是在Android上,可以选择。 有一个本机MediaPlayer,但有一个基于Java的开源ExoPlayer,应用程序可以“随身携带”它们。 他们的优缺点是什么?

比较所有三个:



在自适应流传输的情况下,ExoPlayer会播放DASH / HLS并具有用于其他协议的许多可扩展模块,而AVPlayer会变得越来越差。

原则上,对操作系统版本的支持适合所有地方的所有人。

预取是指当您知道一个视频结束后要在磁带中播放以下内容并预加载它时。

本地播放器的错误修正存在问题。 对于ExoPlayer,您只需将其滚动到应用程序的新版本中,但是在本机AVPlayer和MediaPlayer中,该错误仅在下一个OS版本中得以修复。 我们痛苦地遇到了这一点:在iOS 8.01中,我们的视频开始播放效果不佳;在iOS 8.02中,整个门户网站停止了工作;在8.03中,一切又恢复了。 在这种情况下,没有任何东西依赖我们,我们只是坐在那里等待苹果推出下一个版本。

ExoPlayer团队讨论了音频情况下的能源效率低下。 Google提出了一些一般性建议:播放音频,使用MediaPlayer以及其他Exo。

理解之后,我们将在Android上将ExoPLayer与DASH一起用于视频,在iOS上将AVPlayer与HLS一起使用。

快速第一帧


同样,记住直到第一帧的时间。 在iOS HLS上的显示方式:首先是清单后面的RTT,然后是嵌套清单后面的另一个RTT,然后-获取片段并播放。 在Android中,一个RTT越少,它的启动效果就越好。



缓冲区大小


现在让我们处理缓冲区。 开始播放之前,我们需要下载的数据量最少。 在AVPlayer中,使用AVPlayerItem preferredForwardBufferDuration配置此值。



在Android上,ExoPlayer具有更多的配置机制。 必须有相同的最小缓冲区才能启动。 但是,还有一个用于拒绝的单独设置(如果您的网络掉线,则缓冲区中的数据用完,然后返回):



什么是利润? 如果您拥有良好的人际网络,则可以快速开始并争取快速的第一帧,这是您第一次可以尝试抓住机会。 但是,如果在播放期间网络中断,很明显,您需要请求在缓冲期间播放更多的缓冲,这样就不会出现重复的问题。

原始品质





iOS上的HLS存在一个很酷的问题:它总是从m3u8清单中的第一质量开始播放。 您给他的回报将开始。 只有这样,它才能测量下载速度并开始以正常质量播放。 很明显,这是不允许的。

逻辑优化-重新排序质量。 在服务器上(通过向preferredquality添加一个附加参数,它会对清单进行重新排序),或者在客户端上(创建一个可以为您完成此操作的代理)。

在Android上,有一个DefaultBandwidthMeter参数。 它给出的值将考虑您频段的默认带宽。



工作原理:代码中有一个庞大的常数表,参数很简单-国家(地区)和连接类型(Wi-Fi,2G,3G,4G)。 什么意思 例如,如果您具有Wi-Fi并且位于美国,则您的初始带宽为5.6 Mbps。 如果3G为700 kbps。

可以看出,根据Google的估计,俄罗斯的4G速度是美国的2-3倍。

显然,俄罗斯是一个大国,这种设置根本不适合我们。因此,如果您想简单地进行操作,请记住当前网络的先前值,以防万一减去一个单位,然后启动它。

并且,如果您有一个大型应用程序可以在世界范围内播放视频,请收集有关子网的统计信息,并从服务器推荐开始的质量。请记住,建议在缓冲后增加缓冲区的值(在Android上,这很容易允许)。

如何加快倒带速度


当用户将视频倒带到特定位置(搜索)时,您可能不会落在参考帧中,而是落在它们之间。因此,从先前参考到它的所有内容都需要下载和解码。



实际上,如果用户观看了两个小时的电影,那么加/减秒对他来说并不重要。因此,在iOS上,如果您知道视频以一定的间隔进行了整齐的切割,则可以计算并将其发送到该参考帧所在的位置(加上一个小的变化幅度,恰好在它之后,而不是在它的前面)。

在版本2.7.0的ExoPlayer中,可以指定要倒带的方式,并且在“下一帧”中有一个选项。在这种情况下,他将搜索最近的一帧,向前一秒,向后三帧。哪个会找到,然后倒带。



如果视频不是从头开始的(几乎所有视频托管公司都记得用户最后一次观看视频的时间),并且倒带到某个位置,请不要在Android上进行准备(mediaSource),然后在Android上进行seekTo()。如果您这样做,他将首先从一开始就准备比赛,然后倒带。交换这些行-这可以使我们大大加快速度:



即使您更改视频(先播放一个视频,然后播放另一个视频),也最好不要放开编解码器。这是一个非常昂贵的操作(大约100毫秒),您可能会使用相同的解码器设置播放下一个视频,这将完全适合您。



渲染图


在iOS上,所有内容都是简单呈现的,但是在Android上,有许多不同的遗留事物。
许多在TextureView上渲染。该选项很好,因为它是一个单独的内存区域,您复制整个框架,动画效果很好,并且与UI同步。但是也有缺点-发射时间长且功耗高。

有一个SurfaceView。您可以从那里快速开始,但这是视频内存中的一个漏洞。因此,在某些较旧的Android设备上,滚动时会以各种伪像的形式出现一个洞。 YouTube最初从未在播放过程中滚动视频,因此适合他们。

因此,存在GLSurfaceView-前两个之间的中间版本。如果归档渲染,则可以解决旧设备上纹理缓慢的问题。



底线:我们发现,如果我们仔细调整ExoPlayer,我们可以使第一帧速度提高23%。“捻”数减少了10%。所有这些调整为我们增加了大约4%的观看次数。是否需要这4%-自己决定,但这并不困难。

底线:Android建议


  • 使用MediaPlayer播放音乐,以及ExoPlayer所存在的所有其他功能
  • 优化开始,寻找,交换
  • 写下您的估计,很容易更换
  • 根据建议使用正确的视图

底线:iOS建议


iOS更难:

  • 我们在AVPlayer中的HLS上有额外的RTT
  • 专有估算器
  • AVPlayer#暂停后减慢主流
  • 本机-无源,仅在iOS版本上更新


因此,我们决定以自己的DASH播放器为生,以“任何实时播放器的体系结构”为基础。我们使用了:

  • cURL或GCDAsyncSocket
  • AVAssetReader,然后放弃它
  • CADisplayLink
  • AVSampleBufferDisplayLayer


这很耗时,但是我们得到了很多加速。到第一帧的时间减少了28%,扭曲减少了6%。但是最令人高兴的是,当从HLS切换到DASH时,我们将平均消耗的比特率提高了100 kbit / s,视图数量增加了6%。

iOS建议如下所示:

  • 优化开始和寻找
  • 在片段mp4上使用HLS
  • 编写您的DASH播放器


我们认为我们将努力使我们的玩家也跨平台。

第一部分结论:


您了解了视频,标准播放器体系结构,播放器比较和调优。

  • 选择适当的流格式(不仅限于mp4)
  • 选择合适的播放器(ExoPlayer,AVPlayer)
  • 收集有关firstFrame,seek,emptyBuffer的统计信息
  • 拉玩家并看到您的估算器
  • 写出您的播放器(如果确实需要的话)
  • 如果您想做严肃的事情,请提高标准。我们将标准提高到4K,并发现了所有错误:性能,解析,所有错误。


现在有关流媒体。

第二部分:DIY视频流


如果您需要从我们的移动设备发送视频怎么办?



需要用于相机捕获和编码的API。这些API提供对iOS和Android上的相机和硬件编码器的访问,这非常重要-它的运行速度比软件快得多。

套接字:您可以在自己喜欢的框架中使用某种包装器,也可以使用POSIX套接字,以纯模式进行所有操作,然后可以构成跨平台网络部分。

我们想从流媒体获得什么?

  • 低延迟
  • 广播质量好
  • 视音频稳定性
  • 快速上手


那又要打什么呢?

  • 低带宽
  • 延误
  • 音视频中断
  • 启动延迟(N x RTT,通常以RTT的数量来计算启动时间是很方便的)


为什么需要低延迟





第一种情况是与观众互动。我们具有测验和实时通话等功能,延迟在那里非常重要。

在测验中,他们提出一个问题并设置一个计时器:如果用户缓冲区中的数据量不同,他们将处于不同的状况,并且回答时间也将不同。实现相同缓冲区的唯一方法是降低延迟。

当前正在开发的方案是实时呼叫。您可以现场直播,并与他交谈。

第三种情况是4K体育广播。例如,您观看带有啤酒和薯条的世界杯,而墙后的邻居则观看同一件事。如果他们的目标已经实现,并且您还有30秒的缓冲时间,那么他们会更早开始欢欣鼓舞并破坏整个嗡嗡声。人们会去找延迟较小的竞争对手。

适应性


当然,我们拥有的网络是不同的,因此您需要适应每种网络。为此,我们更改了视频和音频的比特率(此外,在视频中,它可以更改100次)。

如果我们发现我们没有时间去适应或已经耗尽了适应的可能性,那么我们可以放下一些镜头。

我们还需要更改视频的分辨率。如果我们以一种分辨率对整个比特率范围进行100次编码,结果将很糟糕。例如,如果您以300 kbps的相同比特率对FullHD视频和480p进行编码,那么高级FullHD看起来会更糟。高分辨率,编解码器很硬,图像崩溃了:它不是在图像本身编码上花一些钱,而是对开销片段进行编码。因此,分辨率应与比特率匹配。

具有适应性的通用编码方案如下:



我们有一些可以即时更改比特率的来源,并且有一个网络。所有数据都进入网络,以某种形式,我们从网络获得反馈,并了解是否可以增加或减少发送的数据量。

对于流媒体,MediaCodec或VideoToolbox充当源(取决于平台)。在播放过程中,一切都由服务器转码器完成。

在网络上-我们已经讨论过并且将会谈论更多的各种网络协议。

折衷三角


当我们开始研究流媒体时,我们会遇到一些妥协。特别是,在拐角处有一个三角形,其中可靠性是可靠性(无丢包),吞吐量是带宽(我们使用多少网络),低延迟是低延迟(我们得到低延迟)。



如果我们开始优化这些参数之一,其余的将不可避免地失败。我们不能一次获得所有东西,我们必须牺牲一些东西。

通讯协定


我们今天将看到的协议:RTMP和WebRTC是标准协议,OKMP是我们的自定义协议。

值得一提的是,RTMP运行在TCP之上,另外两个运行在UDP之上。

RTMP


他给什么? 在某种程度上,这是所有服务(YouTube,Twitch,Flash,OK)都支持的标准。 他们使用它,以便用户可以上传实时流。 如果要将实时流传输到某些第三方服务,则很可能必须使用RTMP。

我们设法从磁带机到播放器的最小延迟是300毫秒,但这是在天气晴朗时的理想网络。 当我们有一个真实的网络时,延迟通常会增加到2-3秒,如果网络的所有情况都不好,则延迟可能会增加到数十秒。

RTMP支持动态更改分辨率和比特率(提到的其他协议是相同的,但是关于RTMP的错误信息是动态没有更改)。

缺点:建立在TCP上(我们将在后面解释为什么这很糟糕),延迟不受控制。

如果看三角形,RTMP将无法提供低延迟。 可以获取,但不能完全保证。

此外,RTMP有点废话:它不支持新的编解码器,因为Adobe不这样做,并且文档非常古老且歪曲。



为什么TCP不适合直播? TCP提供了传递保证:您放入套接字中的数据将完全按照其放置顺序和形式进行传递。 不会丢弃或重新排列任何内容。 TCP将要么这样做,要么死亡。 但这意味着排除了延迟保证-他将无法丢弃可能已经不需要发送的旧数据。 缓冲区,积压等开始增加。



例如,生产线主管阻塞问题。 它不仅可以在流媒体中找到,还可以在许多其他情况下找到。

这是什么 我们最初有一个空的接收器缓冲区。 我们从某个地方接收数据:大量数据和大量IP数据包。 我们收到了第一个IP数据包,然后在接收器上使用recv()方法可以减去该数据包,获取数据,丢失数据,然后进行渲染。 但是随后突然第二个数据包丢失了。 接下来会发生什么?

要恢复丢失的IP数据包,TCP必须重新传输。 为此,您需要花费RTT,同时重传也可能会丢失,我们将分周期进行。 如果有很多软件包,这肯定会发生。

在此之后,由于我们正在等待第二个程序包,因此无法读取很多数据。 尽管他展示了五分钟前发生的广播帧,不再需要。

为了理解另一个问题,让我们看一下RTMP的适应性。 我们在发送方进行适配。 如果网络无法以将其放入套接字的速度塞入数据,则缓冲区将被填充,并且套接字会显示EWOULDBLOCK,或者如果此时使用阻塞,则阻塞。



仅在此刻,我们才知道我们有问题,我们需要降低质量。

假设我们有一个特定速度为4 Mbps的网络。 我们选择了250 KB的套接字大小(对应于我们的速度为0.5秒)。 突然,网络出现了10次故障-这是正常情况。 我们有400 kbps。 缓冲区很快就充满了半秒钟,只有到那时,我们才知道需要关闭电源。



但是现在的问题是,我们有一个250 KB的缓冲区,将传输5秒钟。 我们已经完全落后了:我们需要先推送旧数据,然后才可以适应最新的新数据。

怎么办 在这里,我们的“妥协三角”才有意义。



  • 我们可以减少发送方缓冲区,而不是0.5秒-0.1秒。 但是我们正在失去带宽,因为我们经常会“慌张”并关闭。 而且,TCP的工作方式是,如果您将发送方缓冲区设置为小于RTT,则无法使用通道的全部带宽,它将减少数倍。
  • 我们可以增加接收缓冲区。 有了大缓冲区,数据就会到达,我们可以消除缓冲区中的一些不规则性。 但是,当然,由于我们立即设置了一个5秒的缓冲区,因此丢失了低延迟。
  • 我们可以主动删除旧数据。 在TCP中,唯一的选择是断开连接并重新创建它。 我们失去了可靠性,因为此时玩家没有任何可显示的东西。


WebRTC


这是一个C ++库,已经考虑了经验并在UDP之上运行。 在iOS,Android下构建,内置在浏览器中,支持HTML5。 由于它被囚禁在P2P呼叫中,因此延迟为0.1-1秒。



缺点:这是一个单片库,具有大量无法删除的遗产。 此外,由于专注于P2P呼叫,因此优先考虑低延迟。 似乎我们想要这个,但是为此,她牺牲了其他参数。 而且没有设置可以更改优先级。

还应该记住,该库是面向客户端的,用于两个没有服务器的客户端之间的对话。 必须在服务器上搜索第三方或编写您自己的服务器。

选择什么-RTMP或WebRTC? 我们实现了这两种协议,并在不同的场景中对其进行了测试。 从图中可以看出,WebRTC具有较低的延迟,但吞吐量较低,而RTMP具有相反的延迟。 在它们之间是一个洞。

我们希望制定一个可以完全掩盖此漏洞并且可以在WebRTC和RTMP模式下工作的协议。 他们制作并命名为OKMP。


Okmp


这是UDP的灵活协议。

支持多路复用。 这是什么意思:会话中有多个通道(在OK Live的情况下-经理,音频和视频)。 在每个通道内,保证按一定顺序传送数据(但不能保证它们本身可以传送),并且不保证通道之间的顺序,因为这并不重要。

它有什么作用? 首先,它使我们有机会优先考虑渠道。 可以说控制通道的优先级高,声音中等,视频低。 视频抖动和不均匀的视频传递更易于掩盖,与视频问题相比,与音频令人讨厌的卡顿相比,用户遇到的问题更少。



另外,我们的协议具有可选的交付保证。 我们可以说,在某个通道上,我们以TCP模式工作,保证了传递,而在其余通道上,我们允许一些丢弃。

因此,也可以保证延迟:TCP通道上没有延迟保证,但是在允许丢弃的其他信道上,设置了阈值,此后数据开始丢弃,我们停止传送旧数据。

例如,对于音频,这是1秒,对于视频,是0.5秒。 阈值为何不同? 这是另一种优先排序机制。 由于对我们而言,音频的流畅性更为重要,因此我们首先开始放下视频。

我们的协议可以灵活配置:没有单一的操作模式,我们可以随时更改设置以切换到所需的模式,而不会给用户带来明显的影响。 怎么了 例如,对于相同的视频通话:如果视频通话在流中开始,我们将其悄悄地转移到低延迟模式。 然后返回到吞吐量模式以获得最高质量。
实施困难



当然,如果您决定用UDP编写协议,则会遇到一些问题。 使用TCP,我们可以获得自己必须在UDP上编写的机制:

  • 打包/拆包。 您需要将数据切成大小约为1.5 KB的数据包,以使其适合MTU网络。
  • 重新排序。 您以一种顺序发送数据包,然后将它们重新排列,然后以另一种顺序进来。 为了解决这个问题,您需要使用包裹号设置序列,然后在接收器上重新排列它们。
  • 损失。 当然会有损失。 当发生丢失时,接收方必须分别告诉发送方“我收到了这些数据包,但没有收到”,并且发送方必须重新传输丢失的数据包。 或放下它们。
  • 流量控制 如果接收器没有接收到数据,或者跟不上我们推数据的速度,则数据可能开始丢失,我们必须处理这种情况。 对于TCP,发送套接字将被阻止,而对于UDP,则不会被阻止,您必须了解接收者未接收到数据,并减少发送的数据量。
  • 拥塞控制。 类似的事情,只是在这种情况下网络死亡。 如果我们将数据包发送到已故网络,则不仅将破坏我们的连接,还将破坏邻近的连接。
  • 加密方式 需要注意加密
  • ...还有更多


OKMP与RTMP


当开始使用OKMP代替RTMP时,我们得到了什么?

  • OKLive比特率的平均增加是30%。
  • 抖动(不均匀的数据包到达量度)-0%(平均相同)。
  • 抖动音频--25%
  • 抖动视频-40%


音频和视频的变化-演示我们协议中的优先级。 音频是我们的重中之重,由于视频,它开始变得更加流畅。

如何选择流协议





如果您需要低延迟-WebRTC。

如果要使用外部服务,在第三方服务上发布视频,则必须使用RTMP。

如果要为脚本量身定制协议,请实施自己的协议。

Source: https://habr.com/ru/post/zh-CN467669/


All Articles