一文讲透音视频编解码M3U8(M3U8格式结构和解析)

一、M3U8格式

HLS(HTTPLiveStreaming)是苹果公司针对iPhone、iPod、iTouch和iPad等移动设备而开发的基于HTTP协议的流媒体解决方案。在HLS技术中Web服务器向客户端提供接近实时的音视频流。但在使用的过程中是使用的标准的HTTP协议,所以这时,只要使用HLS的技术,就能在普通的HTTP的应用上直接提供点播和直播。在AppStore中的视频相关的应用,基本都是应用的此种技术。该技术基本原理是将视频文件或视频流切分成小片(ts)并建立索引文件(m3u8)。支持的视频流编码为H.264,音频流编码为AAC。

1.1 M3U8

1.1.1 M3U8简介

m3u8,是HTTP Live Streaming直播的索引文件。m3u8基本上可以认为就是.m3u格式文件,区别在于,m3u8文件使用UTF-8字符编码。M3U8主要是可以做多码率的适配,根据网络带宽,客户端会选择一个适合自己码率的文件进行播放,保证视频流的流畅。在IOS device和mac上可以用http的方式进行分发,其中playlist标准为由m3u扩展而来的m3u8文件,媒体文件为MPEG2-TS或者AAC文件(audio only)。

m3u8文件有两种应用场景:多码率适配流和单码率适配流。

多码率适配流:

#EXTM3U
#EXT-X-STREAM-INF: PROGRAM-ID=1, BANDWIDTH=1280000
http://example.com/low.m3u8
#EXT-X-STREAM-INF: PROGRAM-ID=1, BANDWIDTH=2560000
http://example.com/mid.m3u8
#EXT-X-STREAM-INF: PROGRAM-ID=1, BANDWIDTH=7680000
http://example.com/hi.m3u8
#EXT-X-STREAM-INF: PROGRAM-ID=1, BANDWIDTH=65000, CODECS="mp4a.40.5"
http://example.com/audio-only.m3u8

单码率适配流:

#EXTM3U
#EXT-X-TARGETDURATION: 5220
#EXTINF: 5220,
http://media.example.com/entire.ts
#EXT-X-ENDLIST

1.1.2 M3U8组成

播放列表必须是扩展的M3U文件,该文档通过定义新的标签扩展了m3u文件的格式。M3U播放列表是一个文本文件,它包含了各自独立的行,行以一个LF字符或者LF字符紧跟一个CR字符来结束。行可以是一个URI,空行,或者以字符#开头。空行将会被忽略。空格只能作为一行中不同元素间的分隔。

一个URI表示一个媒体文件或是变种播放列表文件。URI可以是相对的,一个相对的URI必须被包含该URI的播放列表文件中的URI所解析。一个M3U的Playlist就是一个由多个独立行组成的文本文件,每行由回车/换行区分。每一行可以是一个URI空白行或是以“#”号开头的字符串,并且空格只能存在于一行中不同元素间的分隔。一个URI表示一个媒体段或是“variant Playlist file”(最多支持一层嵌套,即一个m3u8文件中嵌套另一个m3u8),以“#EXT”开头的。

以注释字符#开头的行可能是注释或者标签,标签以#EXT开头,表示一个“tag”,否则表示注释,直接忽略。播放列表文件的持续时间是他所指向的媒体文件的时长的总和。

播放列表文件名必须以.M3U8为后缀、HTTP Content-Type为“Application/vnd.apple.mpeg url”(如果使用http传输)或者以.M3U为后缀、HTTP Content-Type为“audio/mpeg url”。

扩展的M3U文件格式定义了两种标签:EXTM3U和EXTINF。区分扩展的M3U文件与普通M3U文件的关键在于前者的首行为#EXTM3U。

EXTINF是一个记录标记,该标记描述了后边URI所指定的媒体文件。每个媒体文件URI前边必须有EXTINF标签。格式如下:

#EXTINF:<DURATION>,<TITLE>

DURATION是一个整数,它指定了媒体文件以秒为单位的持续时间,时间应四舍五入到最接近的整数。“Durations MUST be integers if the protocol version of the Playlist file is less than 3”,否则可以是浮点数。行内逗号后边的剩余部分是媒体文件的名字,该名字是媒体分片的人眼可读的信息标题。

该文档定义了如下的新标签:

EXT-X-TARGETDURATION,
EXT-X-MEDIA-SEQUENCE,
EXT-X-KEY,
EXT-X-PROGRAM-DATE-TIME,
EXT-X-ALLOW-CATCH,
EXT-X-ENDLIST,
EXT-X-STREAM-INF,
EXT-X-DISCONTINUITY,
EXT-X-VERSION。

1.2 新标签

1.2.01 EXT-X-TARGETDURATION

该标签指定了媒体(TS)文件持续时间(duration)的最大值,播放文件列表中的媒体文件在EXTINF标签中定义的持续时间必须小于或者等于该标签指定的持续时间。该标签在整个播放列表Playlist文件中只能出现一次(在嵌套的情况下,一般有真正ts url的m3u8才会出现该tag)。其格式为:

#EXT-X-TARGETDURATION:<s> S是一个以秒为单位的整数。

1.2.02 EXT-X-MEDIA-SEQUENCE

播放列表文件中每个媒体文件(TS)的URI在m3u8文件Playlist中都有一个固定唯一的序列号。URI的序列号等于它之前那个RUI的序列号加一,即相邻之间序号+1;该序列号用于在MBR时切换码率进行对齐。EXT-X-MEDIA-SEQUENCE指明了出现在播放列表文件中的第一个URI的序列号。其格式如下:

#EXT-X-MEDIA-SEQUENCE:<Number>

播放列表文件中的EXT-X-MEDIA-SEQUENCE标签不能多于一个。如果播放列表文件中没有EXT-X-MEDIA-SEQUENCE标签,那么将会把播放列表中第一个URI的序列号当成0。

媒体文件的序列号码不是必须出现在它的URI中的。

1.2.03 EXT-X-KEY

媒体文件可能是被加密的,EXT-X-KEY提供了解密媒体文件的必要信息,用于取得16bytes的key文件解码ts文件。它的格式如下:

#EXT-X-KEY:METHOD=<method> [,URI=<uri>][,IV=<iv>]

Method属性指定了加密方法,定义了两种加密方法:NONE和AES-128。

加密方法NONE表示媒体文件不被加密,如果加密方法是NONE,那么URI和IV属性不允许存在。

加密方法AES(Advanced Encryption Standard)-128表示媒体文件使用高级加密标准128位密钥和PKCS7padding加密。如果加密方法是AES-128,key tag和URI属性共同表示了一个key文件,通过URI可以获得这个key。那么对于URI属性,如果存在,则指定获取密钥的方法;对于IV属性,如果存在,则指定使用密钥的初始化向量,将改值当成16个字节的16进制数,如果没有IV(Initialization Vector),则使用序列号作为IV进行编解码,将序列号的高位赋到16个字节的buffer中,左边补0。

IV属性出现在协议版本2中,新的EXT-X-KEY将会取代任何一个先前的EXT-X-KEY。

如果播放列表文件没有包含EXT-X-KEY标签,那么媒体文件将不会被加密。

1.2.04 EXT-X-PROGRAM-DATE-TIME

EXT-X-PROGRAM-DATE-TIME标签将下一个媒体文件的开头第一个sample和绝对日期或者时间关联起来,只对下一个media URI有效。日期/时间的表示基于ISO/IEC,并且要指明时区。例如:

#EXT-X-PROGRAM-DATE-TIME:<YYYY–MM–DDThh:mm:ssZ>。

1.2.05 EXT-X-ALLOW-CATCH

EXT-X-ALLOW-CATCH标签指定客户端是否准许缓存下载的媒体文件用来重播。它可能会出现在播放列表文件的任何地方,但是不能出现两次或以上。该标签适用于播放列表中的所有分片。其格式如下:

#EXT-X-ALLOW-CACHE:<YES|NO>

1.2.06 EXT-X-ENDLIST

EXT-X-ENDLIST标签标识没有更多媒体文件将会加入到播放列表中,它可能会出现在播放列表文件的任何地方,但是不能出现两次或以上。其格式如下:

#EXT-X-ENDLIST

livem3u8没有该tag。

1.2.07 EXT-X-STREAM-INF

EXT-X-STREAM-INF标签表示在播放列表中的下一个URI标识另一个播放列表文件。格式如下:

#EXT-X-STREAM-INF:[attribute=value][,attribute=value]*<URI>

在一个EXT-X-STREAM-INF标签中attribute不能出现两次或以上。其它属性定义:

BANDWIDTH=<n> 必须存在;n为每秒比特数,它必须是每个媒体文件比特速率的上限,必须经过计算包含那些在播放列表中出现的或者将要出现的容器开销。

PROGRAM-ID=<i> i是一个数字,在播放列表文件的范围内唯一的标识了一个Playlist文件范围内的特定的描述。

一个播放列表文件可能包含多个具有相同PROGRAM-ID的EXT-X-STREAM-INF标签来标识某个演示文稿的不同编码。这些变种的播放列表可能包含额外的EXT-X-STREAM-INF标签。

CODECS=”[format][,format]*” 不是必须的;每一种格式都指定了存在于媒体文件中的媒体类型。合法的格式标示符都是那些在ISO文件格式名称空间被RFC4281定义的格式。

RESOLUTION=<N>x<M> N是流中视频水平编码分辨率的近似,以像素数表示,M是编码垂直分辨率的近似。

AUDIO:这个值必须和AUDIO类别的“EXT-X-MEDIA”标签中“GROUP-ID”属性值相匹配。

VIDEO:同上

1.2.08 EXT-X-DISCONTINUITY

EXT-X-DISCONTINUITY标签表示该标签后边的媒体文件和之前的媒体文件之间的编码间断。当遇到该tag的时候说明以下属性发生了变化,特性可能改变的一组是:

File format
Number and type of tracks
Encoding parameters
Encoding sequence

1.2.09 EXT-X-VERSION

EXT-X-VERSION标签指出了播放列表版本的适应性。播放列表文件、其关联的媒体和服务器必须遵守最新版本的所有规定。

1.2.10 EXT-X-BYTERANGE

EXT-X-BYTERANGE:表示媒体段是一个媒体URI资源中的一段,只对其后的media URI有效,格式如下:

#EXT-X-BYTERANGE:<n>[@o]:

其中n表示这个区间的大小,o表在URI中的offset;”The EXT-X-BYTERANGE tag appeared in version 4 of the protocol“。

1.2.11 EXT-X-PLAYLIST-TYPE

# EXT-X-PLAYLIST-TYPE:提供关于Playlist的可变性的信息,这个对整个Playlist文件有效,是可选的,格式如下:

#EXT-X-PLAYLIST-TYPE:<EVENT|VOD>:如果是VOD,则服务器不能改变Playlist文件;如果是EVENT,则服务器不能改变或是删除Playlist文件中的任何部分,但是可以向该文件中增加新的一行内容。

1.3 M3U8举例

下文是M3U8格式的举例:


#EXTM3U
#EXT-X-TARGETDURATION:15
#EXTINF:7,http://data.video.qiyi.com/videos/movie/20111225/f9eb21f9247aafb04b39cc5bba13afa1.ts?start=0&end=658512&hsize=5343&tag=0&v=7620766549&contentlength=229360
#EXTINF:14,http://data.video.qiyi.com/videos/movie/20111225/f9eb21f9247aafb04b39cc5bba13afa1.ts?start=1712&end=2720295&hsize=5343&tag=1&v=7620766549&contentlength=1544984
#EXTINF:10,http://data.video.qiyi.com/videos/movie/20111225/f9eb21f9247aafb04b39cc5bba13afa1.ts?start=658512&end=3785637&hsize=5343&tag=1&v=7620766549&contentlength=1082880
//省略...
 #EXT-X-DISCONTINUITY
#EXTINF:9,http://data.video.qiyi.com/videos/movie/20111225/f2eab9af69495077eea62a17029b0c9b.ts?start=0&end=836062&hsize=14301&tag=0&v=7620766549&contentlength=408148
#EXTINF:10,http://data.video.qiyi.com/videos/movie/20111225/f2eab9af69495077eea62a17029b0c9b.ts?start=1748&end=1489908&hsize=14301&tag=1&v=7620766549&contentlength=493500
#EXTINF:10,http://data.video.qiyi.com/videos/movie/20111225/f2eab9af69495077eea62a17029b0c9b.ts?start=377373&end=2159598&hsize=14301&tag=1&v=7620766549&contentlength=694660
//省略...
#EXT-X-ENDLIST

这就是简略的M3U8文件。其中要注意#EXTINF:[int/double],表示这个片段的总时长,这个字段很关键,可以通过它查找跳转位置的TS片段;#EXT-X-DISCONTINUITY,表示一个新的时间点开始,也就是说数据流的时间戳从此刻开始从0开始。那你可要准备好换算了,否则IMediaSeeking::SetPositions可就找不见了哦。当然有部分M3U8没有这个字段,大部分是影片总长度比较小的,也存在例外情况。

注意:最好将时间列表和ts地址列表分离开来,使用起来会更方便因为大部分时候是多线程的情况。

2 M3U8 结构

2.1 M3U8总体结构

M3U8分顶级M3U8和二级M3U8,顶级M3U8主要是做多码率适配的,二级M3U8才是真正的切片文件;客户端默认会优先选择码率最高的请求;如果发现码率达不到,会请求较低码率的流。

2.2 顶级M3U8

一个实际使用中的顶级M3U8文件如下:


#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=201975244867,BANDWIDTH=358400
test1.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=201975244869,BANDWIDTH=972800
test2.m3u8

上面顶级M3U8文件中又定义了11.m3u8和22.m3u8两个二级文件,客户端会选择其中一个获取其内容。

2.3 二级M3U8

二级M3U8文件内容如下:


#EXTM3U
#EXT-X-VERSION:1
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:3,
1-4.ts
#EXTINF:8,
1-6.ts
#EXTINF:8,
1-8.ts
#EXTINF:8,
1-10.ts
#EXTINF:8,
1-12.ts
#EXTINF:8,
1-14.ts
#EXTINF:8,
1-16.ts
#EXTINF:9,
1-18.ts
#EXTINF:6,
1-20.ts
#EXTINF:8,
1-22.ts
#EXTINF:9,
1-24.ts
#EXTINF:3,
1-26.ts
#EXT-X-ENDLIST

客户端拿到上面的二级M3U8文件后,会继续请求里面的文件,这时就可进行播放了。上面讲解的是点播的情况;而直播的情况,M3U8文件里面会有属性(那个属性?)告诉是直播,客户端会定时来请求新的M3U8文件。

三、M3U8解析

3.1 M3U8地址解析

不论是点播还是直播,重要的部分不外乎都是数据源和数据播放两个方面。对于播放没什么特殊性,现在针对直播的特殊地方,M3U8的解析进行简要说明。

通过CCTV-4的网络直播地址进行分析cctvksh5ca.v.kcdnvip.com 。通过上个地址可以获得如下的内容:


#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=8,BANDWIDTH=600000
/live/cdrmcctv4_1/index.m3u8?BR=md&region=beijing
#EXT-X-STREAM-INF:PROGRAM-ID=8,BANDWIDTH=900000
/live/cdrmcctv4_1/index.m3u8?BR=hd&region=beijing
#EXT-X-STREAM-INF:PROGRAM-ID=8,BANDWIDTH=1350000
/live/cdrmcctv4_1/index.m3u8?BR=ud&region=beijing
#EXT-X-STREAM-INF:PROGRAM-ID=8,BANDWIDTH=1800000
/live/cdrmcctv4_1/index.m3u8?BR=td&region=beijing

其中EXT-X-STREAM-INF字段,说明了关于所属下载地址的相关信息。当然有些字段需要,有些字段不需要,依据具体需求而定。而这里主要利用了BANDWIDTH,默认选取其中最高的一个。

接下来我们通过CCTV4中提供的数据链接获取地址为例。cctvcnchwh5c.v.cdn20.com,获取到一下内容:


#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:159745587

#EXTINF:10.077,
/live/cdrmcctv4_1_600/122697.ts?wsApp=HLS&wsMonitor=0
#EXTINF:10.716,
/live/cdrmcctv4_1_600/122698.ts?wsApp=HLS&wsMonitor=0
#EXTINF:9.596,
/live/cdrmcctv4_1_600/122699.ts?wsApp=HLS&wsMonitor=0
#EXTINF:9.757,
/live/cdrmcctv4_1_600/122700.ts?wsApp=HLS&wsMonitor=0

其中#EXTINF:10.077,/live/cdrmcctv4_1_600/122697.ts,标记了一个TS下载片段和时长。还需注意就是#EXT-X-MEDIA-SEQUENCE:159745587,这个字段标记了此M3U8下载的片段的序号。以上为了分别是159745587,159745588,159745589,159745590,相应序号。为了防止出现记录下载列表出现片段冲突的情况,最好在数据结构里定义序列号。通过频繁的刷新片可以不间断的获取到实时TS片段的下载地址,并不断的将其存放在队列中。

注意以下下几点问题:

1、不要将片段在队列中冲突了。

2、一定要将#EXT-X-STREAM-INF字段进行解析过程和片段解析过程放到一起,因为有时服务器会突然更换下载片段M3U8地址。

3、注意一次m3u8获取到的片段个数,从而得到一次获取到的总的播放时长。进而安排好程序下次刷新的时间间隔。

4、一定要设定下载的超时时间,不能无限等待。拿不到的片段,果断丢弃。

5、片段序号总有一个时间点上会被归为0或1(不同的源不一样),提前处理做好准备。

在上一篇文章中讲述了网络直播电视的M3U8解析和其中的关键字段。本章我将对我遇见到的不同数据源的M3U8文件进行列举和分析。

3.1.1 文件名

第一种:ts片段地址为文件名称,下载地址为:http:\\XXX.com\01\XX\1.m3u8


#EXTM3U
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:67835
#EXTINF:8,
20190815T182851-04-67835.ts
#EXTINF:8,
20190815T182851-04-67836.ts
#EXTINF:8,
20190815T182851-04-67837.ts
#EXTINF:8,
20190815T182851-04-67838.ts
#EXTINF:8,
20190815T182851-04-67839.ts
#EXTINF:8,
20190815T182851-04-67840.ts
#EXTINF:8,
20190815T182851-04-67840.ts
#EXTINF:8,
20190815T182851-04-67840.ts

那么要获取到20190815T182851-04-67840.ts片段绝对路径地址就需要添加文件目录信息,其路径为:http:\\XXX.com\01\XX\20190815T182851-04-67835.ts。

类似情况,如下:

#EXTM3U#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:3
#EXT-X-MEDIA-SEQUENCE:6198
#EXTINF:3,aac749f7425bf07f_13b4b0fd1b7_6198.ts?wsApp=HLS&wsMonitor=-1&wsHost=rtmp.cntv.lxdns.com
#EXTINF:3,aac749f7425bf07f_13b4b0fe1b8_6199.ts?wsApp=HLS&wsMonitor=-1&wsHost=rtmp.cntv.lxdns.com
#EXTINF:3,aac749f7425bf07f_13b4b0ffa08_6200.ts?wsApp=HLS&wsMonitor=-1&wsHost=rtmp.cntv.lxdns.com

3.1.2 目录

第二种:ts片段地址为目录结构,下载地址为:http:\\XXX.com\01\XX\1.m3u8。

#EXTM3U
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:9190381
#EXTINF:10,
/timeshift/63/20191129165010.ts
#EXTINF:10,
/timeshift/63/20191129165020.ts
#EXTINF:10,
/timeshift/63/20191129165030.ts

那么获取到/timeshift/63/20191129165010.ts片段地址就为:http:\\XXX.com\01\XX/timeshift/63/20191129165010.ts。

3.1.3 重叠目录

第三种:ts片段地址为目录结构,但是和m3u8下载地址目录重叠。下载地址为:http:\\XXX.com\01\timeshift\63\1.m3u8。

#EXTM3U
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:9190381
#EXTINF:10,
/timeshift/63/20191129165010.ts
#EXTINF:10,
/timeshift/63/20191129165020.ts
#EXTINF:10,
/timeshift/63/20191129165030.ts

将冲突的目录剔除,那么获取到/timeshift/63/20191129165010.ts片段地址就为http:\\XXX.com\01\XX/timeshift/63/20191129165010.ts。

3.1.4 片段地址

第四种:ts片段地址为完整的片段下载地址,下载地址为:http:\\XXX.com\01\XX\1.m3u8。


#EXTM3U
#EXT-X-ALLOW-CACHE:NO
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:6297202
#EXTINF:10,
http://202.108.17.170:80/ipad/160_12784_1758/20191127185340.ts?userid=2221281760225887_160_12784_1758
#EXTINF:10,
http://202.108.17.170:80/ipad/160_12784_1758/20191127185350.ts?userid=2221281760225887_160_12784_1758
#EXTINF:10,
http://202.108.17.170:80/ipad/160_12784_1758/20191127185400.ts?userid=2221281760225887_160_12784_1758

这种情况下下载地址就不需要拼接了。

直播不同的数据得到的片段下载地址也就基本维持这四种情况,当然也难免存在其他的情况,需要具体情况具体分析。

3.2 总结

1、“http”开头的一定是全下载地址,不需要进行拼接处理的。如果碰到“HTTP”或“Http”等等情况,需要先转成小写在进行匹配,当然下载地址的http还需为小写。

2、带有目录结构的源,同样有些或是这样的“timeshift/63/2019129165020.ts”,前面不带“/”。

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/yinshipin/11115.html

(0)

相关推荐

发表回复

登录后才能评论