流媒体指的是使音频和视频形成稳定和连续的传输流和回放流的一系列技术、方法和协议的总称,即流媒体技术。
通过流媒体技术,服务器能够向客户机发送稳定和连续的多媒体数据流。客户机在接收数据的同时以一个稳定的速率回放,而不用等数据全部下载完之后再进行回放。
流媒体协议的作用:流同步、播放控制、质量控制、多端跨平台播放等。
直播三要素:低延时、高可用、质量反馈和检测。
简介:RTP(Real-time Transport Protocol)实时传输协议 是一个由IETF(The Internet Engineering Task Force,国际互联网工程任务组)提出的网络传输协议。
RTP用来为IP网上的音频、视频、传真等多种需要实时传输的多媒体数据提供端到端的实时传输服务,RTP协议详细说明了在互联网上传输音频和视频的数据包格式。RTP为Internet上端到端的实时传输提供时间信息和流同步,但不能证服务质量,服务质量由RTCP来提供。因此,用于流媒体系统时,RTP和RTCP一起使用,而且它是创建在UDP协议上的。
RTCP(Real-time Transport Control Protocol)实时传输控制协议 是由IETF定义的一个与RTP配套的协议,负责管理传输质量,提供流量控制和拥塞控制服务。RTCP为RTP流媒体提供信道外(out-of-band)控制。RTCP本身并不传输数据,但是和RTP一起合作将多媒体数据打包和发送。
RTP与RTCP的配合使用可以使传输效率最佳化,故常用于实时数据的传输。
实时传输协议(RTP)为数据提供了具有实时特征的端对端传送服务,如在组播或单播网络服务下的交互式视频音频或模拟数据。应用程序通常在 UDP 上运行 RTP 以便使用其多路结点和校验服务;这两种协议都提供了传输层协议的功能。但是 RTP 可以与其它适合的底层网络或传输协议一起使用。如果底层网络提供组播方式,那么 RTP 可以使用该组播表传输数据到多个目的地。
RTP 本身并没有提供按时发送机制或其它服务质量(QoS)保证,它依赖于底层服务去实现这一过程。 RTP 并不保证传送或防止无序传送,也不确定底层网络的可靠性。 RTP 实行有序传送, RTP 中的序列号允许接收方重组发送方的包序列,同时序列号也能用于决定适当的包位置,例如:在视频解码中,就不需要顺序解码。RTP 由两个紧密链接部分组成:
RTP ― 传送具有实时属性的数据;
RTP 控制协议(RTCP) ― 监控服务质量并传送正在进行的会话参与者的相关信息。
RTP标准定义了两个子协议,RTP和RTCP。
数据传输协议RTP,用于实时传输数据。该协议提供的信息包括:时间戳(用于同步)、序列号(用于丢包和重排序检测)、以及负载格式(用于说明数据的编码格式)。
控制协议RTCP,用于QoS反馈和同步媒体流。相对于RTP来说,RTCP所占的带宽非常小,通常只有5%。
RTP 使用偶数端口号接收发送数据,相应的RTCP则使用相邻的下一位奇数端口号。
RTP提供抖动补偿和数据无序到达检测的机制。由于IP网络的传输特性,数据的无序到达是很常见的。 RTP允许数据通过IP组播的方式传送到多个目的地。RTP被认为是在IP网络中传输音频和视频的基本标准。RTP通常配合模板和负载格式使用。
对于实时多媒体流应用,及时传送信息是首要目标,为达到目标可以忍受部分丢包。例如,在音频应用中的一个丢包,可能导致损失音频数据中的一秒内容,这个很容易通过合适的隐藏算法掩盖过去,从而不被人注意。由于TCP更注重可靠性而不是及时性,在RTP应用中很少使用。取而代之,大部分RTP实施是基于UDP的。
每一个多媒体流会建立一个RTP会话。一个会话包含带有RTP和RTCP端口号的IP地址。例如,音频和视频流使用分开的RTP会话,这样用户可以选择其中一个媒体流。形成会话的端口由其他协议(例如RTSP和SIP)来协商。RTP和RTCP使用UDP端口1024 - 65535。
RTP报文由两部分组成:报头和有效载荷。RTP报头格式其中:
这里的同步信源是指产生媒体流的信源,它通过RTP报头中的一个32位数字SSRC标识符来标识,而不依赖于网络地址,接收者将根据SSRC标识符来区分不同的信源,进行RTP报文的分组。特约信源是指当混合器接收到一个或多个同步信源的RTP报文后,经过混合处理产生一个新的组合RTP报文,并把混合器作为组合RTP报文的SSRC,而将原来所有的SSRC都作为CSRC传送给接收者,使接收者知道组成组合报文的各个SSRC。
RTCP 控制协议(RTCP) ― 监控服务质量并传送正在进行的会话参与者的相关信息。RTCP 第二方面的功能对于“松散受控”会话是足够的,也就是说,在没有明确的成员控制和组织的情况下,它并不非得用来支持一个应用程序的所有控制通信请求。
Ver.(2位元)是协定的版本号码。P(1位元)是用于RTP封包(packet)结束点的预留空间,视封包是否需要多余的填塞空间。X(1位元)是否在使用延伸空间于封包之中。。CC(4位元)包含了CSRC数目用于修正标头(fixedheader)。M(onebit)是用于应用等级以及其原型(profile)的定义。如果不为零表示资料有特别的程式解译。PT(7bits)是指payload的格式并决定将如何去由应用程式加以解译。SSRC是同步化来源。
RTSP(Real Time Streaming Protocol),RFC2326,实时流传输协议,是TCP/IP协议体系中的一个应用层协议,由哥伦比亚大学、网景和RealNetworks公司提交的IETF RFC标准。该协议定义了一对多应用程序如何有效地通过IP网络传送多媒体数据。RTSP在体系结构上位于RTP和RTCP之上,它使用TCP或UDP完成数据传输。HTTP与RTSP相比,HTTP请求由客户机发出,服务器作出响应;使用RTSP时,客户机和服务器都可以发出请求,即RTSP可以是双向的。RTSP是用来控制声音或影像的多媒体串流协议,并允许同时多个串流需求控制,传输时所用的网络通讯协定并不在其定义的范围内,服务器端可以自行选择使用TCP或UDP来传送串流内容,它的语法和运作跟HTTP 1.1类似,但并不特别强调时间同步,所以比较能容忍网络延迟。
其是 TCP/IP 协议体系中的一个应用层协议,该协议定义了一对多应用程序如何有效地通过 IP 网络传送多媒体数据。RTSP在体系结构上位于RTP和RTCP之上,它使用TCP或UDP完成数据传输。HTTP与RTSP相比,HTTP传送HTML,而RTSP传送的是多媒体数据。
RTSP是应用级协议,控制实时数据的发送。RTSP提供了一个可扩展框架,使实时数据,如音频与视频的受控点播成为可能。数据源包括现场数据与存储在剪辑中数据。该协议目的在于控制多个数据发送连接,为选择发送通道,如UDP、组播UDP与TCP,提供途径,并为选择基于RTP上发送机制提供方法。
RTSP建立并控制一个或几个时间同步的连续流媒体。尽管连续媒体流与控制流交换是可能的,通常它本身并不发送连续流。换言之,RTSP充当多媒体服务器的网络远程控制。RTSP连接没有绑定到传输层连接,如TCP。在RTSP连接期间,RTSP用户可打开或关闭多个对服务器的可传输连接以发出RTSP请求。此外,可使用无连接传输协议,如UDP。RTSP流控制的流可能用到RTP,但RTSP操作并不依赖用于携带连续媒体的传输机制。
RTSP中所有的操作都是通过服务器和客户端的消息应答机制完成的,其中消息包括请求和应答两种,RTSP是对称的协议,客户机和服务器都可以发送和回应请求。RTSP是一个基于文本的协议,它使用UTF -8编码(RFC2279)和ISO10646字符序列,采用RFC882定义的通用消息格式,每个语句行由CRLF结束。RTSP的消息包括请求和应答两类。
请求消息:请求消息由请求行、标题行中的各种标题域和主体实体组成。请求行和标题行由ASCⅡ字符组成。其中方法包括OPIONS、DESCRIBE、SETUP、PLAY、TEARDOWN等。URL是接接收方的地址,例如:rtsp://192.168.0.1/video.264。RTSP版本一般都是 RTSP/1.0。每行后面的CRLF表示回车换行,需要接收端有相应的解析,最后一个消息头需要有两个CRLF。消息体是可选的,有的请求消息并不带消息体。
应答消息:其中RTSP版本一般都是RTSP/1.0。状态码是一个数值,用于表示请求消息的执行结果,比如200表示成功。短语是与状态码对应的文本解释。
H.321采用,用RTSP代替HTTP。
“rksp"和“rtspu"方案用于指RTSP协议使用的网络资源,为RTSP URL定义方案特定的语法和语义。
会议标识对RTSP来说是模糊的,采用标准URI编码方法编码,可包含任何八位组数值。会议标识必须全局惟一。
连接标识是长度不确定的字符串,必须随机选择,至少要8个八位组长,使其很难被猜出。
SMPTE相关时标表示相对剪辑开始的时间,相关时标表示成SMPTE时间代码,精确到帧级。时间代码格式为小时:分钟:秒:帧。缺省smpte格式是"SMPTE 30",帧速率为每秒29.97帧。其他SMPTE代码可选择使用smpte时间获得支持(如"SMPIE 25")。时间数值中帧段值可从0到29。每秒30与29.97帧的差别可将每分钟的头两帧丢掉来实现。如帧值为零,就可删除。
正常播放时间(NPT)表示相对演示开始的流绝对位置。时标由十进制分数组成。左边部分用秒或小时、分钟、秒表示;小数点右边部分表示秒的部分。演示的开始对应0.0秒,负数没有定义。特殊常数定义成现场事件的当前时刻,这也许只用于现场事件。直观上,NPT是联系观看者与程序的时钟,通常以数字式显示在VCR上。
绝对时间表示成ISO 8601时标,采用UTC(GMT)。
可选标签是用于指定RTSP新可选项的惟一标记。这些标记用在请求和代理-请求头段。当登记新RTSP选项时,需提供下列信息:
(1)名称和描述选项。名称长度不限,但不应该多于20个字符。名称不能包括空格、控制字符。
(2)表明谁改变选项的控制。如IETF,ISO,ITU-T,或其他国际标准团体、联盟或公司。
(3)深入描述的参考,如RFC、论文、专利、技术报告、文档源码和计算机手册。
(4)对专用选项,附上联系方式。
RTSP是基于文本的协议,采用ISO 10646字符集,使用UTF-8编码方案。行以CRLF中断,但接收者本身可将CR和LF解释成行终止符。基于文本的协议使以自描述方式增加可选参数更容易。由于参数的数量和命令的频率出现较低,处理效率没引起注意。文本协议很容易以脚本语言(如:Tcl,Visual Basic与Perl)实现研究原型。
ISO 10646字符集避免敏感字符集切换,但对应用来说不可见。RTCP也采用这种编码方案。带有重要意义位的ISO 8859-1字符表示如100001x 10x x x x x x。RTSP信息可通过任何低层传输协议携带。
请求包括方法、方法作用于其上的对象以及进一步描述方法的参数。方法也可设计为在服务器端只需要少量或不需要状态维护。当信息体包含在信息中,信息体长度由如下因素决定:
(1)不管实体头段是否出现在信息中,不包括信息体的响应,信息总以头段后第一个空行结束。
(2)如出现内容长度头段,其值以字节计,表示信息体长度。如未出现头段,其值为零。
(3)服务器关闭连接。
注意,RTSP目前并不支持HTTP 1.1“块”传输编码,需要有内容长度头。假如返回适度演示描述长度,即使动态产生,使块传输编码没有必要,服务器也应该能决定其长度。如有实体,即使必须有内容长度,且长度没显式给出,规则可确保行为合理。
从用户到服务器端的请求信息在第一行内包括源采用的方法、源标识和所用协议版本。RTSP定义了附加状态代码,但没有定义任何HTTP代码。
RTSP请求可以几种不同方式传送:
传输连接类型由RTSP URL来定义。对“rtsp’’方案,需要持续连接;而"rtspu"方案,调用RTSP请求发送,而不用建立连接。
不像HTTP,RTSP允许媒体服务器给媒体用户发送请求。然而,这仅在持久连接时才支持,否则媒体服务器没有可靠途径到达用户,这也是请求通过防火墙从媒体服务器传到用户的惟一途径。
支持持久连接或无连接的客户端可能给其请求排队。服务器必须以收到请求的同样顺序发出响应。如果请求不是发送给多播组,接收者就确认请求,如没有确认信息,发送者可在超过一个来回时间(RTT)后重发同一信息。
在TCP中RTT估计的初始值为500ms。应用缓存最后所测量的RTT,作为将来连接的初始值。如使用一个可靠传输协议传输RTSP,请求不允许重发,RTSP应用反过来依赖低层传输提供可靠性。如两个低层可靠传输(如TCP和RTSP)应用重发请求,有可能每个包损失导致两次重传。由于传输栈在第一次尝试到达接收者前不会发送应用层重传,接收者也不能充分利用应用层重传。如包损失由阻塞引起,不同层的重发将使阻塞进一步恶化。时标头用来避免重发模糊性问题,避免对圆锥算法的依赖。每个请求在CSeq头中携带一个系列号,每发送一个不同请求,它就加一。如由于没有确认而重发请求,请求必须携带初始系列号。
实现RTSP的系统必须支持通过TCP传输RTSP,并支持UDP。对UDP和TCP,RTSP服务器的缺省端口都是554。许多目的一致的RTSP包被打包成单个低层PDU或TCP流。RTSP数据可与RTP和RTCP包交叉。不像HTTP,RTSP信息必须包含一个内容长度头,无论信息何时包含负载。否则,RTSP包以空行结束,后跟最后一个信息头。
每个演示和媒体流可用RTSP URL识别。演示组成的整个演示与媒体属性由演示描述文件定义。使用HTTP或其他途径用户可获得这个文件,它没有必要保存在媒体服务器上。为了说明这个问题,假设演示描述了多个演示,其中每个演示维持了一个公共时间轴。为简化说明,且不失一般性,假定演示描述的确包含这样一个演示。演示可包含多个媒体流。除媒体参数外,网络目标地址和端口也需要决定。
下面区分几种操作模式。
(1)单播:用户选择的端口号将媒体发送到RTSP请求源。
(2)服务器选择地址多播:媒体服务器选择多播地址和端口,这是现场直播或准点播常用的方式。
(3)用户选择地址多播:如服务器加入正在进行的多播会议,多播地址、端口和密钥由会议描述给出。
RTSP控制通过单独协议发送的数据流,与控制通道无关。例如,RTSP控制可通过TCP连接,而数据流通过UDP。因此,即使媒体服务器没有收到请求,数据也会继续发送。在连接生命期,单个媒体流可通过不同TCP连接顺序发出请求来控制。所以,服务器需要维持能联系流与RTSP请求的连接状态。RTSP中很多方法与状态无关,但下列方法在定义服务器流资源的分配与应用上起着重要的作用:
(1) SETUP:让服务器给流分配资源,启动RTSP连接。
(2) PLAY与RECORD:启动SETUP分配流的数据传输。
(3) PAUSE:临时停止流,而不释放服务器资源。
(4) TEARDOWN:释放流的资源,RTSP连接停止。
标识状态的RTSP方法使用连接头段识别RTSP连接,为响应SETUP请求,服务器连接产生连接标识。
资源预留协议(Resource ReSerVation Protocol;RSVP)是一种用于互联网上质量整合服务的协议。RSVP 允许主机在网络上请求特殊服务质量用于特殊应用程序数据流的传输。路由器也使用 RSVP 发送服务质量(QOS)请求给所有结点(沿着流路径)并建立和维持这种状态以提供请求服务。
通常 RSVP 请求将会引起每个节点数据路径上的资源预留。
RSVP 只在单方向上进行资源请求,因此,尽管相同的应用程序,同时可能既担当发送者也担当接受者,但 RSVP 对发送者与接受者在逻辑上是有区别的。 RSVP 运行在 IPV4 或 IPV6 上层,占据协议栈中传输协议的空间。 RSVP 不传输应用数据,但支持因特网控制协议,如 ICMP、IGMP 或者路由选择协议。正如路由选择和管理类协议的实施一样, RSVP 的运行也是在后台执行,而并非在数据转发路径上。
RFC2205对RSVP的特征做出以下的描述:
(1)支持单播与组播;
(2)单向预留;
(3)接收者发起预留;
(4)维护Internet中的软状态。
RSVP 本质上并不属于路由选择协议, RSVP 的设计目标是与当前和未来的单播(unicast)和组播(multicast)路由选择协议同时运行。 RSVP 进程参照本地路由选择数据库以获得传送路径。以组播为例,主机发送 IGMP 信息以加入组播组,然后沿着组播组传送路径,发送 RSVP 信息以预留资源。路由选择协议决定数据包转发到哪。 RSVP 只考虑根据路由选择所转发的数据包的 QOS 。为了有效适应大型组、动态组成员以及不同机种的接收端需求,通过 RSVP ,接收端可以请求一个特定的 QOS[RSVP93] 。 QOS 请求从接收端主机应用程序被传送至本地 RSVP 进程,然后 RSVP 协议沿着相反的数据路径,将此请求传送到所有节点(路由器和主机),但是只到达接收端数据路径加入到组播分配树中时的路由器。所以, RSVP 预留开销是和接受端的数量成对数关系而非线性关系。
RSVP是由接收者提出资源预留申请的,这种申请是单向的,也就是说为从主机a到主机b的数据流预留的资源,对于从主机b到主机a的数据流是不起作用的。因为在当前的internet中,双向的路由是不对称的:从主机a到主机b的路径并不一定是从主机b到主机a的路径的反向;另外一个,两个方向的数据传输特征和对应申请预留的资源也未必相同。
RSVP标准[RFC 2205]没有定义网络向数据流提供预约带宽的方法,它只是一个允许应用预约必要链路带宽的协议。一旦某预约付诸实施,英特网中的路由器就实际向数据流提供预约的带宽。
RSVP中的资源预留请求通过流描述符来表示,包括“流规范(Flowspec)”和“过滤器规范(Filter spec)”。其中,Flowspec描述符所希望得到的QoS保证,它用来设置相应网络结点中分组调度部件或者链路层机制的参数;而Filter spec 用来设置分组流分类器的参数。Flowerspec一般由服务类型(Service Class)和参数“Rspec”、“Tspec”组成。“Rspec”用来定义所希望的QoS服务,而“Tspec”用来描述数据流。“Rspec”与“Tspec”的格式和内容对RSVP是透明的,它由IntServ的服务类型来描述。
RSVP资源预留消息由接收方发起并一次向上游传送,上游在这里是从接收方到发送方的方向。在途径的每一个结点上,资源预留请求会触发下面的两个动作:
(1)在链路上进行资源预留。每一个结点上的RSVP进程(RSVP Process)都会将 请求资源预留的消息传递给接纳控制部件(Admission Control)和策略控制部件(Policy Control)。只要这两个部件中任何一个在检测是否可接纳时失败,那么资源资源预留请求就会被拒绝;同时,RSVP进程产生一个错误消息发送给接收方。如果二者都能成功,结点就会同时对分组流分类器进行相应的设置,从而在实际数据流传输时能够将这个预留的数据分组从进入路由器中的所有分组中挑选出来,进而为它提供QoS保证。
(2)向上游结点转发资源预留请求
一个需要按特定服务质量发送数据流的RSVP主机将会传输一个RSVP路径消息,这个路径消息将会沿单播或组播路由通过路由协议预先建立的路径传输。如果路径消息到达一个不理解RSVP的路由器,将会将这个消息转发并不对其内容进行分析而且不会为这个流进行资源预留。
当目的路由器接收到路径消息,它将会:
(1)按照请求的参数进行资源预留。对此,许可控制和策略控制处理请求参数并通知分组分类以便正确处理选定的数据分组,或者和上层协商如何进行分组处理。
(2)向上游转发请求(朝着发送方方向)。在每个节点上,预留消息的流量说明(flowspec)可以由前向节点更改。(例如:在多播流资源预留时,预留请求就可以被合并)路径上的每个节点都可以接收或者拒绝请求。
RTMP是Real Time Messaging Protocol(实时消息传输协议)的首字母缩写。该协议基于TCP,是一个协议族,包括RTMP基本协议及RTMPT/RTMPS/RTMPE等多种变种。RTMP是一种设计用来进行实时数据通信的网络协议,主要用来在Flash/AIR平台和支持RTMP协议的流媒体/交互服务器之间进行音视频和数据通信。支持该协议的软件包括Adobe Media Server/Ultrant Media Server/red5等。RTMP与HTTP一样,都属于TCP/IP四层模型的应用层。
RTMP又是Routing Table Maintenance Protocol(路由选择表维护协议)的缩写。 在 AppleTalk 协议组中,路由选择表维护协议(RTMP,Routing Table Maintenance Protocol)是一种传输层协议,它在 AppleTalk 路由器中建立并维护路由选择表。RTMP 基于路由选择信息协议(RIP)。正如 RIP 一样,RTMP 使用跳数作为路由计量标准。一个数据包从源 网络发送到目标网络,必须通过的路由器或其它中间介质节点数目的计算结果即为跳数。
RTMP(Real Time Messaging Protocol)实时消息传送协议是Adobe Systems公司为Flash播放器和服务器之间音频、视频和数据传输 开发的开放协议。它有多种变种:
1)RTMP工作在TCP之上,默认使用端口1935;
2)RTMPE在RTMP的基础上增加了加密功能;
3)RTMPT封装在HTTP请求之上,可穿透防火墙;
4)RTMPS类似RTMPT,增加了TLS/SSL的安全功能;
虽然rtmp有很多变种,但实际在我们的直播应用中,常见的是原始的rtmp。rtmp协议中基本的数据单元称为消息(Message)。当rtmp协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk)。Rtmp的交互过程可以理解成独有的握手过程、控制命令传输、音视频数据传输。
一个 RTMP 连接以握手开始。RTMP 的握手不同于其他协议;RTMP 握手由三个固定长度的块组成,而不是像其他协议一样的带有报头的可变长度的块。客户端 (发起连接请求的终端) 和服务器端各自发送相同的三块。便于演示,当发送自客户端时这些块被指定为 C0、C1 和 C2;当发送自服务器端时这些块分别被指定为 S0、S1 和 S2。
+-+-+-+-+-+-+-+-+-+
| version (1Byte)|
+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+
| time (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+
| zero (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+
| random bytes |
+-+-+-+-+-+-+-+-+-+-+
|random bytes(cont) |
| .... |
+-+-+-+-+-+-+-+-+-+-+
time: 4 字节
本字段包含时间戳。该时间戳应该是发送这个数据块的端点的后续块的时间起始点。
可以是 0 ,或其他的任何值。为了同步多个流,端点可能发送其块流的当前值。
zero: 4 字节
本字段必须是全零。
random bytes: 1528 字节。
本字段可以包含任何值。因为每个端点必须用自己初始化的握手和对端初始化的。
+-+-+-+-+-+-+-+-+-+-+
| time (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+
| time2(4 bytes) |
+-+-+-+-+-+-+-+-+-+-+
| random bytes |
+-+-+-+-+-+-+-+-+-+-+
|random bytes(cont) |
| .... |
+-+-+-+-+-+-+-+-+-+-+
time: 4 字节
本字段必须包含对等段发送的时间(对C2来说是S1 ,对S2来说是C1)。
time2: 4 字节
本字段必须包含先前发送的并被对端读取的包的时间戳。
random bytes: 1528 字节
本字段必须包含对端发送的随机数据字段(对C2来说是S1 ,对S2来说是C1)。
RTMP握手以客户端发送 C0 和 C1 块开始,客户端必须接收到 S1 才能发送 C2,客户端必须接收到 S2 才能发送任何其他数据,服务器端必须接收到 C0 才能发送 S0 和 S1,也可以等待接收到 C1 再发送 S0 和 S1,服务器端必须接收到 C1 才能发送 S2,服务器端必须接收到 C2 才能发送任何其他数据。以下为RTMP的握手过程图介绍:
+----------+ +----------+
| Client | TCP/IP Network | Server |
+----------+ | +----------+
| | |
Unintialized | Unintialized
| C0 | |
|----------------->| C0 |
| C1 |----------------->|
|----------------->| S0 |
| |<-----------------|
Version sent | S1 |
| S0 |<-----------------|
|<-----------------| Version sent
| S1 | |
|<-----------------| C1 |
| |----------------->|
| C2 | |
|----------------->| S2 |
ACK sent |<-----------------|
|<-----------------| C2 ACK sent
| |----------------->|
Handshake Done | Handshake Done
| | |
... ... ...
范要求RTMP需要一个一个的发送握手包,但是实际上客户端发送C0+C1,服务端发送S0+S1+S2,再客户端在发送C2结束握手。
+-+-+-+-+-+-+ +-+-+-+-+-+-+
| Client | | Server |
+-+-+-+-+-+-+ +-+-+-+-+-+-+
|--------- C0C1 -------->|
|<------- S0S1S2 -------|
|---------- C2 --------->|
RTMP协议中基本的数据单元称为消息(Message)。当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk)。Message会被拆分成Chunk发送,而且必须在一个Chunk发送完成之后才能开始发送下一个Chunk。每个Chunk中带有MessageID代表属于哪个Message,接受端也会按照这个id来将chunk组装成Message。
+-------+ +--------------+----------------+
| Chunk | = | Chunk Header | Chunk Data |
+-------+ +--------------+----------------+
Chunk Header 由 Basic Header + Message Header + ExtendedTimestamp(不一定存在)组成
+--------------+ +-------------+----------------+-------------------+
| Chunk Header | = | Basic header| Message Header |Extended Timestamp |
+--------------+ +-------------+----------------+-------------------+
+-+-+-+-+-+-+-+-+
|fmt| cs id |
+-+-+-+-+-+-+-+-+
chuck stream = cs
fmt: 表示块类型,决定了Chunk Msg Header的格式,它占第一个字节的0~1bit,
cs id:表示块流id 占2~7bit属于csid。
①cs id在64~319的范围内时,cs idTS=0,cs id =(第二个字节的值)+64
0 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|fmt|0 0 0 0 0 0|the second byte|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
②cs id在64~65599的范围内时(①与②存在交集,原则上交集部分选择①),cs idTS=0x3f,
bit位全为1时,cs id=(第二个字节的值×256)+(第三个字节的值)+64
0 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|fmt|1 1 1 1 1 1|the second byte| the third byte|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
③cs id在3~63的范围内时,cs idTS=1~0x3e,即6位bit非全0也非全1时,cs id=cs idTS
0
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-+
|fmt|cs id (0x0~0x3f) |
+-+-+-+-+-+-+-+-+-+-+-+
以下是上述 chuck stream id 类型非全部:
typedef NS_ENUM(NSUInteger, RTMPChunckStreamID)
{
RTMPChunckStreamID_PRO_CONTROL = 0x2, // 协议控制块流ID
RTMPChunckStreamID_COMMAND = 0x3, // 控制块流ID
RTMPChunckStreamID_MEDIA = 0x4, // 音视频块流ID
};
包含了要发送的实际信息(可能是完整的,也可能是一部分)的描述信息。Message Header的格式和长度取决于Basic Header的chunk type,共有4种不同的格式,由上面所提到的Basic Header中的fmt字段控制。其中第一种格式可以表示其他三种表示的所有数据,但由于其他三种格式是基于对之前chunk的差量化的表示,因此可以更简洁地表示相同的数据,实际使用的时候还是应该采用尽量少的字节表示相同意义的数据。以下按照字节数从多到少的顺序分别介绍这4种格式的Chuck Message Header。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | timestamp | message length: +-------------------------------+---------------+---------------+ : |message type id| : +-------------------------------+---------------+---------------+ : message stream id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ timestamp(时间戳): 占 3 byte 最大表示16777215=0xFFFFFF=2^24-1,超出这个值,这3个字节置为1,将实际数据转存到Extended Timestamp字段中。 message length(时间戳): 占 3 byte 表示实际发送的消息的数据如音频帧、视频帧等数据的长度,单位是字节。注意这里是Message的长度,也就是chunk属于的Message的总数据长度,而不是chunk本身Data的数据的长度。 message type id(消息的类型id): 占 1 byte 表示实际发送的数据的类型,如8代表音频数据、9代表视频数据。 message stream id(消息的流id): 占 4byte 表示该chunk所在的流的ID,和Basic Header的CSID一样,它采用小端存储的方式。 ①fmt=0:长度11 byte,其他三种能表示的数据它都能表示在一个块流的开始和时 间戳返回的时候必须有这种块 Chuck Message Header = timestamp + message length + message type id + message stream id ②fmt=1:长度为7 byte,与fmt=0时,相比,该类型少了Message Stream Id, 具有可变大小消息的流,在第一个消息之后的每个消息的第一个块应该使用这个格式 Chuck Message Header = timestamp + message length + message type id ③fmt=2:长度3 byte,不包含Message Stream Id和Message Length 、 Message type Id具有固定大小消息的流,在第一个消息之后的每个消息的第 一个块应该使用这个格式 Chuck Message Header = timestamp ④fmt=3:长度为0 byte, 当一个消息被分成多个块,除了第一块以外, 所有的块都应使用这种类型 Chuck Message Header = 0 byte
typedef NS_ENUM(NSUInteger, RTMPBHFmt)
{
RTMPBHFmt_FULL = 0x0,
RTMPBHFmt_NO_MSG_STREAM_ID = 0x1,
RTMPBHFmt_TIMESTAMP = 0x2, // 'Chuck Message Header' only timestamp
RTMPBHFmt_ONLY = 0x3, // 'Chunk Message Header' all no
};
以下是上述 message type id 类型非全部:
typedef NS_ENUM(NSUInteger, RTMPMessageTypeID)
{
RTMPMessageTypeID_CHUNK_SIZE = 0x1, //协议控制消息 ChunkData承载大小,进行分块
RTMPMessageTypeID_ABORT = 0x2, //协议控制消息 消息分块只收到部分时,发送此控制消息,发端不在
RTMPMessageTypeID_BYTES_READ = 0x3, //协议控制消息
RTMPMessageTypeID_PING = 0x4, //用户控制消息 该消息在Chunk流中发送时,msg stream id = 0, chunck stream id = 2, message type id = 4
RTMPMessageTypeID_SERVER_WINDOW = 0x5, //协议控制消息
RTMPMessageTypeID_PEER_BW = 0x6, //协议控制消息
RTMPMessageTypeID_AUDIO = 0x8, //音频消息
RTMPMessageTypeID_VIDEO = 0x9, //视频消息
RTMPMessageTypeID_FLEX_STREAM = 0xF,
RTMPMessageTypeID_FLEX_OBJECT = 0x10,
RTMPMessageTypeID_FLEX_MESSAGE = 0x11,
RTMPMessageTypeID_NOTIFY = 0x12, //数据消息,传递一些元数据
RTMPMessageTypeID_SHARED_OBJ = 0x13, //
RTMPMessageTypeID_INVOKE = 0x14, //命令消息,客户端与服务器之间执行命令如:connect、publish
RTMPMessageTypeID_METADATA = 0x16, //
};
注意
message type id 发送音视频数据的时候,如果包头MessageTypeID为0x8或0x9,数据(chunk data)是flv的tag data(没有tag header),flv格式封装请见官网。也可以用新类型MessageTypeID为0x16,数据(chunk data)是一个完整flv的tag(tag header + tag data)。
message stream id 采用 小端 存储,RTMP都是大端模式,所以发送数据,包头,交互消息都要填写 大端 模式的,但是只有streamID是 小端 模式。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
只有当块消息头中的普通时间戳设置为 0xffffff 时,本字段才被传送。
如果普通时间戳的值小于 0x00ffffff ,那么本字段一定不能出现。
如果块消息头中时间戳字段不出现本字段也一定不能出现。
类型 3 的块一定不能含有本字段。
本字段在块消息头之后,块数据之前。
+-----------+
|Chunk Data | Chunk Data的实例就是Message
+-----------+
Message = Message Header + Message Payload
Message Header = Message Type + Payload Length + Timestamp + Stream ID
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Message Type | Payload Length |
+---------------------------------------------------------------+
| Timestamp |
+-----------------------------------------------+---------------+
| Stream ID | :
+-----------------------------------------------+ - - - - - - - +
: Message Payload :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
: ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
(1)Message Type(1 byte)以下简写为MT,消息类型很重要,
它代表了这个消息是什么类型,当写程序的时候需要根据不同的消息,做不同的处理。
1~2 用于chunk协议,3~6 用于rtmp协议本身,协议控制消息必须要求。
(2)Payload length(3 bytes) 表示负载的长度(big-endian 格式)。
(3)Timestamp (4 bytes) 时间戳(big-endian 格式)。
(4)Stream ID (3 bytes) 消息流ID(big-endian 格式)。
(5)Message Payload 真实的数据。
(1) MT=1,Set Chunk Size 设置块的大小,通知对端用使用新的块大小,共4 bytes。默认大小是128字节。
(2) MT=2,Abort Message 取消消息,用于通知正在等待接收块以完成消息的对等端,丢弃一个块流中已经接收的部分并且取消对该消息的处理,共4 bytes。
(3) MT=3,Acknowledgement 确认消息,客户端或服务端在接收到数量与窗口大小相等的字节后发送确认消息到对方。窗口大小是在没有接收到接收者发送的确认消息之前发送的字节数的最大值。服务端在建立连接之后发送窗口大小。本消息指定序列号。序列号,是到当前时间为止已经接收到的字节数。共4bytes。
(4) MT=4,User Control Message 用户控制消息,客户端或服务端发送本消息通知对方用户的控制事件。本消息承载事件类型和事件数据。消息数据的头两个字节用于标识事件类型。事件类型之后是事件数据。事件数据字段是可变长的。
(5) MT=5,Window Acknowledgement Size 确认窗口大小,客户端或服务端发送本消息来通知对方发送确认消息的窗口大小,共4 bytes。
(6) MT=6,Set Peer Bandwidth 设置对等端带宽,客户端或服务端发送本消息更新对等端的输出带宽。发送者可以在限制类型字段(1 bytes)把消息标记为硬(0),软(1),或者动态(2)。如果是硬限制对等端必须按提供的带宽发送数据。如果是软限制,对等端可以灵活决定带宽,发送端可以限制带宽。如果是动态限制,带宽既可以是硬限制也可以是软限制。
(7) MT=8,Audio message,客户端或服务端发送本消息用于发送音频数据。消息类型8,保留为音频消息。
(8) MT=9,Video message,客户端或服务端使用本消息向对方发送视频数据。消息类型值 9,保留为视频消息。
(9) MT=15或18,Data message,客户端或服务端通过本消息向对方发送元数据和用户数据。元数据包括数据的创建时间、时长、主题等细节。消息类型为 18 的用 AMF0 编码,消息类型为 15 的用AMF3 编码。
(10) MT=17或20,Command message,命令消息都是用AMF编码的,AMF有两种,为AMF0和AMF3。命令消息有命令名,传输ID,和命名对象组成。而命名对象是由一系列参数组成的。
+-------------+ +----------+
| Play Client | | | Server |
+-------------+ | +----------+
| |Handshaking and Application| |
| | connect done | |
| | |
---+---- |---------Command Message(createStream) --------->|
Create | |
Stream | |
---+---- |<-------------- Command Message -----------------|
| (_result- createStream response) |
| |
---+---- |------------ Command Message (play) ------------>|
play | |
| |<---------------- SetChunkSize ------------------|
| | |
| |<----- User Control (StreamIsRecorded) ----------|
| | |
| |<-------- UserControl (StreamBegin) -------------|
| | |
| |<---- Command Message(onStatus-play reset) ------|
| | |
| |<---- Command Message(onStatus-play start) ------|
| | |
| |------------------ Audio Message---------------->|
| | |
| |------------------ Video Message---------------->|
| | |
|
|
Keep receiving audio and video stream till finishes
a. 客户端从服务端接收到流创建成功消息,发送播放命令到服务端。
b. 接收到播放命令后,服务端发送协议消息设置块大小。
c. 服务端发送另一个协议消息(用户控制消息),并且在消息中指定事件”streamisrecorded” 和流 ID 。消息承载的头 2 个字,为事件类型,后4 个字节为流 ID 。d. 服务端发送事件” streambegin” 的协议消息(用户控制),告知客户端流 ID 。
e. 服务端发送响应状态命令消息NetStream.Play.Start & NetStream.Play.reset,如果客户端发送的播放命令成功的话。只有当客户端发送的播放命令设置了 reset 命令的条件下,服务端才发送NetStream.Play.reset消息。如果要发送的流,没有找的话,服务端发送NetStream.Play.StreamNotFound消息。在此之后服务端发送客户端要播放的音频和视频数据。
+-------------+ +----------+
| Client | | | Server |
+-------------+ | +----------+
| | Handshaking Done | |
| | |
| | |
---+---- |--------- Command Message(connect) --------->|
| | |
Connect |<---------- Window Acknowledge Size -------------|
| | |
| |<------------- Set Peer BandWidth ---------------|
| | |
| |----------- Window Acknowledge Size ------------>|
| | |
| |<--------- User Control(StreamBegin) ------------|
| | |
---+---- |--------------- Command Message ---------------->|
| (_result- connect response) |
| |
---+---- |---------Command Message(createStream) --------->|
Create | |
Stream | |
---+---- |<-------------- Command Message -----------------|
| (_result- createStream response) |
| |
---+---- |--------- Command Message (publish) ------------>|
| | |
publish |<-------- UserControl (StreamBegin) -------------|
| | |
| |---------- Data Message (Metadata) ------------->|
| | |
| |------------------ Audio Message---------------->|
| | |
| |----------------- SetChunkSize ----------------->|
| | |
| |<--------------- Command Message ----------------|
| | (_result- publish result) |
| |------------------ Video Message---------------->|
|
|
Until the stream is complete
MT=22,Aggregate message,聚合消息是含有一个消息列表的一种消息。消息类型值 22,保留用于聚合消息。
+---------+-------------------------+ | Header | Aggregate Message body | +---------+-------------------------+ 聚合消息的格式+--------+--------------+--------------+--------+-------------+---------------+ - - - -|Header 0|Message Data 0|Back Pointer 0|Header 1|Message Data 1|Back Pointer 1|+--------+--------------+--------------+--------+--------------+--------------+ - - - - 聚合消息的bodyBack Pointer包含了前面消息的大小(包括Header的大小)。这个设置匹配了 flv 文件格式,可用于后向搜索。
FLV 由 FLV Header + FLV Body 组成 -- FLV Body ------------------------------ ... ---------------------------- / \+---------+-------------+-------------+-------------+-- ... --+-------------+-------------+| FLV | PreTag | Tag | PreTag | | Tag | PreTag | | Hearder | Size | 1 | Size | | N | Size |+---------+-------------+-------------+-------------+-- ... --+-------------+-------------+jiantou |┏—————————————————————————————┛|| FLV Header占9bytes,flv的类型、版本的信息,| 组成:Signature(3bytes)+Version(1bytes)+Flags(1bytes)+DataOffset(4bytes)| ①Signature:固定FLV三个字符作为标示,一般前3个字符为FLV是就认为是flv文件| ②Version:表示FLV的版本号| ③Flags:内容标示,第0位和第2位,分别表示video与audio存在的情况(1表示存在,0表示不存在) | 如0x05(00000101)同时存在视频、音频| ④DataOffset:表示FLV的Header长度。这里固定是9|| FLV Body: TagSize0 + Tag1 + Tag1 Size + Tag2 + Tag2 Size + ... + TagN + TagN Size|| PreTagSize占4bytes,值表示前一个Tag的长度| Tag 由 Tag Header + Tag Data 组成,Tag分三种类型,video、audio、scripts(元数据)|| (某一个Tag)┗——→ +------------+ | Tag Header | +------------+ | Tag Data | +------------+ +------------+------------+------------+------------+------------+ TagHeader | Tag type | Data Size | Time Stamp |ExtTimeStamp| Stream ID | +------------+------------+------------+------------+------------+ +------------+------------+------------+-----------------------------------+TagData_Video | Frame | AvcPk |Composition | AVC Pk Type == 0: SPS_PPS | | Codec | Type | Time | AVC Pk Type == 1: nalu len + nalu | +------------+------------+------------+-----------------------------------+ +------------+------------+-----------------------------------+TagData_Audio | Format | AACPk | AAC Pk Type == 0: AAC Spec | | SR,SZ,ST | Type | AAC Pk Type == 1: AAC RAW | +------------+------------+-----------------------------------+ //AVC Pk Typetypedef NS_ENUM(NSUInteger, flv_video_h264_packettype){ flv_video_h264_packettype_seqHeader = 0, flv_video_h264_packettype_nalu = 1, flv_video_h264_packettype_endOfSeq = 2,};//AAC Pk Typetypedef NS_ENUM(NSUInteger, flv_audio_aac_packettype){ msp_flv_audio_aac_packettype_seqHeader = 0, msp_flv_audio_aac_packettype_raw = 1,}; flv要求发送音视频之前先发送一个tag_scripts类型元数据,描述视频或音频的信息的数据,如宽度、高度、采样、声道、频率、编码等等 flv要求第一个tag_video必须是sps pps数据包 之后才能发送视频编码数据 flv要求第一个tag_audio必须是音频配置数据包 之后才能发送音频编码数据 Tag Header占11bytes,存放当前Tag类型、TagData(数据区)的长度等信息 +------------+ | Tag Header | +------------+ ①Tag类型:1byte,8 = 音频,9 = 视频,18(0x12) = 脚本, 其他 = 保留 ②数据区长度(tag data size):3bytes ③时间戳:3bytes,整数单位毫秒,脚本类型Tag为0 ④时间戳扩展:1bytes ⑤StreamsID:3bytes 总是0 Tag Data 数据区,音频数据(TagData_Audio)、视频数据(TagData_Video)、脚本数据(TagData_Scripts) +------------+ | Tag Data | +------------+ TagData_Video 第一个byte视频信息 = 帧类型(4bit) + 编码ID(4bit) 后面数据,视频格式为 AVC(H.264)的话,后面为4个字节信息,AVCPacketType(1byte)和 CompositionTime(3byte) AVCPacketType == 1 则CompositionTime = Composition time offset 后面三个字节也是0,说明这个tag记录的是AVCDecoderConfigurationRecord。包含sps和pps数据。 后面数据为:0x01+sps[1]+sps[2]+sps[3]+0xFF+0xE1+sps_size+sps+01+pps_size+pps AVCPacketType != 1 则CompositionTime = 0 后面三个字节也是0,说明这个tag记录的是AVCDecoderConfigurationRecord。包含sps和pps数据 后面数据为:0x01+sps[1]+sps[2]+sps[3]+0xFF+0xE1+sps_size+sps+01+pps_size+pps TagData_Audio 第一个byte音频信息 = 音频格式(4bit) + 采样率(2bit) + 采样长度(1bit) + 音频类型(1bit) 后面数据,如果音频格式为AAC,后面跟1byte 0x00/0x01。 如果0x00 后面跟 audio config data 数据 需要作为第一个 audio tag 发送 如果0x01 后面跟 audio frame data 数据 TagData_Scripts 数据类型 +(数据长度)+ 数据,数据类型占1byte,数据长度根据数据类型 数据类型: 0 = Number type 1 = Boolean type 2 = String type 3 = Object type 4 = MovieClip type 5 = Null type 6 = Undefined type 7 = Reference type 8 = ECMA array type 10 = Strict array type 11 = Date type 12 = Long string type 如果为 String type ,那么数据长度占2bytes(Long string type 占 4bytes),后面就是字符串数据 举个栗子:0x02(String 类型)+0x000a("onMetaData"长度) + "onMetaData" 如果为 Number type ,没有数据长度,后面直接为8bytes的 Double 类型数据 如果为 Boolean type,没有数据长度,后面直接为1byte的 Bool 类型数据 如果为 ECMA array type,数据长度占4bytes 值表示数组长度,后面 键是 String 类型的,开头0x02被省略, 直接跟字符串长度,然后是字符串,在是值类型(根据上面来) #pragma mark - video Tag Data// 帧类型 占4bits 这里只用到了 key、innertypedef NS_ENUM (NSUInteger, flv_video_frametype){ flv_video_frametype_key = 1,// keyframe (for AVC, a seekable frame) flv_video_frametype_inner = 2,// inter frame (for AVC, a non-seekable frame) //flv_video_frametype_inner_d = 3,// disposable inter frame (H.263 only) //flv_video_frametype_key_g = 4,// generated keyframe (reserved for server use only) //flv_video_frametype_vi_cf = 5,// video info/command frame};// 编码(格式)ID 占4bits 只用到了H264typedef NS_ENUM (NSUInteger, flv_video_codecid){ flv_video_codecid_JPEG = 1,// JPEG (currently unused) flv_video_codecid_H263 = 2,// Sorenson H.263 //flv_video_codecid_ScreenVideo = 3,// Screen video //flv_video_codecid_On2VP6 = 4,// On2 VP6 //flv_video_codecid_On2VP6_AC = 5,// On2 VP6 with alpha channel //flv_video_codecid_ScreenVideo2 = 6,// Screen video version 2 flv_video_codecid_H264 = 7,// AVC //flv_video_codecid_RealH263 = 8, //flv_video_codecid_MPEG4 = 9,};#pragma mark - audio Tag Data// 音频编码(音频格式)ID 占4bits 只用到了AACtypedef NS_ENUM (NSUInteger, flv_audio_codecid){ //flv_audio_codecid_PCM = 0,// Linear PCM, platform endian //flv_audio_codecid_ADPCM = 1,// ADPCM flv_audio_codecid_MP3 = 2,// MP3 //flv_audio_codecid_PCM_LE = 3,// Linear PCM, little endian //flv_audio_codecid_N16 = 4,// Nellymoser 16-kHz mono //flv_audio_codecid_N8 = 5,// Nellymoser 8-kHz mono //flv_audio_codecid_N = 6,// Nellymoser //flv_audio_codecid_PCM_ALAW = 7,// G.711 A-law logarithmic PCM //flv_audio_codecid_PCM_MULAW = 8,// G.711 mu-law logarithmic PCM //flv_audio_codecid_RESERVED = 9,// reserved flv_audio_codecid_AAC = 10,// AAC //flv_audio_codecid_SPEEX = 11,// Speex //flv_audio_codecid_MP3_8 = 14,// MP3 8-Khz //flv_audio_codecid_DSS = 15,// Device-specific sound};// soundSize 8bit/16bit 采样长度 压缩过的音频都是16bit 占1bittypedef NS_ENUM (NSUInteger, flv_audio_soundsize){ flv_audio_soundsize_8bit = 0,// snd8Bit flv_audio_soundsize_16bit = 1,// snd16Bit};// sound rate 5.5 11 22 44 kHz 采样率 对于AAC总是3typedef NS_ENUM (NSUInteger, flv_audio_soundrate){ flv_audio_soundrate_5_5kHZ = 0,// 5.5-kHz flv_audio_soundrate_11kHZ = 1,// 11-kHz flv_audio_soundrate_22kHZ = 2,// 22-kHz flv_audio_soundrate_44kHZ = 3,// 44-kHz};// sound type mono/stereo 对于AAC总是1 立体音typedef NS_ENUM (NSUInteger, flv_audio_soundtype){ flv_audio_soundtype_mono = 0,// sndMono flv_audio_soundtype_stereo = 1,// sndStereo};
MMS(Microsoft Media Server Protocol),中文“微软媒体服务器协议”,用来访问并流式接收 Windows Media 服务器中 .asf 文件的一种协议。MMS 协议用于访问 Windows Media 发布点上的单播内容。
MMS 是连接 Windows Media 单播服务的默认方法。若观众在 Windows Media Player 中键入一个 URL 以连接内容,而不是通过超级链接访问内容,则他们必须使用MMS 协议引用该流。MMS的预设埠(端口)是1755。
当使用 MMS 协议连接到发布点时,使用协议翻转以获得最佳连接。“协议翻转”始于试图通过 MMSU 连接客户端。 MMSU 是 MMS 协议结合 UDP 数据传送。如果 MMSU 连接不成功,则服务器试图使用 MMST。MMST 是 MMS 协议结合 TCP 数据传送。
如果连接到编入索引的 .asf 文件,想要快进、后退、暂停、开始和停止流,则必须使用 MMS。不能用 UNC 路径快进或后退。若您从独立的 Windows Media Player 连接到发布点,则必须指定单播内容的 URL。若内容在主发布点点播发布,则 URL 由服务器名和 .asf 文件名组成。例如:mms://windows_media_server/sample.asf。其中 windows_media_server 是 Windows Media 服务器名,sample.asf 是您想要使之转化为流的 .asf 文件名。
若您有实时内容要通过广播单播发布,则该 URL 由服务器名和发布点别名组成。
如例:mms://windows_media_server/LiveEvents。这里 windows_media_server 是 Windows Media 服务器名,而 LiveEvents 是发布点名。
HLS (HTTP Live Streaming)是Apple的动态码率自适应技术。主要用于PC和Apple终端的音视频服务。包括一个m3u(8)的索引文件,TS媒体分片文件和key加密串文件。
用的流媒体协议主要有 HTTP 渐进下载和基于 RTSP/RTP 的实时流媒体协议,这二种基本是完全不同的东西,目前比较方便又好用的是用 HTTP 渐进下载方法。在这个中 apple 公司的 HTTP Live Streaming 是这个方面的代表。它最初是苹果公司针对iPhone、iPod、iTouch和iPad等移动设备而开发的流.现在见到在桌面也有很多应用了,HTML5 是直接支持这个。
但是HLS协议的小切片方式会生成大量的文件,存储或处理这些文件会造成大量资源浪费。如果要实现数天的时移,索引量将会是个巨额数字,并明显影响请求速度。因此,HLS协议对存储I/O要求相当苛刻。对此,也有公司提出了非常好的解决方案。
新型点播服务器系统,独创了内存缓存数据实时切片技术,颠覆了这种传统实现方法,从根本上解决了大量切片的碎片问题,使得单台服务器的切片与打包能力不再是瓶颈。其基本原理如下:
不将TS切片文件存到磁盘,而是存在内存当中,这种技术使得服务器的磁盘上面不再会有“数以吨计”的文件碎片,极大减少了磁盘的I/O次数,延长了服务器磁盘的使用寿命,极大提高了服务器运行的稳定性。同时,由于使用这种技术,使得终端请求数据时直接从服务器的内存中获取,极大提高了对终端数据请求的反应速度,优化了视频观看体验。