流媒体协议—FLV

认识FLV


上一篇讲了HTTP在流媒体中的应用,接下来我们先把基于HTTP的HTTP-FLV和HLS两种直播中应用非常广泛的协议提一下。

先看看HTTP-FLV长成什么样子:http://ip:port/live/livestream.flv,协议头是http,另外”.flv”这个尾巴是它最明显的特征。

在流媒体尤其是直播应用中,为什么我们要如此重视HTTP-FLV呢,因为他的使用非常广泛,可以这么说,当下的直播平台中大部分的主线路使用的都是HTTP-FLV协议,备线路多为RTMP。小编随便在Safari中打开几个直播平台房间,一抓包就不难发现使用HTTP-FLV协议的身影:熊猫、斗鱼、虎牙、B站。



FLV格式


在说HTTP-FLV之前,我们有必要对FLV adobe 官方标准有个认识,因为HTTP-FLV协议中封装格式使用的是FLV。

FLV文件格式标准是写F4V/FLV fileformat spec v10.1的附录E里面的FLVFile Format。

▣  单位说明


▣  FLV 文件头和文件体 (E.2,E.3)

从整个文件上看,FLV = FLV FileHeader + FLV File Body。通常,FLV的前13个字节(flv header + PreviousTagSize0)完全相同,所以, 程序中会单独定义一个常量来指定。



▣  FLV Tag (E.4)


Timestamp和TimestampExtended组成了这个TAG包数据的PT 信息,PTS =Timestamp | TimestampExtended << 24。


▣  AudioTag (E.4.2)

由于AAC编码的特殊性, 这里着重说明了AAC编码的Tag格式。


AudioTagHeader的第一个字节,也就是接跟着StreamID的1个字节包含了音频类型,采样率等的基本信息。

AudioTagHeader之后跟着的就是AUDIODATA部分了。但是,这里有个特例,如果音频格式(SoundFormat)是 AAC,AudioTagHeader中会多出1个字节的数据AACPacketType,这个字段来表示AACAUDIODATA的类型: 0 = AAC sequence header,1 = AAC raw。

AudioSpecificConfig结构描述非常复杂,在标准文档中是用伪代码描述的,这里先假定要编码的音频格式,做一下简化。

音频编码为:AAC-LC, 音频采样率为 44100。


在FLV的文件中,一般情况下AAC sequence header这种包只出现1次, 而且是第一个audio tag,为什么需要这种tag,因为在做FLV demux的时候,如果是AAC的音频,需要在每帧AAC ES流前边添加7个字节ADST头, ADST是解码器通用的格式, 也就是说AAC的纯ES流要打包成ADST格式的AAC文件,解码器才能正常播放。就是在打包ADST的时候,需要samplingFrequencyIndex这个信息,samplingFrequencyIndex最准确的信息是在AudioSpecificConfig中,这样,你就完全可以把FLV文件中的音频信息及数据提取出来,送给音频解码器正常播放了。


▣  VideoTag (E.4.3)

由于AVC(H.264)编码的特殊性,这里着重说明了AVC(H.264编码的Tag格式。


VideoTagHeader的第一个字节,也就是接跟着StreamID的1个字节包含着视频帧类型及视频CodecID等最基本信息。

VideoTagHeader之后跟着的就是VIDEODATA部分了。但是,这里有个特例,如果视频格式(CodecID)是AVC,VideoTagHeader会多出4个字节的信息。

AVCDecoderConfigurationRecord包含着是H.264解码相关比较重要的SPS和PPS信息,在给AVC解码器送数据流之前一定要把SPS和PPS信息送出,否则的话,解码器不能正常解码。而且在解码器stop之后再次start之前, 如seek,快进快退状态切换等,都需要重新送一遍SPS和PPS的信息。AVCDecoderConfigurationRecord在FLV文件中一般情况也只出现1次, 也就是第一个video tag。

AVCDecoderConfigurationRecord长度为sizeof(UI8) * (11 +sps_size + pps_size)



▣  SCRIPTDATA (E.4.4)

ScriptTagBody内容用AMF编码。


一个SCRIPTDATAVALUE记录包含一个有类型的ActionScript值。


▣  onMetadata (E.5)

FLV metadata object保存在SCRIPTDATA中,叫onMetaData。不同的软件生成的FLV的properties不同。



▣  keyframes索引信息

官方的文档中并没有对keyframesindex做描述, 但是,flv的这种结构每个tag又不像TS有同步头,如果没有keyframes index的话,seek及快进快退的效果会非常差,因为需要一个tag一个tag的顺序读取。后来在做flv文件合成的时候,发现网上有的flv文件将keyframes信息隐藏在ScriptTag中。keyframes几乎是一个非官方的标准, 也就是民间标准。

两个常用的操作metadata的工具是flvtool2和FLVMDI,都是把keyframes作为一个默认的元信息项目。在FLVMDI的主页上有描述:


也就是说keyframes中包含着2个内容‘filepositions’和‘times’分别指的是关键帧的文件位置和关键帧的PTS。通过keyframes可以建立起自己的Index,然后在seek和快进快退的操作中,快速有效地跳转到你想要找的关键帧位置进行处理。


▣  FLV分析工具

▲  http://www.flvmeta.com/

▲  yamdi:将flv转成带索引的flv,yamdi -i i.flv -o o.flv

▲  flvlib:pip install flvlib,查看索引信息:debug-flv--metadata file.flv

▲  flvchek:http://www.adobe.com/products/adobe-media-server-family/tool-downloads.html



HTTP-FLV

我们这里说的HTTP-FLV,主要是说的是HTTP-FLV流,而不是基于HTTP的FLV视频文件点播,也不是能够随意SEEK的HTTP FLV伪流。

FLV渐进式下载:通过HTTP协议将FLV下载到播放器中播放,无法直接拉到中间去播放。

HTTP FLV伪流:支持SEEK,可从未下载的部分开始播放。

HTTP-FLV流:拥有和流式协议RTMP一样的特征,长连接,流式数据。


▣  HTTP-FLV技术实现

HTTP协议中有个content-length字段的约定,即http的body部分的长度。服务器回复http请求时如果有这个字段,客户端就接收这个长度的数据然后认为数据传输完成了,开始播放。

如果服务器回复http请求中没有这个字段,客户端就一直保持长连接接收数据,直到服务器跟客户端的socket断开。

HTTP-FLV流就利用了上述的第二个原理,服务器回复客户端请求的时候不加content-length字段,在回复了http内容之后,进行持续的数据发送,客户端就一直接收数据,以此实现了HTTP-FLV流直播。

数据传输依然是之前讲过的内容,每一个音视频数据都被封装成包含时间戳信息头的数据包,封装格式采用FLV,传输协议采用http。


▣  HTTP-FLV抓包分析

打开熊猫TV的一条直播流:

http://175.25.168.16/pl3.live.panda.tv/live_panda/d4e0a83a7e0b0c6e4c5d03774169fa3e.flv?wshc_tag=0&wsts_tag=57e233b1&wsid_tag=6a27c14e&wsiphost=ipdbm

返回信息如下:


我们发现响应头中出现Connection:close的字段,表示网宿采用的是短连接方式,直接通过服务器关闭连接来确定消息的传输长度。

还有一种实现方式,如果HTTP Header中有Content-Length,那么这个Content-Length既表示实体长度,又表示传输长度。而HTTP-FLV这种流,服务器是不可能预先知道内容大小的,这时就可以使用Transfer-Encoding:chunked模式来传输数据了。如下的响应就是采用的Chunked的方式进行的传输的响应头:



▣  HTTP-FLV延迟分析

通过http-flv的实现中不难发现,HTTP-FLV的延迟方面和RTMP能够保持一致。


▣  HTTP-FLV与其他流媒体协议的比较

当前,RTMP、HLS、HTTP-FLV是直播应用的三种主协议,说他主流,主要是因为国内所有的CDN都支持对它们的分发。这里需要注意的是,有些厂商如网宿所指的HDL,国外所称的HFL,本质上都是我们今天所讲的HTTP-FLV协议。

观止云的BMS是在国内最早支持HTTP-FLV的流媒体服务器,且相对于其他方案,观止云BMS集群内部全走RTMP,只是在边缘实时转为HTTP-FLV。如此一来系统架构更简单,稳定,且一路RTMP回源节省了不少回源流量。

❶  延迟比较

HTTP-FLV:低延迟,内容延迟可以低于3秒

RTMP:低延迟,内容延迟可以低于3秒

HLS::延迟较高,一般在10秒左右

❷  易用性比较

RTMP和HTTP-FLV:二者一样,服务端需要专门的流媒体服务器,播放端需要专门的FlashPlayer。但目前浏览器支持Flash较好,所以PC上的播放问题不大,移动端需要专门的SDK解码。

HLS:更为易用,服务端就是WEB服务器外加切片工具。播放端只要是苹果设备、HTML5平台的浏览器均可直接播放。也就是说,移动端不论是IOS还是Android,微信,朋友圈等都可以直播播放HLS直播流。

❸  RTMP和HTTP-FLV的比较:

RTMP和HTTP-FLV延迟上保持一致,在这二者的区别如下:

▲  穿墙:很多防火墙会墙掉RTMP,但是不会墙HTTP,因此HTTPFLV更不容易出问题。

▲  调度:虽然RTMP也能支持302,单实现起来较麻烦。HTTP FLV本身就支持302,更方便CDN进行重定向以便更精准的调度。

▲  容错: HTTP-FLV回源时也可以回多个源,能做到和RTMP一样,支持多级热备。

▲  简单:FLV是最简单的流媒体封装,HTTP是最广泛的协议,这两个组合在一起维护性更高,比RTMP简单。

▲  友好:HTTP-FLV代码量更小,集成SDK也更轻便。使用起来也更简单。

综上,HTTP-FLV协议具有RTMP的延迟优势,又继承了HTTP所有优势,是流媒体直播首选的分发协议。

另外,HTTP-FLV也能在推流端实现,用HTTP进行数据推流。就同样能在推流端实现上述一切优势了,只是目前国内还没有厂商实现。

你可能感兴趣的:(流媒体服务器)