如果我们想要理解 HTML5 视频,首先需要知道,你应该知道,但你不知道的内容?那怎么去判断呢? ok,很简单,我提几个问题即可,如果某些童鞋知道答案的话,可以直接跳过。
.
)这些叫做什么吗?当然,还有一些问题,我这里就不废话了。上面主要想说的其实就两个概念:视频文件格式(容器格式),视频编解码器(视频编码格式)。当然,还有另外一种,叫做音频编解码器。简而言之,就是这三个概念比较重要:
这里,我们主要讲解一下前面两个。视频一开始会由两个端采集,一个是视频输入口,是一个音频输入口。然后,采集的数据会分别进行相关处理,简而言之就是,将视频/音频流,通过一定的手段转换为比特流。最终,将这里比特流以一定顺序放到一个盒子里进行存放,从而生成我们最终所看到的,比如,mp4/mp3/flv 等等音视频格式。
视频编码格式就是我们上面提到的第一步,将物理流转换为比特流,并且进行压缩。同样,它的压缩编码格式会决定它的视频文件格式。所以,第一步很重要。针对于 HTML5 中的 video/audio,它实际上是支持多种编码格式的,但局限于各浏览器厂家的普及度,目前视频格式支持度最高的是 MPEG-4/H.264,音频则是 MP3/AC3。(下面就主要说下视频的,音频就先不谈了。)
目前市面上,主流浏览器支持的几个有:
其它格式,我们这里就不过多赘述,来看一下前两个比较有趣的。如下图:
请问,上面箭头所指的编码格式是同一个吗?
答案是:No~
因为,MPEG-4 实际上是于 1999 年提出的一个标准。而 H.264 则是后台作为优化提出的新的标准。简单来说就是,我们通常说的 MPEG-4 其实就是MPEG-4 Part 2。而,H.264 则是MPEG-4(第十部分,也叫ISO/IEC 14496-10),又可以理解为 MPEG-4 AVC。而两者,不同的地方,可以参考:latthias 的讲解。简单的区别是:H.264 压缩率比以前的 MPEG-4(第 2 部分) 高很多。简单可以参考的就是:
详细参考: 编码格式详解
视频文件格式实际上,我们常常称作为容器格式,也就是,我们一般生活中最经常谈到的格式,flv,mp4,ogg 格式等。**它就可以理解为将比特流按照一定顺序放进特定的盒子里。**那选用不同格式来装视频有什么问题吗? 答案是,没有任何问题,但是你需要知道如何将该盒子解开,并且能够找到对应的解码器进行解码。那如果按照这样看的话,对于这些 mp4,ogv,webm等等视频格式,只要我有这些对应的解码器以及播放器,那么就没有任何问题。那么针对于,将视频比特流放进一个盒子里面,如果其中某一段出现问题,那么最终生成的文件实际上是不可用的,因为这个盒子本身就是有问题的。 不过,上面有一个误解的地方在于,我只是将视频理解为一个静态的流。试想一下,如果一个视频需要持续不断的播放,例如,直播,现场播报等。这里,我们就拿 TS/PS 流来进行讲解。
针对于上面两种容器格式,实际上是对一个视频比特流做了不一样的处理。
那么结果就是,如果一个或多个盒子出现损坏,PS 格式无法观看,而 TS 只是会出现跳帧或者马赛克效应。两者具体的区别就是:对于视频的容错率越高,则会选用 TS,对视频容错率越低,则会选用 PS。
常用为:
详细参考:视频文件格式
2016 年是直播元年,一是由于各大宽带提供商顺应民意增宽降价
,二是大量资本流进了直播板块,促进了技术的更新迭代。市面上,最常用的是 Apple 推出的 HLS 直播协议(原始支持 H5 播放),当然,还有 RTMP、HTTP-FLV、RTP等。 这里,再问一个问题:
简单来说,没关系。
HLS 根本就不会涉及到视频本身的解码问题。它的存在只是为了确保你的视频能够及时,快速,正确的播放。
现在,直播行业依旧很火,而 HTML5 直播,一直以来都是一个比较蛋疼的内容。一是,浏览器厂商更新速度比较慢,二是,这并不是我们前端专攻的一块,所以,有时候的确很鸡肋。当然,进了前端,你就别想着休息。接下来,我们来详细的看一下市面上主流的几个协议。
HLS 全称是 HTTP Live Streaming。这是 Apple 提出的直播流协议。目前,IOS 和 高版本 Android 都支持 HLS。那什么是 HLS 呢? HLS 主要的两块内容是 .m3u8
文件和 .ts
播放文件。接受服务器会将接受到的视频流进行缓存,然后缓存到一定程度后,会将这些视频流进行编码格式化,同时会生成一份 .m3u8
文件和其它很多的 .ts
文件。根据 wiki 阐述,HLS 的基本架构为:
.ts
文件。并且生成一个 .m3u8
作为索引文件(确保包的顺序)playback software
(即时播放器) 进行播放。这里,我们着重介绍一下客户端的过程。首先,直播之所以是直播,在于它的内容是实时更新的。那 HLS 是怎么完成呢? 我们使用 HLS 直接就用一个 video 进行包括即可:
<video controls autoplay>
<source src="http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8" type="application/vnd.apple.mpegurl" />
<p class="warning">Your browser does not support HTML5 video.</p>
</video>
根据上面的描述,它实际上就是去请求一个 .m3u8
的索引文件。该文件包含了对 .ts
文件的相关描述,例如:
#EXT-X-VERSION:3 PlayList 的版本,可带可不带。下面有说明
#EXTM3U m3u文件头
#EXT-X-TARGETDURATION:10 分片最大时长,单位为 s
#EXT-X-MEDIA-SEQUENCE:1 第一个TS分片的序列号,如果没有,默认为 0
#EXT-X-ALLOW-CACHE 是否允许cache
#EXT-X-ENDLIST m3u8文件结束符
#EXTINF 指定每个媒体段(ts)的持续时间(秒),仅对其后面的URI有效
不过,这只是一个非常简单,不涉及任何功能的直播流。实际上,HLS 的整个架构,可以分为:
当然,如果你使用的是 masterplaylist
作为链接,如:
<video controls autoplay>
<source src="http://devimages.apple.com/iphone/samples/bipbop/masterplaylist.m3u8" type="application/vnd.apple.mpegurl" />
<p class="warning">Your browser does not support HTML5 video.</p>
</video>
我们看一下,masterplaylist 里面具体的内容是啥:
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2855600,CODECS="avc1.4d001f,mp4a.40.2",RESOLUTION=960x540
live/medium.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=5605600,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1280x720
live/high.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1755600,CODECS="avc1.42001f,mp4a.40.2",RESOLUTION=640x360
live/low.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=545600,CODECS="avc1.42001e,mp4a.40.2",RESOLUTION=416x234
live/cellular.m3u8
EXT-X-STREAM-INF
这个标签头代表:当前用户的播放环境。masterplaylist 主要干的事就是根据, 当前用户的带宽,分辨率,解码器等条件决定使用哪一个流。所以,master playlist 是为了更好的用户体验而存在的。不过,弊端就是后台储备流的量会成倍增加。 现在,我们来主要看一下,如果你使用 master playlist,那么整个流程是啥? 当填写了 master playlist URL,那么用户只会下载一次该 master playlist。接着,播放器根据当前的环境决定使用哪一个 media playlist(就是 子 m3u8 文件)。如果,在播放当中,用户的播放条件发生变化时,播放器也会切换对应的 media playlist。关于 master playlist 内容,我们就先介绍到这里。 关于 HLS,感觉主要内容还在 media playlist 上。当然,media playlist 还分为三种 list:
#EXT-X-PLAYLIST-TYPE:EVENT
作为标识。#EXT-X-ENDLIST
表示文件结尾。live playlist DEMO:
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:26
#EXTINF:9.901,
http://media.example.com/wifi/segment26.ts
#EXTINF:9.901,
http://media.example.com/wifi/segment27.ts
#EXTINF:9.501,
http://media.example.com/wifi/segment28.ts
evet playlist DEMO:
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:EVENT
#EXTINF:9.9001,
http://media.example.com/wifi/segment0.ts
#EXTINF:9.9001,
http://media.example.com/wifi/segment1.ts
#EXTINF:9.9001,
http://media.example.com/wifi/segment2.ts
VOD playlist DEMO:
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:9.9001,
http://media.example.com/wifi/segment0.ts
#EXTINF:9.9001,
http://media.example.com/wifi/segment1.ts
#EXTINF:9.9001,
http://media.example.com/wifi/segment2.ts
#EXT-X-ENDLIST
上面提到过一个 EXT-X-VERSION
这样的标签,这是用来表示当前 HLS 的版本。那 HLS 有哪些版本呢? 根据 apple 官方文档 的说明,我们可以了解到,不同版本的区别:
当然,HLS 支持的功能,并不只是分片播放(专门适用于直播),它还包括其他应有的功能。
由于 HLS 是基于 HTTP 的,所以,它关于 HTTP 的好处,我们大部分都了解,比如,高兼容性,高可扩展性等。不过正由于是 HTTP 协议,所以会在握手协议上造成一定的延迟性。HLS 首次连接时,总共的延时包括:
其中,每个 ts 文件,大概会存放 5s~10s 的时长,并且每个 m3u8 文件会存放 3~8 个 ts 文件。我们折中算一下,5 个 ts 文件,每个时长大约 8s 那么,总的下来,一共延时 40s。当然,这还不算上 TCP 握手,m3u8 文件下载等问题。那优化办法有吗?有的,那就是减少每个 m3u8 文件中的 ts 数量和 ts 文件时长,不过,这样也会成倍的增加后台承受流量请求的压力。所以,这还是需要到业务中去探索最优的配置(打个广告:腾讯云的直播视频流业务,做的确实挺棒。) 关于 HLS 的详细内容,可以参考:HLS 详解 关于 m3u8 文件的标签内容,可以参考:HLS 标签头详解 总而言之,HLS 之所以能这么流行,关键在于它的支持度是真的广,所以,对于一般 H5 直播来说,应该是非常友好的。不过,既然是直播,关键在于它的实时性,而 HLS 天生就存在一定的延时,所以,就可以考虑其他低延时的方案,比如 RTMP,HTTP-FLV。下面,我们来看一下 RTMP 内容。
RTMP 全称为:Real-Time Messaging Protocol 。它是专门应对实时交流场景而开发出来的一个协议。它爹是 Macromedia,后来卖身给了 Adobe。RTMP 根据不同的业务场景,有很多变种:
既然是 Adobe 公司开发的(算吧),那么,该协议针对的就是 Flash Video,即,FLV。不过,在移动端上,Flash Player 已经被杀绝了,那为啥还会出现这个呢?简单来说,它主要是针对 PC 端的。RTMP 出现的时候,还是 零几 年的时候,IE 还在大行其道,Flash Player 也并未被各大浏览器所排斥。那时候 RTMP 毋庸置疑的可以在视频界有自己的一席之地。
RTMP 由于借由 TCP 长连接协议,所以,客户端向服务端推流这些操作而言,延时性很低。它会将上传的流分成不同的分片,这些分片的大小,有时候变,有时候不会变。默认情况下就是,64B 的音频数据 + 128B 的视频数据 + 其它数据(比如 头,协议标签等)。但 RTMP 具体传输的时候,会将分片进一步划分为包,即,视频包,音频包,协议包等。因为,RTMP 在进行传输的时候,会建立不同的通道,来进行数据的传输,这样对于不同的资源,对不同的通道设置相关的带宽上限。
RTMP 处理的格式是 MP3/ACC + FLV1。 不过,由于支持性的原因,RTMP 并未在 H5 直播中,展示出优势。下列是简单的对比:
HTTP-FLV 和 RTMPT 类似,都是针对于 FLV 视频格式做的直播分发流。但,两者有着很大的区别。
通过上面来看,HTTP-FLV 和 RTMPT 确实不是一回事,但,如果了解 SRS(simple rtmp server),那么 对 HTTP-FLV 应该清楚不少。SRS 本质上,就是 RTMP + FLV 进行传输。因为 RTMP 发的包很容易处理,通常 RTMP 协议会作为视频上传端来处理,然后经由服务器转换为 FLV 文件,通过 HTTP-FLV 下发给用户。
现在市面上,比较常用的就是 HTTP-FLV 进行播放。但,由于手机端上不支持,所以,H5 的 HTTP-FLV 也是一个痛点。不过,现在 flv.js 可以帮助高版本的浏览器,通过 mediaSource 来进行解析。HTTP-FLV 的使用方式也很简单。和 HLS 一样,只需要添加一个连接即可:
<object type="application/x-shockwave-flash" src="http://s6.pdim.gs/static/a2a36bc596148316.flv"></object>
不过,并不是末尾是 .flv
的都是 HTTP-FLV 协议,因为,涉及 FLV 的流有三种,它们三种的使用方式都是一模一样的。
?start=xxx
的参数,指定返回的对应开始时间视频数据。该方式比上面那种就多了一个点播的功能。本质上还是 FLV 直播。上面说到,HTTP-FLV 就是长连接,简而言之只需要加上一个 Connection:keep-alive
即可。关键是它的响应头,由于,HTTP-FLV 传递的是视频格式,所有,它的 Content-Type
和 Transfer-Encoding
需要设置其它值。
Content-Type:video/x-flv
Expires:Fri, 10 Feb 2017 05:24:03 GMT
Pragma:no-cache
Transfer-Encoding:chunked
不过,一般而言,直播服务器一般和业务服务是不会放在一块的,所以这里,可能会额外需要支持跨域直播的相关技术。在 XHR2 里面,解决办法也很简单,直接使用 CORS 即可:
// 那么整个响应头,可以为:
Access-Control-Allow-credentials:true
Access-Control-Allow-max-age:86400
Access-Control-Allow-methods:GET,POST,OPTIONS
Access-Control-Allow-Origin:*
Cache-Control:no-cache
Content-Type:video/x-flv
Expires:Fri, 10 Feb 2017 05:24:03 GMT
Pragma:no-cache
Transfer-Encoding:chunked
对于 HTTP-FLV 来说,关键难点在于 RTMP 和 HTTP 协议的转换,这里我就不多说了。因为,我们主要针对的是前端开发,讲一下和前端相关的内容。
接下来,我们在主要来介绍一下 FLV 格式的。因为,后面我们需要通过 mediaSource 来解码 FLV。
FLV 原始格式,Adobe 可以直接看 flv格式详解。我这里就抽主要的内容讲讲。FLV 也是与时俱进,以前 FLV 的格式叫做 FLV,新版的可以叫做 F4V。两者的区别,简单的区分方法就是:
这里我们主要针对 FLV 进行相关了解。因为,一般情况下,后台发送视频流时,为了简洁快速,就是发送 FLV 视频。FLV 由于年限比较久,它所支持的内容是 H.263,VP6 codec。FLV 一般可以嵌套在 .swf
文件当中,不过,对于 HTTP-FLV
等 FLV 直播流来说,一般直接使用 .flv
文件即可。在 07 年的时候,提出了 F4V 这个视频格式,当然,FLV 等也会向前兼容。
这里,我们来正式介绍一下 FLV 的格式。一个完整的 FLV 流包括 FLV Header + FLV Packets。
FLV 格式头不难,就几个字段:
|Field|Data Type|Default|Details| |:—|:—|:—| |Signature|byte[3]|“FLV”|有三个B的大小,算是一种身份的象征| |Version|uint8|1|只有 0x01 是有效的。其实就是默认值| |Flags|uint8 bitmask|0x05|表示该流的特征。0x04 是 audio,0x01 是 video,0x05 是 audio+video| |Header Size|uint32_be|9|用来跳过多余的头|
在 FLV 的头部之后,就正式开始发送 FLV 文件。文件会被拆解为数个包(FLV tags)进行传输。每个包都带有 15B 的头。前 4 个字节是用来代表前一个包的头部内容,用来完成倒放的功能。整个包的结构为:
具体解释如下:
字段 | 字段大小 | 默认值 | 详解 |
---|---|---|---|
Size of previous packet | uint32_be | 0 | 关于前一个包的信息,如果是第一个包,则该部分为 NULL |
Packet Type | uint8 | 18 | 设置包的内容,如果是第一个包,则该部分为 AMF 元数据 |
Payload Size | uint24_be | varies | 该包的大小 |
Timestamp Lower | uint24_be | 0 | 起始时间戳 |
Timestamp Upper | uint8 | 0 | 持续时间戳,通常加上 Lower 实际上戳,代表整个时间。 |
Stream ID | uint24_be | 0 | 流的类型,第一个流设为 NULL |
Payload Data | freeform | varies | 传输数据 |
其中,由于 Packet Type 的值可以取多个, 需要额外说明一下。
上面是关于 FLV 简单的介绍。不过,如果没有 Media Source Extensions
的帮助,那么上面说的基本上全是废话。由于,Flash Player 已经被时代所遗弃,所以,我们不能在浏览器上,顺利的播放 FLV 视频。接下来,我们先来详细了解一下 MSE 的相关内容。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。