英国·阿什顿庭院庄园
(本文基本逻辑:M3U8 封装格式概览 → M3U8 格式解析 → M3U8 封装示例)
M3U 文件是一种纯文本文件,可以指定一个或多个多媒体文件的位置。它的设计初衷是为了播放音频文件,但后来越来越多的用于播放视频文件列表。而 M3U8 则是用 UTF-8 编码的 M3U。M3U、M3U8 文件都是苹果公司使用的 HLS(HTTP Live Streaming) 协议的基础。
在实际应用场景中,由于 HLS/M3U8/TS 这套方案在控制直播延时上不太理想,所以一般实时直播场景不会选择使用 M3U8 媒体格式。但是,对于直播回放这种场景,由于使用 M3U8/TS 这套方案能够在直播过程中就持续生成和存储切片,所以直播回放基本上都会选择 M3U8 媒体格式。
1、M3U8 格式概览
M3U8 文件其实是一个播放列表,这个列表可能是一个媒体播放列表(Media Playlist),也可能是一个主播放列表(Master Playlist)。但无论是哪种播放列表,其内部文字使用的都是 utf-8 编码。
1.1、媒体播放列表
当 M3U8 文件作为媒体播放列表(Meida Playlist)时,其包含的信息记录的是一系列多媒体资源切片,顺序播放这些切片,即可完整呈现多媒体资源。
第一行的 #EXTM3U
表示文件格式。第二行的 #EXT-X-TARGETDURATION:10
表示后面的各个资源切片时长都小于或等于 10 秒。接下来,我们看到有 3 个资源切片,时长分别是 9.009 秒、9.009 秒、3.003 秒。
在点播时,客户端首先下载 M3U8 文件,然后按照 M3U8 列表下载各个资源切片依次播放即可。在直播时,客户端则需要定时重新请求 M3U8 文件,从而检查是否有新的媒体切片需要进行下载播放。所有的这些数据都通过 HTTP 协议传输。
1.2、主播放列表
当 M3U8 文件作为主播放列表(Master Playlist)时,其包含的信息是同一个媒体资源的多路流资源列表。不同的流可能有着不同的码率,不同的格式,不同的分辨率。不同的流也可以指定不同语言的音频,不同视角的视频等等。
客户端应该根据网络状况来选择合适的流来播放,也应该根据用户的偏好来选择合适的语言和视角的流来播放。
2、M3U8 格式解析
这里讲的播放列表文件主要是指 HLS 协议所使用的播放列表文件,该文件的格式主要包含下面几方面的内容:
- 格式规范
- 属性列表
- 标签
2.1、格式规范
M3U8 播放列表文件必须以 UTF-8 进行编码,不能包含任何 Byte Order Mark(BOM)内容,并且除了 CR(U 000D) 和 LF(U 000A) 之外不能包含任何 UTF-8 控制字符 (U 0000 ~ U 001F 及 U 007F ~ U 009F)。并且,所有的字符序列必须遵循 Unicode 规范。
M3U8 播放列表文件的每一行要么是一个 URI,要么是空行,要么是以 #
开头的字符串。空行会被忽略,除了显式声明的元素,不能出现空白字符。
以 #
开头的字符串要么是注释,要么是标签。标签以 #EXT
开头,大小写敏感。以 #
开头的注释在解析时应该忽略。
如果 M3U8 文件是一个媒体播放列表(Meida Playlist),那么每个 URI 对应的都是一个媒体切片;如果 M3U8 文件是一个主播放列表(Master Playlist),那么每个 URI 对应的是一个媒体播放列表。其他表示都是不正确的。
一个媒体播放列表的时长等于它包含的所有媒体切片时长的总和。
每个媒体切片的码率等于切片的大小除以它的时长。需要注意的是,这里及后面码率的计算包含了除了音视频数据外的容器数据,但是不包含各种传输协议(HTTP、TCP、IP)头所占用的数据。
一个媒体播放列表的最高码率是所有切片中码率的最大值,但这里的切片需要满足条件:时长是 #EXT-X-TARGETDURATION
指定值的 0.5 ~ 1.5 倍的连续切片。
一个媒体播放列表的平均码率是所有切片的大小之和(单位:bit)除以播放列表的时长。
2.2、属性列表
属性列表是一组可以设置值的特定标签,它们对应的是一个个的键值对,语法如下:
代码语言:javascript复制AttributeName=AttributeValue
代码语言:javascript复制这里的属性名和属性值都不能包含空白字符。属性名允许的字符集是 [A..Z] [0..9] -。一个属性名只能出现一次。属性值也需要遵循一定的规范。
2.3、标签
播放列表的标签用于指定文件的全局信息,或者指定跟在其后的媒体切片或媒体播放列表的相关信息。
2.3.1、基础标签(Basic Tags)
基础标签(Basic Tags)可以在媒体播放列表(Media Playlist)和主播放列表(Master Playlist)中使用。
EXTM3U
,表示文件继承自 M3U 标准。这个标签必须放在文件第一行。EXT-X-VERSION
,表示文件的版本,这个与文件相关的媒体和服务器相关。- 语法:
#EXT-X-VERSION:<n>
- 语法:
2.3.2、媒体切片标签(Media Segment Tags)
每个切片 URI 前面都有一组媒体切片标签(Media Segment Tags)对其进行描述。有一些媒体切片标签只对跟在其后的一个媒体切片相关;有的则与其后的所有切片都相关,直到后面遇到另一个该标签的描述。
媒体切片标签不能出现在主播放列表(Master Playlist)中。
EXTINF
,表示其后媒体切片的时长(单位为秒)。每个媒体切片之前必须指定该标签。- 语法:
#EXTINF:<duration>,[<title>]
- 语法:
EXT-X-BYTERANGE
,表示指定媒体切片是其后 URI 指定的媒体资源的一部分。- 语法:
#EXT-X-BYTERANGE:<n>[@<o>]
- 说明:其中 n 表示字节大小,o 表示起始位置。如果指定了 o 值,则表示对 URI 指定资源从 o 指定的位置开始截取 n 字节;如果 o 未指定,则表示把上一个该标签指定的媒体资源作为目标,将其已截取片段的下一个字节作为起始位置开始再截取 n 字节。如果没有指定该标签,则表明切片范围为整个 URI 指定的媒体资源。该标签兼容的版本是 EXT-X-VERSION 为 4 及以上。
- 语法:
EXT-X-DISCONTINUITY
,表示其前一个切片和下一个切片之间存在中断。在媒体文件格式、媒体轨道的数量和类型、时间戳序列、编码参数、编码序列的内容发生变化时,需要使用该标签。EXT-X-KEY
,媒体切片是可以加密的,这个标签用来指定解密方法。- 语法:
#EXT-X-KEY:<attribute-list>
- 说明:一般一个媒体播放列表中会出现 2 个以上的 EXT-X-KEY 标签,一个 EXT-X-KEY 标签作用于包含在它和下一个具有同样 KEYFORMAT 属性值的 EXT-X-KEY 标签之间的所有切片。
- 语法:
EXT-X-MAP
,指定了如何获取媒体初始化信息(Meida Initialization Section)来解析后续的媒体切片数据。该标签对其后所有切片生效,直到遇到下一个EXT-X-MAP
标签。URI
,这个字段是必须的,该 URI 指向包含媒体初始化信息(Meida Initialization Section)资源。BYTERANGE
,该字段是可选的,表示上面 URI 指向的资源中媒体初始化信息(Meida Initialization Section)的精确字节位置。如果没有该字段,则表示该资源所有的数据都是目标数据。- 语法:
#EXT-X-MAP:<attribute-list>
,这里的属性列表包括如下字段:
EXT-X-PROGRAM-DATE-TIME
,使用了一个绝对的时间来指定媒体切片第一个采样的时间。这个标签只作用于其后的一个切片。- 语法:
#EXT-X-PROGRAM-DATE-TIME:<date-time-msec>
- 语法:
EXT-X-DATERANGE
,用于将一个时间范围和一组属性关联起来。
2.3.3、媒体播放列表标签(Media Playlist Tags)
媒体播放列表标签(Media Playlist Tags)主要用来描述全局的媒体信息。
EXT-X-TARGETDURATION
,表示所有媒体切片的最大时长,单位是秒。这个标签是必填的。EXTINF
所指定的各个切片的时长必须不大于这个时长,否则会出现播放卡顿或播放错误。- 语法:
#EXT-X-TARGETDURATION:<s>
- 语法:
EXT-X-MEDIA-SEQUENCE
,表示列表文件中第一个媒体切片的序号。如果没有这个标签,那么表示第一个媒体切片的序号为 0。每个媒体切片都有唯一的序列号,序列号按照出现顺序依次加 1。此外,如果有这个标签,那么这个标签需要放在第一个切片之前。- 语法:
#EXT-X-MEDIA-SEQUENCE:<number>
- 语法:
EXT-X-DISCONTINUITY-SEQUENCE
,该标签用于同步相同流的不同路或者有 EXT-X-DISCONTINUITY 标签的不同备份流。该标签必须出现在第一个切片之前,且必须出现在任何 EXT-X-DISCONTINUITY 标签之前。- 语法:
#EXT-X-DISCONTINUITY-SEQUENCE:<number>
- 语法:
EXT-X-ENDLIST
,表示不会再有更多的切片会添加到播放列表中。该标签可以出现在媒体播放列表的任意位置,一般出现在文件结尾。- 语法:
#EXT-X-ENDLIST
- 语法:
EXT-X-PLAYLIST-TYPE
,该标签表明了全局播放列表的可变性。这个标签是可选的,作用于整个播放列表。该标签如果被省略,则媒体播放列表是可以修改的。- 语法:
#EXT-X-PLAYLIST-TYPE:<EVENT|VOD>
- 说明:
EVENT
表示可以在播放列表可变,不过只能在尾部添加媒体切片;VOD
表示播放列表不可变。
- 语法:
EXT-X-I-FRAMES-ONLY
,该标签表示每个媒体切片都是 I 帧。该标签作用于整个播放列表。- 语法:
#EXT-X-I-FRAMES-ONLY
- 说明:在包含 EXT-X-I-FRAMES-ONLY 切片的播放列表中,每个切片的时长(EXTINF)表示当前 I 帧开始到下一个 I 帧开始的时间。媒体资源如果是 I 帧切片,那么必须在开始位置提供 Media Initialization Section 信息或者通过 EXT-X-MAP 标签提供 Media Initialization Section 的获取路径,这样客户端就在任意位置以任意顺序来对这些 I 帧进行解码。如果 I 帧切片设置了 EXT-X-BYTERANGE 标签,那么它对应的数据长度一定不能包含 Media Initialization Section 的数据长度。客户端可以认为 Media Initialization Section 信息是定义在 EXT-X-MAP 标签中的,或者它的位置是从切片起始的位置开始到第一个 I 帧起始的位置结束。兼容 EXT-X-I-FRAMES-ONLY 要求文件版本号 EXT-X-VERSION 大于等于 4。
- 语法:
2.3.4、主播放列表标签(Master Playlist Tags)
主播放列表标签(Master Playlist Tags)主要用于定义多路流以及其他全局参数。主播放列表标签不能出现在媒体播放列表中。
EXT-X-MEDIA
,该标签用于指定具有相同内容的不同路的流,这些流可能是有不同的音视频参数,或者是对应不同的语言翻译。比如,我们可以通过 3 个 EXT-X-MEDIA 标签来给一个媒体资源分别指定英语、法语、西班牙语的音频内容;我们也可以通过 2 个 EXT-X-MEDIA 标签给一个媒体资源指定两种不同的拍摄视角。TYPE
,资源类型。必填字段,可选值有:AUDIO
、VIDEO
、SUBTITLES
、CLOSED-CAPTIONS
。一般隐藏式字幕(CLOSED-CAPTIONS)是跟着视频数据的,不会专门指定一路流。URI
,资源地址。可选字段,如果 TYPE 是 CLOSED-CAPTIONS,则不要出现这个字段。GROUP-ID
,分组标识。必填字段,用于指定资源属于哪个组。LANGUAGE
,指定资源主要使用的语言。可选字段。ASSOC-LANGUAGE
,指定资源使用的语言的一个版本,常用来指定语言的书写、方言等特效。可选字段。NAME
,用于填写名字,目的是易读。必填字段。DEFAULT
,表示当前资源是否是默认播放资源。可选字段,默认值是 NO。AUTOSELECT
,可选字段,默认值为 NO。当该值为 YES,当用户没有指定偏好时,则默认播放这个资源。如果有该字段,并且 DEFAULT 值为 YES 时,该值必须为 YES。FORCED
,可续字段,默认值为 NO。只有当 TYPE 值为 SUBTITLES 时,才能出现该字段。当该值为 YES,表示资源中包含了重要的内容,客户端应该从中选择最符合当前播放环境的资源来播放。INSTREAM-ID
,只有当 TYPE 为 CLOSED-CAPTIONS 才出现该字段,且必须出现。CHARACTERISTICS
,可选字段。CHANNELS
,当 TYPE 为 AUDIO,该字段表示音频轨道数。- 语法:
#EXT-X-MEDIA:<attribute-list>
,其中这里的属性列表包括: - 说明:同一组的资源都有同样的 GROUP-ID 和同样的 TYPE,同一组的不同路流必须对应的是统一的内容,否则播放可能会出错。一个播放列表的所有 EXT-X-MEDIA 的 NAME 属性都必须各不相同。同一组中只能有一个 DEFAULT 属性为 YES 的 EXT-X-MEDIA。AUTOSELECT 为 YES 的不同 EXT-X-MEDIA 必须能通过 LANGUAGE、ASSOC-LANGUAGE、FORCED、CHARACTERISTICS 属性组做出区分。
EXT-X-STREAM-INF
,该标签用于指定媒体资源的具体信息。BANDWIDTH
,表示流的最高码率(Peak Segment Bit Rate),包含了所有需要播放的媒体资源的码率加和。必填字段。AVERAGE-BANDWIDTH
,表示流的平均码率。可选字段。CODECS
,表示编码器。应该尽量包含该字段。RESOLUTION
,表示分辨率。可选字段。FRAME-RATE
,表示帧率。可选字段。但是包含视频的资源都应该尽量包含该信息。HDCP-LEVEL
,表示数字内容保护。可选字段。AUDIO
,对应某个 TYPE 为 AUDIO 的 EXT-X-MEDIA 标签的 GROUP-ID 字段。表示音频应该使用对应组的资源。可选字段。VIDEO
,对应某个 TYPE 为 VIDEO 的 EXT-X-MEDIA 标签的 GROUP-ID 字段。表示视频应该使用对应组的资源。可选字段。SUBTITLES
,对应某个 TYPE 为 SUBTITLES 的 EXT-X-MEDIA 标签的 GROUP-ID 字段。表示字幕应该使用对应组的资源。可选字段。CLOSED-CAPTIONS
,对应某个 TYPE 为 CLOSED-CAPTIONS 的 EXT-X-MEDIA 标签的 GROUP-ID 字段。表示隐藏字幕应该使用对应组的资源。可选字段。- 语法:
#EXT-X-STREAM-INF:<attribute-list> <URI>
,URI 是换行。这里的属性列表包括:
EXT-X-I-FRAME-STREAM-INF
,表示一个包含 I 帧的媒体播放列表。这个标签是独立的,不作用于主播放列表里的其他资源。该标签主要服务于播放时的快进和快退功能。URI
,对应一个只包含 I 帧的媒体播放列表。该列表中必须包含 EXT-X-I-FRAMES-ONLY 标签。- 语法:
#EXT-X-I-FRAME-STREAM-INF:<attribute-list>
,属性列表包含了上文所讲的 EXT-X-STREAM-INF 标签除了 FRAME-RATE、AUDIO、SUBTITLES、CLOSED-CAPTIONS 外的各属性,同时再增加下列属性: - 说明:每个 EXT-X-I-FRAME-STREAM-INF 必须包含 BANDWIDTH 和 URI 属性。对于主列表中包含的多路流,则应该对应多路 I 帧媒体播放列表,且为它们设置同样的 NAME 和 LANGUAGE 属性。
EXT-X-SESSION-DATA
,该标签允许在主播放列表中携带任意的会话数据。DATA-ID
,ID 最好遵循类似com.example.movie.title
格式。必填字段。VALUE
,数据值。VALUE 字段和 URI 字段二选一。URI
,数据地址,应该指向一个 JSON 文件。VALUE 字段和 URI 字段二选一。LANGUAGE
,语言。可选字段。- 语法:
#EXT-X-SESSION-DATA:<attribute-list>
,属性列表包括: - 说明:一个主播放列表可以包含多个有同样 DATA-ID 的 EXT-X-SESSION-DATA 标签,但是不能包含一个以上的有同样 DATA-ID 和 LANGUAGE 的 EXT-X-SESSION-DATA 标签。
EXT-X-SESSION-KEY
,该标签允许将加密秘钥放在主播放列表中,这样客户端可以预先加载主播放列表类提取获取到加密秘钥,而不用非要加载媒体播放列表来获取。- 语法:
#EXT-X-SESSION-KEY:<attribute-list>
- 语法:
2.3.5、播放列表共用标签(Media or Master Playlist Tags)
有一些标签是媒体播放列表和主播放列表中都可以出现的,但是一般一个标签出现在主播放列表,那么就不要再在该主播放列表索引的媒体播放列表中出现了。如果一定要两边都出现,那么标签对应的值必须相同,否则客户端应该忽略媒体播放列表的值,采用主播放列表的值。在同一个播放列表中,这些标签一定不能出现多次。
EXT-X-INDEPENDENT-SEGMENTS
,表明列表中的所有切片都可以独立解码,无需依赖其他切片的信息。- 语法:
#EXT-X-INDEPENDENT-SEGMENTS
。 - 说明:如果该标签出现在主播放列表,则适用于主播放列表包含的所有媒体播放列表。
- 语法:
EXT-X-START
,表明倾向于从哪个时间点开始播放。TIME-OFFSET
,表示开始时间偏移,必填字段。如果是正数,则表示距离播放开始时间的偏移,此时如果绝对值超过了视频总时长则表示偏移到结束时间;如果是负数,则表示是距离播放结束时间的偏移,此时如果绝对值超过了视频总时长则表示偏移到开始时间。如果播放列表不包含 EXT-X-ENDLIST 标签,则 TIME-OFFSET 的值不应该在播放列表末尾的 3 个切片的时长之内。PRECISE
,表示是否精确,可选字段。默认是 NO。如果设置该值为 YES,则客户端应该播放时间包含 TIME-OFFSET 的切片,并且不要渲染该切片内时间在 TIME-OFFSET 之前的采样;如果该值为 NO,则渲染切片内所有的采样。- 语法:
#EXT-X-START:<attribute-list>
,属性列表包括:
3、实战解析
1)一个点播媒体播放列表:
代码语言:javascript复制#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXTINF:9.009,
http://media.example.com/first.ts
#EXTINF:9.009,
http://media.example.com/second.ts
#EXTINF:3.003,
http://media.example.com/third.ts
#EXT-X-ENDLIST
M3U8 文件支持绝对路径,也支持相对路径,所以上面的格式等效于:
代码语言:javascript复制#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXTINF:9.009,
first.ts
#EXTINF:9.009,
second.ts
#EXTINF:3.003,
third.ts
#EXT-X-ENDLIST
上面的示例是一个典型的点播媒体播放列表,主要特征是:
- 文件包含
EXT-X-ENDLIST
标签。 EXT-X-PLAYLIST-TYPE
标签(可选)值为 VOD,表示播放列表不可变。
2)一个 EVENT 播放列表:
刚开始时,对应的 M3U8 文件内容如下所示:
代码语言:javascript复制#EXTM3U
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10,
fileSequence0.ts
#EXTINF:10,
fileSequence1.ts
#EXTINF:10,
fileSequence2.ts
#EXTINF:10,
fileSequence3.ts
EVENT 播放列表的主要特征是:
EXT-X-PLAYLIST-TYPE
标签值为 EVENT,表示播放列表内容可变,不过只能在文件末尾改变。
结束时,M3U8 文件内容如下所示:
代码语言:javascript复制#EXTM3U
#EXT-X-PLAYLIST-TYPE:EVENT
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10,
fileSequence0.ts
#EXTINF:10,
fileSequence1.ts
#EXTINF:10,
fileSequence2.ts
#EXTINF:10,
fileSequence3.ts
...
#EXTINF:10,
fileSequence120.ts
#EXTINF:10,
fileSequence121.ts
#EXT-X-ENDLIST
EVENT 播放列表可以用在直播中,通常用于晚会和体育赛事场景,用户一方面可以观看直播,一方面还能做 seek 操作回退到之前的时间点去回放。
3)一个直播播放列表:
直播过程中某个时间点的 M3U8 文件内容:
代码语言:javascript复制#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:2680
#EXTINF:7.975,
https://priv.example.com/fileSequence2680.ts
#EXTINF:7.941,
https://priv.example.com/fileSequence2681.ts
#EXTINF:7.975,
https://priv.example.com/fileSequence2682.ts
M3U8 文件可以使用 HTTP,也可以使用 HTTPS。
直播播放列表的主要特征:
- 不包含
EXT-X-ENDLIST
标签。 - 不包含
EXT-X-PLAYLIST-TYPE
标签。
直播播放列表是一个会动态更新的 M3U8 文件,服务端会对直播流进行实时转码生成直播流切片,并定期更新 M3U8 文件。这个 M3U8 文件一般为会包括 3-5 个切片。
直播播放列表中的任意一个切片的 URI 被移除时,都需要更新 EXT-X-MEDIA-SEQUENCE
标签的值( 1)。移除切片 URI 时必须按顺序,以保证客户端通过更新的 M3U8 文件拿到的是连续的切片数据。
当上面的实例更新一个切片后,M3U8 文件内容更新为:
代码语言:javascript复制#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:2681
#EXTINF:7.941,
https://priv.example.com/fileSequence2681.ts
#EXTINF:7.975,
https://priv.example.com/fileSequence2682.ts
#EXTINF:7.971,
https://priv.example.com/fileSequence2683.ts
4)一个加密的媒体播放列表:
代码语言:javascript复制#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:7794
#EXT-X-TARGETDURATION:15
#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"
#EXTINF:2.833,
http://media.example.com/fileSequence52-A.ts
#EXTINF:15.0,
http://media.example.com/fileSequence52-B.ts
#EXTINF:13.333,
http://media.example.com/fileSequence52-C.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=53"
#EXTINF:15.0,
http://media.example.com/fileSequence53-A.ts
主要特征:
- 包含
EXT-X-KEY
标签。
上面示例中的 #EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"
加密信息作用于 fileSequence52-A.ts
、fileSequence52-B.ts
、fileSequence52-C.ts
这 3 个切片。
5)一个 BYTERANGE 播放列表:
代码语言:javascript复制#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:4
#EXTINF:9.009,
#EXT-X-BYTERANGE:752320
media.ts
#EXTINF:9.009,
#EXT-X-BYTERANGE:82112@752321
media.ts
#EXTINF:3.003,
#EXT-X-BYTERANGE:69864
media.ts
#EXT-X-ENDLIST
主要特征:
EXT-X-VERSION
标签的值为 4 以上,确保 HLS 支持。- 通过
EXT-X-BYTERANGE
来指定切片偏移量。语法是:#EXT-X-BYTERANGE:length[@offset]
使用 BYTERANGE 播放列表可以不用在服务端存储大量的小切片文件,只通过一个文件再加上文件偏移量信息就可以支持分片。
比如,上面示例的 BYTERANGE 播放列表等价于下面简单的播放列表:
代码语言:javascript复制#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXTINF:9.009,
first.ts
#EXTINF:9.009,
second.ts
#EXTINF:3.003,
third.ts
#EXT-X-ENDLIST
6)一个插播不同格式内容的播放列表:
代码语言:javascript复制#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
ad0.ts
#EXTINF:8.0,
ad1.ts
#EXT-X-DISCONTINUITY
#EXTINF:10.0,
movieA.ts
#EXTINF:10.0,
movieB.ts
主要特征:
- 包含
EXT-X-DISCONTINUITY
标签。
在一些场景下,我们需要在点播或直播中插入其他内容,比如广告,这时候可能这段广告内容的编码格式与原视频的编码格式存在差异,这种差异可能造成客户端播放出问题,这时候就需要告知客户端。这就需要用到 EXT-X-DISCONTINUITY 标签。
7)一个主播放列表:
代码语言:javascript复制#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=1280000,AVERAGE-BANDWIDTH=1000000
http://example.com/low.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2560000,AVERAGE-BANDWIDTH=2000000
http://example.com/mid.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=7680000,AVERAGE-BANDWIDTH=6000000
http://example.com/hi.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS="mp4a.40.5"
http://example.com/audio-only.m3u8
主要特征:
- 包含
EXT-X-STREAM-INF
标签。
上面示例中,通过 3 个不同码率的视频流和 1 个音频流来描述一个内容。
8)I 帧播放列表:
代码语言:javascript复制#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=1280000
low/audio-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=86000,URI="low/iframe.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=2560000
mid/audio-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=150000,URI="mid/iframe.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=7680000
hi/audio-video.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=550000,URI="hi/iframe.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS="mp4a.40.5"
audio-only.m3u8
主要特征:
- 包含
EXT-X-I-FRAME-STREAM-INF
标签。
HLS 是通过主播放列表标签 EXT-X-I-FRAME-STREAM-INF 和媒体播放列表标签 EXT-X-I-FRAMES-ONLY 配合来实现 I 帧播放列表,从而支持视频播放常用的快进和快退功能。
上面的示例是在主播放列表中通过 EXT-X-I-FRAME-STREAM-INF 标签指定 I 帧播放列表,那么对应的 I 帧播放列表内容示例如下:
代码语言:javascript复制#EXTM3U
#EXT-X-VERSION:4
#EXT-X-I-FRAMES-ONLY
...
#EXTINF:4.12,
#EXT-X-BYTERANGE:9400@376
segment1.ts
#EXTINF:3.56,
#EXT-X-BYTERANGE:7144@47000
segment1.ts
#EXTINF:3.82,
#EXT-X-BYTERANGE:10340@1880
segment2.ts
主要特征:
EXT-X-VERSION
标签的值为 4 以上,确保 HLS 支持。- 包含
EXT-X-I-FRAMES-ONLY
标签。
上面的示例是用 EXT-X-BYTERANGE 来指定每个 I 帧对应的数据。这里需要注意的是 EXTINF 表示的时长是当前 I 帧到下一个 I 帧的时长。
9)Alternate Media 主播放列表:
包含多路音频的主播放列表:
代码语言:javascript复制#EXTM3U
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="English",DEFAULT=YES,AUTOSELECT=YES,LANGUAGE="en",URI="main/english-audio.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Deutsch",DEFAULT=NO,AUTOSELECT=YES,LANGUAGE="de",URI="main/german-audio.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Commentary",DEFAULT=NO,AUTOSELECT=NO,LANGUAGE="en",URI="commentary/audio-only.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS="...",AUDIO="aac"
low/video-only.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2560000,CODECS="...",AUDIO="aac"
mid/video-only.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=7680000,CODECS="...",AUDIO="aac"
hi/video-only.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS="mp4a.40.5",AUDIO="aac"
main/english-audio.m3u8
包含多路视频的主播放列表:
代码语言:javascript复制#EXTM3U
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Main",DEFAULT=YES,URI="low/main/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Centerfield",DEFAULT=NO,URI="low/centerfield/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="low",NAME="Dugout",DEFAULT=NO,URI="low/dugout/audio-video.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=1280000,CODECS="...",VIDEO="low"
low/main/audio-video.m3u8
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mid",NAME="Main",DEFAULT=YES,URI="mid/main/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mid",NAME="Centerfield",DEFAULT=NO,URI="mid/centerfield/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="mid",NAME="Dugout",DEFAULT=NO,URI="mid/dugout/audio-video.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=2560000,CODECS="...",VIDEO="mid"
mid/main/audio-video.m3u8
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="hi",NAME="Main",DEFAULT=YES,URI="hi/main/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="hi",NAME="Centerfield",DEFAULT=NO,URI="hi/centerfield/audio-video.m3u8"
#EXT-X-MEDIA:TYPE=VIDEO,GROUP-ID="hi",NAME="Dugout",DEFAULT=NO,URI="hi/dugout/audio-video.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=7680000,CODECS="...",VIDEO="hi"
hi/main/audio-video.m3u8
为了节省空间,其中 CODECS 字段被省略了。
主要特征:
- 包含 EXT-X-MEDIA 标签,来对描述相同资源的流进行分组。
- EXT-X-STREAM-INF 增加了 VIDEO/AUDIO 属性来实现关联分组。
Alternate Media 为 M3U8 提供外挂音频、视频、字幕的能力,可以在不改动已经存在的媒体切片的情况下,为客户端提供新的可选媒体信息。使用 EXT-X-MEDIA 中的 GROUP-ID 字段与 EXT-X-STREAM-INF 中的 AUDIO、VIDEO、SUBTITLES 关联,实现多码率、多音频、多字幕、多视角的视频播放。
10)主播放列表中的会话数据示例:
代码语言:javascript复制#EXT-X-SESSION-DATA:DATA-ID="com.example.lyrics",URI="lyrics.json"
#EXT-X-SESSION-DATA:DATA-ID="com.example.title",LANGUAGE="en",VALUE="This is an example"
#EXT-X-SESSION-DATA:DATA-ID="com.example.title",LANGUAGE="es",VALUE="Este es un ejemplo"
本文参考
1)M3U8 文件示例
https://developer.apple.com/library/archive/technotes/tn2288/_index.html
2)M3U8 文件标准 https://tools.ietf.org/html/rfc8216
3)HLS 协议 https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/HTTPStreamingArchitecture/HTTPStreamingArchitecture.html
(通过上文的介绍,我们了解了 M3U8 媒体封装格式,这是 HLS 协议的基础,在直播和直播回放场景都有应用。我们将在后面继续探讨其他常见的媒体封装格式,敬请期待)