音视频系列1:流媒体

1. 流媒体技术

1.1 基本需求

流媒体技术需要:
1.允许客户端在不下载完整文件的时候即可以开始播放视频;
2.允许客户端从完整内容的任何位置开始播放(不包括视频直播);
3.针对视频直播,允许客户端从任意时间开始观看频道内容;
4.允许在客户的带宽条件和客户端的硬件条件下播放;
5.提供相对平稳的传输速度,以便用户基本流畅地完成播放。
此外,流媒体还需要以下衍生技术:
1.支持CDN传输,以提供服务扩展能力和较好的用户访问质量。
2.支持视频内容的加密,避免版权内容被人依靠复制传播牟利。鉴权通常包括两个方面:一者服务方对用户进行鉴权,防止非法用户占用甚至偷窃资源;二来用户也需对服务方进行鉴权,防止非法冒充。因流媒体的核心价值在于其传输的内容,完成对一个用户的服务可能持续几小时之久,其间客户端于网络上发起成千上万次数据请求,主要需要保证所有内容都可以发送到不被篡改的用户设备上,与许多其他网络服务类似,对控制协议加密,基于Token有效期的方式保持连接,由用户账户权限加密地获取Token是常见的做法。近年来,由于对用户隐私和内容保护的日益注重,于全栈上使用Https,对所有音视频内容进行DRM加密保护已成为大厂的惯例。除屏幕录制方式无法有效遏制外,其余的盗版方式都得到了较大遏制。防盗链,无论何种流媒体协议,都可以由服务器发布其访问链接供用户连接,如果未进行用户鉴权及内容加密保护,则可能遇到一些用户将其链接再发布,非法传播、篡改,以此牟利,为防止此点,可由服务器通过对引用来源检查、签名URL、Session验证等方式规避。
3. NAT是Network Address Translation的缩写,由于IPv4的地址短缺,常见的家用路由器通过地址转换,可以让家庭内的多个用户设备通过有限的IP地址访问互联网,并隐藏上网设备的真实IP,提高安全性,但劣势是有些协议无法直接通过NAT工作。此处NAT可以分为锥型和对称型,主要区别在于一个请求还是多个请求对应一个端口,流媒体数据将如何发到对方居于NAT设备之后的内网客户端上,又如何令网关允许这样做,是主要需解决的问题。

1.2 性能技术

(1)异步通信
异步模式的网络编程,或更准确地说,基于多路复用模式的异步网络编程,是提升服务器性能的重要原理之一,早先的Apache服务器虽然简单易用,但当同时连接的用户达到千级或更多时就不堪重负。故而在不同操作系统上普遍发展出了高性能多路复用的技术,如BSD上的Kqueue,Windows上的完成端口,Linux上的Epoll,Solaris上的/dev/poll等。
之所以称作高性能技术,以Linux系统为例,同为多路复用,Epoll较之于早期的Select/Poll系统调用,其改进主要是在内核态由红黑树维护待监控链接,而以链表方式维护所有活跃链接并返还用户,在用户态的调用算法复杂度则为O(1),其原理示意如下图所示:
在这里插入图片描述

故而不至于如中Poll和Select调用一样复杂度随着链接增多而剧增(流入live555虽然好用,但是是基于select/poll调用的)。

(2)上下文切换
同样对服务器性能影响极大的,是线程或进程的频繁切换,对一个H.264的NAL进行打包,或者一次不需要陷入内核的glibc调用,可能只需要几个CPU tick,但线程或进程交出运行权,换出内存、保存线程栈等操作则可能耗费高达数百甚至上千tick的时间,因此设计适合当前多核CPU架构的进程、线程模型十分重要。
可以考虑遵循的原则:首先,我们希望进程或线程在某个CPU核心上尽可能连续运行,服务器应根据不同的操作系统选取进程或线程作为基本运行单位,开启适合的进程、线程数量,如与CPU核数相同。其次,对所有的处理操作都按照事件驱动的模型进行编写,避免任何阻塞的硬盘读写以及网络读写操作,以令一个进程或线程可以持续地处理成百甚至上千个链接。在此模型下,针对一个网络链接的处理,原则上只由一个进程或线程完成,避免数据的传递以及不同进程或线程间的相互依赖。此外,服务器还可以将进程或线程绑定CPU的某个核,以避免竞争状态。
(3)内存管理
为追求高性能,现代的服务器往往不依赖于操作系统,而是自己管理内存,由于流媒体服务器需要处理的数据量远较一般的通用HTTP服务器为大,对内存进行自己的管理就显得更有效果。其主要的思路是:首先,从操作系统预先分配大块的内存页,按照较有效率的分块方式统一管理。其次,针对每次内存分配尽可能在本线程所据有的内存中完成,避免需要加锁保护的情况,使用结束的内存并不返还操作系统而是优先用于下次分配,对于常用的内存块大小,提前进行预测分配。自行管理内存的另一个好处是减少页表的大小并改善缓存命中情况。
(4)锁机制
系统中如果使用任何锁机制,不论是操作系统提供,等待满足条件后唤醒的内核态锁,还是在“忙等”的用户态锁,都是对运行效率的一种降低。根据进程、线程模式的设计,绝大部分情况下,各个进程或线程都应该独自处理用户请求,在同一上下文内并无加锁的必要,但仍然有一些关于数据交换或共享的需求,必须加锁来完成,这时就需要详细考量。
1.需要读写全局配置项,此时可考虑类似Windows注册表一样的做法,对每一个注册表项都使用一个独立的Spinlock,互不干扰,降低访问冲突。
2.需要在不同进程或线程间传递数据,如Socket,改变数据的持有者,可以依据进程、线程以及数据类型建立不同的访问队列,然后针对不同队列的访问加不同的锁,目的同样是为了降低访问冲突。
3.不同进程、线程的访问请求指向同一份音视频内容,可以针对每份内容在不同进程、线程中复制相同的对象,对对象本身的访问加锁,以及对该对象管理下的所有Packet分别加锁(引用计数)。
(5)零拷贝
鉴于流媒体服务对I/O的高要求,另一项需要认真对待的原则是尽量实现零内存拷贝,一次常见的读写操作常常会触发四次内存拷贝。内存拷贝的高带宽、高速度针对其他服务或许并非掣肘,但对流媒体服务而言,单台服务器的吞吐量常常可高达Gbit/s级别,高者达到数十Gbit/s,内存拷贝的代价并非可以忽略。以Linux为例,系统提供了几种不同的处理I/O的方法。
1.Direct I/O,允许用户的应用程序直接访问硬件,但缺少内存页的缓存。
2.mmap(),用户态和内核态共享地址空间,在内核中仅在写时有一次内存拷贝。
3.sendfile(),类似于mmap,主要避免了从内核中向Socket缓冲区的拷贝。
4.splice(),允许数据在内核中从源文件描述符拷贝到目标描述符。
5.fbufs,可以允许在应用和内核间分配共享的fbufs。
在这里插入图片描述

1.3 部署模式

两种常见的服务方式:CDN和P2P
CDN是Content Distribution Network的缩写,是利用多个分别部署的数据中心、机房、服务器,在网站和用户之间插入一层网络架构,选取最靠近或服务质量最佳的服务器为每位用户提供服务。CDN可以有效地解决网站容量不足、互联网拥塞、降低主干网流量占用、提高用户响应速度和下载速度等问题,是现代互联网服务中必不可少的环节
在这里插入图片描述
构建一个商用的CDN,需要基于DNS重定向、源站与边缘站(Origin Server与Edge Server)、缓存和负载均衡等关键技术,现代CDN对虚拟化、P2P、定制服务器、SDN等技术亦有很高要求。CDN的基本原理在于,根据用户的来源将其访问请求重新指向选取出来的缓存服务器,用户不需要访问网站服务器即可得到所需的内容,所有静态的视频、图片文件、毋需常常变化的网页等都适合被缓存。一项绝大多数CDN公司均可实现(已实现)的功能是多源站功能,源站和边缘站仅是开发者对服务器角色的定义,因此如果一台边缘服务器具备扮演源站角色的能力,则在实时传输的场景下将大幅拓展CDN的功能,提供更好的用户体验。在视频直播中,低延迟效果很大程度上仰赖于接收节目源的节点是否可以本地化,游戏或秀场类直播就更视之为必要条件。因为直播一对多的观看模式,大部分采取推流的方式,即将直播流推送到源站,经过转码和后处理工作后,由CDN的内部调度系统将其推送到次级源站甚至边缘站。RTMP的协议是常用的推流协议,HLS或DASH协议的直播流可以通过WebDAV协议或其他方式推送,亦有许多选择RTP等实时流协议进行推送的实践。举例来说,假设CDN源站在纽约,直播内容来自于洛杉矶而观众在波特兰,传统的推流方式将令视频流先推送到纽约才能被观众收看到,而多源站支持意味着直播内容可以被推送到最近的源站(假设在旧金山)从而服务给观众,在延时上有明显的优势。
一个可行的CDN架构需要包含GSLB(Global Server Load Balancing,即全局负载均衡)、应用发布、源站和边缘站的节点管理、各个节点的缓存管理、监控和日志分析、客户管理和计费等组件。

P2P(Peer-to-Peer)即点对点服务,常见的互联网服务更多采用“客户端-服务器”架构,所有的内容均由单一服务器发送给客户端,而P2P技术则允许没有中心服务器,用户设备既作为客户端接收和消费内容,也作为服务端,将收到的内容服务发给其他客户端。因为大量客户设备均可提供带宽、存储和计算资源,可以大规模节约运营成本,在许多情况下也可以提升服务质量。
P2P技术因为去中心化、责任不明确或不易监管等原因,使用其进行共享的多是流行音乐或电影、电视剧等版权内容,因此媒体公司常常将P2P与盗版等同起来,但技术本质上是无罪的,包括在线视频服务公司在内许多人都仍在尝试利用它的优点,例如使用P2P节点作为CDN的补充,或在直播中实时对毗邻的客户划分,控制其组成小型的P2P网络,以节约昂贵的带宽。
常见的P2P网络的文件分享协议有Bittorrent、eD2k、FastTrack、Gnutella等以及大量的私有协议,绝大多数协议基于TCP协议之上。以Bittorrent协议为例,发布者需要根据文件内容提供一个.torrent文件(称为种子),其中包含Tracker(追踪者)信息(即Tracker服务器的地址和相应设置),以及文件信息(即根据目标文件计算生成的虚拟分块,也即被分享文件的索引)。下载时,客户端解析种子文件得到Tracker地址,连接Tracker服务器以得到提供下载的各节点IP,此后不再需要服务器参与,不同节点将告知对方已有的块并交换数据。

1.4 播放技术

DRM(Digital Rights Management,数字版权保护)是用于保护视频内容的一系列访问控制技术集合,用于控制视频和设备的使用过程,包括对视频的使用、播放、拷贝、修改等。它可以进行多种不同层次和功能的限制,例如必须在指定电脑或播放器上播放、必须在特定日期前播放、限制播放次数、限制拷贝或限制拷贝次数等。如果说视频内容是钱,在线视频公司是银行,那么DRM就是银行雇佣的保镖,保护视频不受外界窃取。令DRM技术成为现实的基础是加密技术,原理在于将明文信息改换为难以读取的密文信息,只有具备解密方法的对象经由特定过程,才能将密文还原为正常可读的内容。加密算法分为对称加密和非对称加密两类,对称加密将信息使用一个密钥进行加密,解密时只需使用同样的密钥,按同样的算法进行解密,非对称加密算法则在加密和解密环节使用不同的密钥。常见的对称加密算法有DES、AES、IDEA等,非对称加密算法有RSA、ElGamal、ECC等。
10Bit视频:传统上图像的存储多使用24Bit或32Bit的颜色深度,这样在R、G、B色彩通道上均由8Bit表示,意味着每种原色仅有0~255对应的灰度级别,而引入每通道10Bit的图像表达将提供1024个级别,色彩精度是8Bit的4倍,三个通道合计可以提供10.7亿不同的颜色。多数较新的视频标准都加入了对10Bit的支持,例如H.264中加入了名为Hi10P的Profile以支持10Bit,而编码器(如x264)也于近年加入相应代码,从更高质量的源转码为10Bit的视频可能比8Bit效果更佳。
HDR即High Dynamic Range(高动态范围)的缩写,该技术在拍照领域已广为流行,用以实现比普通数字图片(视频)更大曝光动态范围,也即更大的明暗差别,借以表现真实世界中从阳光直射到暗室微光的完整亮度范围。由于传感器所限,图像或视频拍摄时或许无法完全保留光照的细节,但借助技术手段,可以从多种不同曝光设置的照片中组合出HDR图像,当前许多手机的拍照即遵循如下原理。
在这里插入图片描述

1.5 数据库技术

当前,大数据处理架构通常分为以下层次,后续将择要介绍。
1.文件系统,如GFS、HDFS以及Ceph、MooseFS等分布式文件存储系统。
2.键值存储,如Dynamo、Cassandra。
3.列存储,如BigTable、HBase。
4.图存储,如Neo4j、Titan、GraphSQL。
5.文档存储,如MongoDB。
6.事务存储,如Spanner、Megastore、MESA、CockroachDB。
7.资源管理,如YARN和Mesos。
8.资源协调,如Zookeeper、Chubby、Etcd、Paxos等。
9.计算引擎,如Spark、Flink。
10.批处理框架,如MapReduce。
11.流式计算框架,如Storm、Spark Streaming。
12.分析工具,如Pig、Hive、Phoenix。
13.实时计算框架,如Druid、Pinot。
14.交互式计算框架,如Drill、Implala、Presto、Dremel。
15.分析类库,如MLlib、SparkR、Mahout。
16.ETL工具,如Crunch、Cascading、Oozie。
17.元数据,如HCatalog。
18.序列化,如Protocol Buffers、Avro。
19.数据导入,如Flume、Sqoop、Kafka。
20.监控管理,如OpenTSDB、Amdari。
在一些场景中,当需要描述大量实体间的关系时,不论传统的关系型数据库,还是BigTable或Dynamo类型的列存储与Key-Value存储,均不能很好胜任,以Neo4j为代表的图数据库则为此目的而生。
Neo4j数据库由Lable和连接节点的关系构成,如果希望在两个Lable间建立双向联系,则需要为每个方向定义一个关系。与其他数据库集群不同的是,Neo4j与其他集群的横向扩展能力相较更为受限,所有节点均拥有全量数据,而Master节点负责写入,所有节点均可负责读取,可见Neo4j擅长应对的将是多读少写的场景,当Master节点失效时,新的Master将由选举产生。Neo4j的节点数量大致只支持到亿级别,当需要数十亿乃至百亿以上节点时,可能需要考虑Titan(及其分离出的JanusGraph)、商用的GraphSQL等方案。
MongoDB是一个十分流行、基于文档的数据库,由10gen团队推出,大致介于关系数据库和非关系型数据库之间,其结构非常松散,采用类似JSON的BSON格式,可以存储复杂的数据类型,并可支持对任意字段进行索引。MongoDB的读性能非常出色,并有完善的集群支持,但并不适合需要高事务性的系统或传统的BI应用。
Spanner是Google最新一代高可用、多版本支持、全球分布式的同步备份数据库、可以支持数百个数据中心,扩展到百万级机器和万亿级数据,支持自动地在机器之间自动共享和迁移数据,用于负载均衡和失败恢复,其最大的亮点是基于GPS和原子钟实现的时间API。
提供相近功能,可供开发者参考的选择包括Spanner的开源实现CockroachDB,Spanner的“前任”Megastore,以及同样来自Google的新型数据仓库系统Mesa等。其中Megastore是一个基于BigTable的跨机房高可用数据库,实现了EntityGroup内部及之间的事务性和跨DC的多备份一致性,Mesa则能够支持原子更新、一致性和正确性、可用性、近实时的更新吞吐率、查询性能、在线的数据转换。
Mesos是一个开源分布式资源管理框架,它从设备抽取CPU、内存、存储和其他计算资源,向应用程序提供资源。Mesos通过ZooKeeper实现容错,支持容器,并可通过Marathon或Chronos等上层组件支持服务和任务的调度管理。
Zookeeper与Google的分布式锁服务Chubby相似,为大型的分布式系统提供服务协调,包括同步、配置和命名等。由于大多数分布式系统均无法放弃分区容错性,只会在一致性和可用性之间权衡,而Zookeeper的性质是CP的,即保证所有的请求均能得到一致结果,但不保证所有请求均能成功。与Zookeeper功能相近的还有Etcd等。
Hadoop/YARN,Hadoop支持在集群上运行应用程序,每个Job通过JobClient类将应用打包成JAR包并提交给JobTracker,JobTracker负责创建每个Task并分发给各个TaskTracker服务中执行,TaskTracker在每个节点上运行负责,负责执行Task。YARN是Hadoop的升级版本,它将JobTracker的资源管理功能和作业调度功能分离,资源管理器(即YARN)负责所有应用程序资源的分配,每个应用的ApplicationMaster负责相应的调度和协调,此时的应用程序既可以是传统的MapReduce任务,也可以是一个DAG任务。
Spark是一个大数据处理框架,与Hadoop不同,它的中间输出结果可以保存于内存中,具备更好的性能,但它大多数情况下仍旧基于Hadoop文件系统(即HDFS)。Spark支持MapReduce模式,而并不仅仅是MapReduce框架,它还支持各种各样的运算、迭代模型等。Spark的基本概念是DataFrame(包含列名称的数据集合,在早期版本中常用的是数据结构无关的RDD),支持比map和reduce远为丰富的计算原语,按照DAG的方式组织,并提供大量的库,如SQL、MLlib、SparkStreaming、Shark等。
Flink是一个针对流数据和批处理数据的分布式处理引擎,确切地讲,它会将所有数据按照流的模型处理,与Spark Streaming的Micro-batch方式不同,Flink在数据到来时就对其进行实时(近似)处理,这点与Storm更为相似,但基于轻量级快照实现的容错机制有更好的性能。
Pig是Hadoop生态中的数据集分析工具,需要程序员以Pig Latin语言编写脚本,并由Pig Engine转换为MapReduce任务执行。
Hive是Facebook打造的数据仓库工具,同样基于Hadoop,在相似的层级上提供了解决方案,它通过HDFS存储,通过Map Reduce执行,使用HQL(一种类SQL语言)作为查询接口。
Hive的工作方式大致如下:查询将通过名为Driver的组件到Compiler,通过Metastore获取元数据并生成查询计划,再由执行引擎下方给Hadoop集群,适用于离线的批量数据计算。Hive中的表是纯逻辑表,即只有表的定义(元数据),在大数据架构中,Hive常用于清洗、处理和计算原始数据,并将结果存储于HBase,也可用于历史数据的挖掘和分析。
Druid是一个用于大数据实时查询和分析的高性能分布式系统,其主要卖点在于实时,即允许事件在创建后毫秒内被查询到,并提供以交互方式访问数据的能力,非常适合聚合分析。它实现了Dremel的几乎所有功能,同时还支持为快速过滤设计的索引、实时导入和查询等功能。Druid集群由Historical、Broker、Realtime、Coordinator、Index等节点组成,同时依赖ZooKeeper、HDFS和MySQL作为外部组件,组件之间的关系和工作流程示意可以参考图7-21。
Pinot由LinkedIn开源,同样为实时查询和分析设计,适用于给定数据集(Append Only)上进行低延时的数据分析使用。与Druid相似,Pinot对数据进行历史和实时的划分,历史数据存储在HDFS上,依据时间分段索引,而实时数据从Kafka中消费,查询结果将自动合并。还有一个被广泛使用,基于HBase添加二级索引和SQL支持的工具称为Phoenix,同样适用于实时分析需求,适于在海量数据集上建立索引查询少量数据。
Drill是一个对大数据进行实时分布式查询的引擎,可以被视作另一个开源版本的Dremel,它按照无主节点的方式设计分布式架构,每个节点都包含基于RPC协议的客户端接口、用于解析SQL语句的SQL Parser,以及支持多种数据源如HDFS、HBase、Hive和文件的统一读写接口Storage Engine Interface。
Impala和Presto同样侧重于提供SQL支持,其中Impala由Cloudera开发,设计为直接从HDFS或HBase中用SELECT、JOIN和统计函数查询数据而非通过MapReduce,与Hive相比,Impala偏重于交互式查询,而Hive更适于长时间段的批处理查询。Presto是Facebook开发的查询工具,同样支持交互式的SQL查询,其计算完全基于内存,直接针对HDFS,也支持Hive或其他类型数据库作为数据源。
在Hadoop生态体系中,还存在许多可以帮助定制化开发的类库和框架。例如Crunch就是一个基于Java实现的,基于MapReduce的数据管道库,用于简化MapReduce任务的编写和执行,以及简化连接和数据聚合任务的API。又如Cascading是一个架构在Hadoop上,用来创建复杂和容错数据处理管道的API,如Count、Group By、Join等,依赖于Hadoop提供存储和执行框架。
Oozie则是一个构建在Hadoop上的工作流调度管理系统,用户可将多个MapReduce任务提交给Oozie服务器并由其管理起来,常见与之竞争的调度管理器是以简单清晰著称的Azkaban以及Airflow。
HCatalog同样是Apache大数据生态体系的一部分,它是一个对表和底层数据管理统一服务的平台,因为所有数据均保存在Hive的Metastore中,故而需要Hive支持。由于用户往往在Hadoop上使用多种工具查询和分析,通过共享Metastore可以打通不同工具之间的访问,同时,注册数据本身即是发挥数据价值的必然步骤。
为Hadoop集群运行维护方便,还有一些相关项目可以帮助监控和管理,例如OpenTSDB是一个基于HBase的时间序列存储,适用于从大规模集群中获取相应信息并存储,常用于监控系统的实现。Amdari则是Apache的另一个顶级项目,用于帮助创建、管理、监视Hadoop集群(包括整个Hadoop生态的各种组件,如Hive、HBase、Zookeeper等)。

2. 流媒体协议

在早期的互联网上,为了节约昂贵的带宽成本,有很多基于组播技术的传播尝试,但组播的弱点在于,互联网的网络环境太过复杂,组播树上的任意环节出现问题都会导致所有下游观看者无法获取,很难建立稳定的观看体验,因此更多应用于可控的网络环境包括一些有线电视领域。
流媒体技术通常首先以协议的形式展现,对于音视频编码好的文件,经过提取和再封装,被放在协议规定的包格式中,逐次发送到支持该协议的客户端进行播放,在后续章节我们将逐一介绍MPEG-TS、RTSP、RTMP、HLS、Smooth Streaming、HDS、MPEG-DASH等协议。此外,曾经广泛运用的流媒体协议还包括微软的MMS和MS-WMSP(也被部分人称作WMT,Windows Media Technology)等。除了流媒体服务器和播放器构成的两极,流媒体协议也应用于上传实时或预先拍摄的节目到服务端,或者多人视频会议等不同情形。

2.1 MPEG-TS协议

MPEG2-TS又称Transport Stream或TS,是ISO/IEC标准13818-1或ITU-T Rec.H.222.0中规定的标准的音视频传输协议,因传输的Packet可不经转换地存到文件中,又可被视为文件格式。前面的章节中曾作简单介绍,MPEG2-TS广泛应用于广播电视领域,也被苹果的HLS协议(后续章节会予介绍)采用为其视频文件格式,其设计初衷即是视频流可以从任意片段开始解码。
TS流可视为由一系列188字节的包组成(在一些扩展中可能有不同长度)的“列车”,包头固定为4字节,以0x47作为同步码起始,其中的关键信息是PID。
TS码流的基础是ES流即Elementary Stream,包含视频、音频或数据的连续码流,在此基础上,拆分成不同大小的数据包并加上包头,就形成了PES流。TS流由对一个或多个PES码流进行再封装得到,也即一个TS流可以包含多个PES流,一个音频PES包需要小于或等于64KB,视频PES包即是视频的一帧,由于TS包的负载大小仅为184字节,一个PES包需要被分成多个TS包进行传输,如有空余负载,则以固定值填充。
在这里插入图片描述
TS流内必不可少的还有PSI信息(Program Specific Information),其中包含如下分类。
·PAT(Program Association Table,节目关联表)。
·PMT(Program Map Tables,节目映射表)。
·CAT(Conditional Access Tables,条件访问表)。
·NIT(Network Information Table,网络信息表)。
·TSDT(Transport Stream Description Table,传输流描述表)。
当客户端获取PAT和PMT包之后,即可了解TS流中包含哪些内容。
在这里插入图片描述
由TS流的结构可知,其设计目标之一是在同一个流中包含多个节目,既可以是不同的频道内容,也可以是同一频道的不同码率,由客户端根据不同的PID取舍。一个频道的内容,通常可以由一个或多个视频流、一个或多个音频流以及字幕或其他信息流组成。
在实践中,除获取到直接的TS流以外,若所获取直播节目的输入是非压缩的数字信号,还可以通过ASI、SDI接口的设备将其编码为基于IP的节目流。
在这里插入图片描述

2.2 RTSP协议

RTSP(Real Time Streaming Protocol)是早期常用的流媒体协议,它用来建立客户端与服务器之间的会话,客户端发布播放暂停等命令,协议由RealNetworks、Netscape和哥伦比亚大学合作开发,并由IETF标准化(即RFC2326,此外尚有RFC7826发布的RTSP2.0协议)。
4.3.1 RTSP协议
RTSP通常与RTP和RTCP协议共同使用,其中RTSP是服务端与客户端间的双向协议,它不负责传输音视频数据,而是用来控制多个音视频流。RTSP是一个基于ISO10646字符集的文本协议,基于TCP建立会话,与HTTP1.1很类似,例如404代表错误码“Not Found”,200代表“OK”。
在这里插入图片描述
RTSP通过不同的命令构建完整的控制会话,同时依赖RTP和RTCP或其他协议(例如在广播电视领域,有些方案采用TS作音视频传输)传输音视频本身的数据,一次典型的播放过程将在客户端和服务器间建立5个不同的Session:一路RTSP的Session、两路RTP的Session(音频和视频各一)以及两路RTCP Session(分别对应两路RTP Session),占用5个不同的端口(RTSP协议的默认端口是554,RTP及RTCP的端口由SETUP命令指定)。
RTSP协议支持重定向,即将播放会话重定向,让其他服务器提供服务。协议也可选择不同的传输通道,例如基于TCP、UDP以及组播UDP传输RTP协议,下图画出了RTSP和RTP、RTCP等在网络协议中所在的层级。除流媒体播放以外,RTSP的可扩展性、对SMPTE的帧级支持令其也适用于视频会议等场合。
在这里插入图片描述

扫描二维码关注公众号,回复: 11539220 查看本文章

RTP是Real-time Transport Protocol的简称,定义于RFC1889标准中,RTP协议将不同编码和封装格式的音视频数据进行再封装,加上RTP头形成RTP包,再行发送,RTP包头内的重要信息包括序列号、时间戳、负载格式等。RTP协议提供抖动补偿和数据无序到达的检测机制,对实时多媒体传输,及时送达是首要目标,为此可以忍受部分丢包,少量丢包可以在客户端通过某些方法进行掩盖,不损害或少损害用户体验。
RTCP即RTP Control Protocol,亦由RFC1889定义,协议本身并不发送数据,而是收集客户端的统计信息,包括传输字节数、传输分组数、丢失分组数、网络延迟、Jitter(抖动)等,服务器可籍此改变码率或调节数据发送速度。
另一项与RTSP配合使用的协议是SDP,由RFC 2327规定,即Session Description Protocol(会话描述协议),后重新发布为RFC 4566,用于和RTSP以及SIP等协议协同工作。SDP同样基于文本,前述RTSP协议中DESCRIBE命令的回复即是SDP格式,SDP的格式异常简单,由多个<类型>=<值>的字符串组成,用于描述会话信息,也用于描述音视频的类型和格式,所需要的带宽、时间范围甚至邮件地址、编码参数等。例如,当传输AAC音频时,假如编码参数保持不变,就可以通过SDP会话传输StreamMuxConfig(AudioSpecificConfig)信息,同时RTP流只需承载audioMuxElements

2.3 RTMP协议

RTMP(Real-Time Messaging Protocol,即实时消息传输协议)是Adobe公司的专有协议,最初由Macromedia开发,属于Flash的一部分,后被Adobe收购后进行了扩展,该协议虽然应用广泛,但都基于Adobe公开而不完整的规范,Adobe在其上尚有许多私有定义,除非通过逆向工程进行解析,否则无法兼容使用。Adobe公开的部分协议内容可见Adobe网站。
RTMP并非一个单独协议,而是由多个相关协议组成的协议族。
1.RTMP,默认使用TCP端口1935的明文协议。
2.RTMPS,即通过TLS/SSL连接传输的RTMP。
3.RTMPE,使用Adobe私有安全机制加密的RTMP。
4.RTMPT,使用HTTP封装的RTMP、RTMPS或RTMPE,利于穿透防火墙。
5.RTMPFP,使用UDP的RTMP,允许用户进行P2P连接。
(1)RTMP协议
RTMP是基于TCP的可靠传输层协议,仅需一个会话即可相互通信,与RTSP协议相比,如同由轨道支撑的高速铁路,虽然形式略重,但效率高、速度快。
协议的主要概念是将音视频及其他数据封装为RTMP Message发送,而在实际传输时会进一步将Message划分为带有Message ID的Chunk。每个Chunk可以携带一个Message,但更多情况下,一个Message将由多个Chunk承载,直到客户端接收后将其还原。Chunk Stream是基于RTMP Chunk的逻辑抽象,客户端将据此区分不同类型的数据并组织接收以及还原。
RTMP Chunk由包头和负载组成,对连接和控制命令,采用AMF格式编码(有AMF0和AMF3两种版本),包头包括Basic Header和Chunk Header,其中Basic Header可被扩展一到两个字节,Chunk Header则含有如Message长度等信息。
建立TCP连接后,RTMP协议会要求进行3个包的握手代表连接的建立,客户端发送一个代表协议版本号的0x03初始化连接,随后发送1536个字节(包括4个字节的时间戳消息、4个值为0的字节以及1528个随机生成的字节),服务器亦将发送0x03的版本消息、1536字节消息,客户端和服务器随后发送回声字节(本方及对方的时间戳对以及1528个随机字节),并在收到后确认连接的建立。
当握手完毕后,连接将被复用来发送一个或多个Chunk流,Chunk的默认大小为128字节,由客户端和服务器设置其可以接受的Chunk大小(可以动态调整),Chunk承载的Message类型不同,其Message Header亦有多种,不同的fmt取值将用以鉴别不同的Chunk类型。
RTMP协议支持Push和Pull两种模式,Pull即是普遍的客户端根据URL进行播放的方式,而Push基于RTMP的视频直播,其握手顺序和createStream步骤类似,由客户端使用Publish命令而非Play命令,发起自客户端到服务端的推送。
当开发基于RTMP的在线视频服务时,RTMPDump是一个常用的开源RTMP工具,它系由逆向工程得到,支持RTMP、RTMPT、RTMPE、RTMPS及变种协议RTMPTE、RTMPTS等,可以帮助模拟实验和工程测试,同时提供二进制库librtmp、简易的RTMP服务器及代理工具rtmpsrv和rtmpsuck,在FFMpeg、Gstreamer等多个项目中被集成使用。
除Adobe自家的Flash Media Server以外,尚有Red5、SRS等开源RTMP服务器,或在Nginx上基于RTMP插件搭建的流媒体服务器等方案供在线视频服务商选择使用,大部分商用流媒体服务器也支持RTMP协议。

2.4 HLS协议

HLS协议随苹果手机的推出而流行,不仅在苹果的手机、平板、Safari浏览器上成为首选的流媒体协议,许多视频网站也采用HLS及各种自定义的变种协议进行视频传输。协议的原理是将点播所需的多媒体文件或直播的视频流,切分成许多小块的文件,让客户端基于HTTP进行下载,当播放时,客户端需下载包含metadata信息的M3U8文件(也称作索引文件、Playlist或Manifest文件),根据M3U8文件的内容,同时依据网络条件选择不同码率的内容进行播放。
M3U8文件是文本文件,后缀名常为.m3u或.m3u8,早先为描述MP3音乐的目的设计,其中M3U8即Unicode版本的M3U,在被苹果选取描述HLS协议的索引文件后,逐渐成为M3U8文件最大的用途。
HLS支持如下音视频格式,首先是MPEG2-TS或fMP4(即Fragmented MP4)格式封装的切片文件(Segment)。其次,它支持打包的纯音频格式,包括以ADTS头封装的AAC帧、MP3、AC3和EAC3格式,对字幕,它只支持WebVTT格式。
·一个点播文件的M3U8示例如下:
在这里插入图片描述

在这个例子中,#EXTM3U、#EXT-X-TARGETDURATION等是M3U8文件规定的tag,其中包括原有的定义和由苹果扩展的tag,这个点播文件一共21s,分为3个TS的Segment。
·直播的M3U8示例如下。
在这里插入图片描述
此例中,协议希望客户端规律地访问服务器(例如7.975s访问一次)以观察是否有Segment持续被更新,而Segment的文件名也按顺序增加。
HLS协议的一大特点在于,将以往RTSP、RTMP等协议中实现复杂的多码率、多音轨的音视频流变得容易,并可以明晰地表达、理解和优化,在协议中规定需要传递给客户端的信息可以由Master和Alternative两种M3U8来表达。在此设计中,客户端承担起了码率控制和选择的主要职责,每个播放器可以根据自己的网速选择合适的码率播放,并在网络环境波动或某些文件下载失败的情况下切换到其他码率,保持流畅播放,服务端则对缓存和CDN友好,毋需针对不同用户予以不同处理。
下面是多码率的视频流的Master类型M3U8示例,描述了高、中、低三种码率的音视频流以及一路仅包含音频内容的Alternative M3U8的访问URL。
在这里插入图片描述
在这里插入图片描述

苹果公司推荐在使用HLS协议时,提供Alternative类型的M3U8示例与普通单码率M3U8文件相同,其中记叙了该码率的Segment文件访问地址。HLS协议支持在同一视频流中提供不同编码器的音频或视频流供客户端选择,于播放会话中,客户端根据自己的需求,切换码率进行下载播放。同一机制也可用于多语言的支持,对不同语言分提供不同的音轨。为支持多码率、多语言或不同Codec的切换,在节目制作时,应保证不同码率的流中,所有视频关键帧其时间戳完全对齐,否则客户端难以正确工作。
在这里插入图片描述

2.5 HDS,Smooth Streaming,MPEG-DASH

与HLS同一时期制定的,具备相似特性(基于HTTP、支持多码率、音视频文件切片)的流媒体协议另有Adobe推出的HDS(HTTP Dynamic Streaming)和微软推出的Smooth Streaming,它们与MPEG-DASH一道,被称作Adaptive Bitrate Streaming技术(码率自适应的流媒体技术)。HDS由Adobe自己的Flash Media Server支持,其文件格式为FLV、F4V和MP4,索引文件格式为F4M,支持直播和时移电视。
微软的Smooth Streaming是IIS服务器的多媒体服务扩展,支持PIFF格式(后文中将谈及)的MP4文件,后缀为ISMV和ISMA,索引文件为ISM或ISMC,同样支持直播和时移电视,
MPEG-DASH是由MPEG牵头开发的基于HTTP的自适应码率流媒体技术,于2011年11月形成国际标准,其标准文档为ISO/IEC 23009-1,发布自2012年4月,目标是统一不同公司的自适应码率技术。微软、高通、Google、Akamai等公司出力甚多,并获得YouTube、Hulu、Netflix等在线视频巨头的倾力支持,在短短几年间已经俨然取代RTMP,成为应用最广的流媒体协议。
苹果虽然坚持HLS协议,但由于互操作性的压力以及TS格式的固有弱点,也已于2016年开始支持fMP4格式,至少在音视频文件层面展示了与DASH协议达成兼容的意愿,在苹果设备上支持DASH协议的播放软件也已有许多应用。
在2015年,曾有人对不同自适应码率的流媒体协议所支持的功能进行比较,MPEG-DASH协议被认为考虑了流媒体涉及的各个方面,有很好的弹性满足多方需要,近年更扩展到VR、AR、P2P等方面的使用。
在这里插入图片描述
在这里插入图片描述
DASH协议原则上可以支持任何编码格式,作为指导意见,推荐使用与HLS协议兼容的TS文件或ISO-BMFF的扩展作为多媒体文件格式(即Fragmented MP4),后者的文件后缀多见.mp4、.m4v、.m4a或.m4s。DASH所使用的MP4文件扩展来自于微软于2009年发布的PIFF文件扩展,这意味着Smooth Streaming协议可以MPEG-DASH协议和在音视频文件层面相互兼容。
与标准的MP4文件相似,DASH使用的fMP4扩展可以被解析为一系列的Box(也被称为Atom),DASH协议将对于音视频流描述的部分(也即文件头上的信息)封装为init文件并于MPD文件中提供URL,任何时候客户端均可单独下载解析,这就避免了TS文件反复插入PSI信息的消耗,客户端下载init文件后,则可任意下载切片文件播放(反之,切片将因缺少解码信息无法播放)。针对音视频,还可提供不同的init文件,增加客户端的灵活度。
fMP4中有三个关键的Box,即MOOV、MOOF和MDAT,MOOV描述了文件层次的metadata信息,MDAT用于描述媒体数据,与普通MP4只有一个MDAT Box不同,fMP4的每个Fragment都有一个MDAT Box,MOOF存放了Fragment层次的metadata,每个Fragment都会有MOOF Box。
DASH中的MPD符合XML格式,协议定义了大量标签以帮助描述,其中以Period定义一段连续的音视频片段,每个Period内包含多各音视频内容的集合(主要应用于多分辨率、帧率、码率或者多语言,相互可以切换)称作AdaptationSet,每个AdaptationSet内含多个Representation,即一个独立的音频或视频流,每个Representation再由一系列的多媒体Segment组成。
DASH协议在播放期间并不能随意从Representation切换,需要等到初始帧为一个关键帧的视频Segment。若AdaptationSet中各个视频流编码时是以关键帧对齐的,则可以从不同的流间进行切换。
由于DASH协议内涵丰富,功能众多,较之前的协议略显复杂,在早期开发中,经常有各家对协议理解不同,实现不全,进而无法相互兼容的情形,DASH-IF为此提供了参考的播放器实现Dash.js,近年来,Google亦开源了Shaka播放器,便于开发者参考和测试。

3. 搭建服务器

当确定音视频格式和流媒体协议后,就轮到流媒体服务器粉墨登场,作为视频分发的主体,服务器应达到快速响应、高并发、高吞吐量和高可靠性。前面多次提到,视频文件的大小,促使人们研究编码技术和流媒体技术的关键,可以认为,整个视频技术,需要解决的核心问题是I/O问题。原因在于,普通的互联网网站服务,传输一个网页只需要占用几十或几百KB的流量,即使包含许多图片,不过是数MB的大小,然而即使小于400Kbit/s、十分模糊的网络视频,半小时的在线观看也将轻松用去近百兆字节。
在流媒体服务兴起的年代,它曾是高性能服务器设计的最大推手,对网页服务器而言,100名用户并不能让Apache有任何为难之处,但换作100名甚至1000、10000名视频用户,如不进行专门设计,将无法保证服务的质量。
流媒体服务器可将数据快速可靠地发送到客户端,客户端为避免后续准备数据尚未下载成功导致的播放等待,需要缓冲区具备一定的长度,但为防止开始播放时为填满缓冲区而等待时间太长,又需要将缓冲区大小控制到一定范围内,缓冲区管理是流媒体播放的关键之一,较好的实现通常对此有独到的处理。对不能按时下载数据的情况,客户端还需建立起良好的超时重试机制,在较新的流媒体实践中,码率自适应、CDN选择、多路下载等技术相互配合,帮助用户得到可靠和平稳、流畅的观看体验。
流媒体技术不仅涉及点播,在直播领域中对其连续稳定的要求更显重要,而大型活动(如体育赛事、演唱会、新闻采访、颁奖典礼、产品发布等)也需要其保证快速、及时、稳定的上传、编播与分发。
以高性能著称的服务器,不论是专用的流媒体服务器(如Helix Server),还是通用的HTTP服务器(如Nginx),其在当前的计算机体系架构下,采用的思路大体一致,例如采用异步的网络通信方式以避免连接增加对性能带来的线性损害,设计完全基于回调函数的进程或线程模型避免频繁的线程上下文切换,自我管理内存分配避免陷入内核的耗时,对锁机制的细致使用最大概率避免竞争状态等。
下面是总结的常用的搭建方式:

3.1 使用vlc,自带server

安装好vlc软件,然后用如下命令起流

Applications/VLC.app/Contents/MacOS/VLC -vvv  test.264 –sout ‘#rtp{sdp=rtsp://:5544/test}’;

vlc会自动创建server,还不错。不过vlc的开源GPL协议,不适合商用。

3.2. 使用ffmpeg,nginx做server

参考这里
mac貌似自带ffmpeg,没有的话就安装一个,然后

ffmpeg -re -i test.mp4 -vcodec copy -codec copy -f rtsp rtsp://ip地址/

3.3. 使用live555,自带server

参考本文
live555目录下有个mediaServer目录,其中包含Live555流媒体服务器的标准示例程序,运行live555MediaServer.exe后出现如下界面:
在这里插入图片描述
在mediaServer目录中放入你的媒体文件,如test.mp3,在VLC播放器中选择“媒体”-“打开网络串流”,然后输入 rtsp://127.0.0.1:8554/test.mp3 就可以播放刚才的mp3文件了。

proxyServer目录中是live555实现的代理服务器的例子程序,这个程序可以从其他的流媒体服务器(如支持RTSP的摄像机)取实时的视频流然后转发给多个RTSP客户端,这个程序很有用,可以转发摄像机的实时视频流。

3.4. 使用gstream,自带server

下载源码进行编译后:
1、切换到examples目录:cd examples
2、搭建Rtsp Server:./test-launch “( videotestsrc ! x264enc ! rtph264pay name=pay0 pt=96 )”
3、播放rtsp流:gst-launch-1.0 playbin uri=rtsp://127.0.0.1:8554/test`

3.5. 使用ffmpeg,go做server

https://github.com/aler9/rtsp-simple-server,下载源码后,直接运行./rtsp-simple-server,然后就可以发布流了。

3.6. 使用SRS

参考下文:https://www.cnblogs.com/yjmyzz/p/srs_study_1_install_push_and_pull_stream.html

3.7. easyDarwin和easyPusher

这里用easyDarwin+ffmpeg, 项目地址:https://github.com/EasyDarwin/EasyDarwin
下载release包:https://github.com/EasyDarwin/EasyDarwin/releases
直接运行EasyDarwin.exe,或者启动服务:ServiceInstall-EasyDarwin.exe
起流可以用自带的easyPusher,也可以用ffmpeg起流。

猜你喜欢

转载自blog.csdn.net/kittyzc/article/details/106920930