• M3U8 格式:为什么直播回放都用这个格式?丨音视频基础


    (本文基本逻辑: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、属性列表

    属性列表是一组可以设置值的特定标签,它们对应的是一个个的键值对,语法如下:

    AttributeName=AttributeValue
    这里的属性名和属性值都不能包含空白字符。属性名允许的字符集是 [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:

    2.3.2、媒体切片标签(Media Segment Tags)

    每个切片 URI 前面都有一组媒体切片标签(Media Segment Tags)对其进行描述。有一些媒体切片标签只对跟在其后的一个媒体切片相关;有的则与其后的所有切片都相关,直到后面遇到另一个该标签的描述。

    媒体切片标签不能出现在主播放列表(Master Playlist)中。

    • EXTINF,表示其后媒体切片的时长(单位为秒)。每个媒体切片之前必须指定该标签。
      • 语法:#EXTINF:,[]</code></li></ul></li><li><code>EXT-X-BYTERANGE</code>,表示指定媒体切片是其后 URI 指定的媒体资源的一部分。 <ul><li>语法:<code>#EXT-X-BYTERANGE:<n>[@<o>]</code></li><li>说明:其中 n 表示字节大小,o 表示起始位置。如果指定了 o 值,则表示对 URI 指定资源从 o 指定的位置开始截取 n 字节;如果 o 未指定,则表示把上一个该标签指定的媒体资源作为目标,将其已截取片段的下一个字节作为起始位置开始再截取 n 字节。如果没有指定该标签,则表明切片范围为整个 URI 指定的媒体资源。该标签兼容的版本是 EXT-X-VERSION 为 4 及以上。</li></ul></li><li><code>EXT-X-DISCONTINUITY</code>,表示其前一个切片和下一个切片之间存在中断。在媒体文件格式、媒体轨道的数量和类型、时间戳序列、编码参数、编码序列的内容发生变化时,需要使用该标签。</li><li><code>EXT-X-KEY</code>,媒体切片是可以加密的,这个标签用来指定解密方法。 <ul><li>语法:<code>#EXT-X-KEY:<attribute-list></code></li><li>说明:一般一个媒体播放列表中会出现 2 个以上的 EXT-X-KEY 标签,一个 EXT-X-KEY 标签作用于包含在它和下一个具有同样 KEYFORMAT 属性值的 EXT-X-KEY 标签之间的所有切片。</li></ul></li><li><code>EXT-X-MAP</code>,指定了如何获取媒体初始化信息(Meida Initialization Section)来解析后续的媒体切片数据。该标签对其后所有切片生效,直到遇到下一个 <code>EXT-X-MAP</code> 标签。 <ul><li><code>URI</code>,这个字段是必须的,该 URI 指向包含媒体初始化信息(Meida Initialization Section)资源。</li><li><code>BYTERANGE</code>,该字段是可选的,表示上面 URI 指向的资源中媒体初始化信息(Meida Initialization Section)的精确字节位置。如果没有该字段,则表示该资源所有的数据都是目标数据。</li><li>语法:<code>#EXT-X-MAP:<attribute-list></code>,这里的属性列表包括如下字段:</li></ul></li><li><code>EXT-X-PROGRAM-DATE-TIME</code>,使用了一个绝对的时间来指定媒体切片第一个采样的时间。这个标签只作用于其后的一个切片。 <ul><li>语法:<code>#EXT-X-PROGRAM-DATE-TIME:<date-time-msec></code></li></ul></li><li><code>EXT-X-DATERANGE</code>,用于将一个时间范围和一组属性关联起来。</li></ul> <p><strong>2.3.3、媒体播放列表标签(Media Playlist Tags)</strong></p> <p>媒体播放列表标签(Media Playlist Tags)主要用来描述全局的媒体信息。</p> <ul><li><code>EXT-X-TARGETDURATION</code>,表示所有媒体切片的最大时长,单位是秒。这个标签是必填的。<code>EXTINF</code> 所指定的各个切片的时长必须不大于这个时长,否则会出现播放卡顿或播放错误。 <ul><li>语法:<code>#EXT-X-TARGETDURATION:<s></code></li></ul></li><li><code>EXT-X-MEDIA-SEQUENCE</code>,表示列表文件中第一个媒体切片的序号。如果没有这个标签,那么表示第一个媒体切片的序号为 0。每个媒体切片都有唯一的序列号,序列号按照出现顺序依次加 1。此外,如果有这个标签,那么这个标签需要放在第一个切片之前。 <ul><li>语法:<code>#EXT-X-MEDIA-SEQUENCE:<number></code></li></ul></li><li><code>EXT-X-DISCONTINUITY-SEQUENCE</code>,该标签用于同步相同流的不同路或者有 EXT-X-DISCONTINUITY 标签的不同备份流。该标签必须出现在第一个切片之前,且必须出现在任何 EXT-X-DISCONTINUITY 标签之前。 <ul><li>语法:<code>#EXT-X-DISCONTINUITY-SEQUENCE:<number></code></li></ul></li><li><code>EXT-X-ENDLIST</code>,表示不会再有更多的切片会添加到播放列表中。该标签可以出现在媒体播放列表的任意位置,一般出现在文件结尾。 <ul><li>语法:<code>#EXT-X-ENDLIST</code></li></ul></li><li><code>EXT-X-PLAYLIST-TYPE</code>,该标签表明了全局播放列表的可变性。这个标签是可选的,作用于整个播放列表。该标签如果被省略,则媒体播放列表是可以修改的。 <ul><li>语法:<code>#EXT-X-PLAYLIST-TYPE:<EVENT|VOD></code></li><li>说明:<code>EVENT</code> 表示可以在播放列表可变,不过只能在尾部添加媒体切片;<code>VOD</code> 表示播放列表不可变。</li></ul></li><li><code>EXT-X-I-FRAMES-ONLY</code>,该标签表示每个媒体切片都是 I 帧。该标签作用于整个播放列表。 <ul><li>语法:<code>#EXT-X-I-FRAMES-ONLY</code></li><li>说明:在包含 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。</li></ul></li></ul> <p><strong>2.3.4、主播放列表标签(Master Playlist Tags)</strong></p> <p>主播放列表标签(Master Playlist Tags)主要用于定义多路流以及其他全局参数。主播放列表标签不能出现在媒体播放列表中。</p> <ul><li><code>EXT-X-MEDIA</code>,该标签用于指定具有相同内容的不同路的流,这些流可能是有不同的音视频参数,或者是对应不同的语言翻译。比如,我们可以通过 3 个 EXT-X-MEDIA 标签来给一个媒体资源分别指定英语、法语、西班牙语的音频内容;我们也可以通过 2 个 EXT-X-MEDIA 标签给一个媒体资源指定两种不同的拍摄视角。 <ul><li><code>TYPE</code>,资源类型。必填字段,可选值有:<code>AUDIO</code>、<code>VIDEO</code>、<code>SUBTITLES</code>、<code>CLOSED-CAPTIONS</code>。一般隐藏式字幕(CLOSED-CAPTIONS)是跟着视频数据的,不会专门指定一路流。</li><li><code>URI</code>,资源地址。可选字段,如果 TYPE 是 CLOSED-CAPTIONS,则不要出现这个字段。</li><li><code>GROUP-ID</code>,分组标识。必填字段,用于指定资源属于哪个组。</li><li><code>LANGUAGE</code>,指定资源主要使用的语言。可选字段。</li><li><code>ASSOC-LANGUAGE</code>,指定资源使用的语言的一个版本,常用来指定语言的书写、方言等特效。可选字段。</li><li><code>NAME</code>,用于填写名字,目的是易读。必填字段。</li><li><code>DEFAULT</code>,表示当前资源是否是默认播放资源。可选字段,默认值是 NO。</li><li><code>AUTOSELECT</code>,可选字段,默认值为 NO。当该值为 YES,当用户没有指定偏好时,则默认播放这个资源。如果有该字段,并且 DEFAULT 值为 YES 时,该值必须为 YES。</li><li><code>FORCED</code>,可续字段,默认值为 NO。只有当 TYPE 值为 SUBTITLES 时,才能出现该字段。当该值为 YES,表示资源中包含了重要的内容,客户端应该从中选择最符合当前播放环境的资源来播放。</li><li><code>INSTREAM-ID</code>,只有当 TYPE 为 CLOSED-CAPTIONS 才出现该字段,且必须出现。</li><li><code>CHARACTERISTICS</code>,可选字段。</li><li><code>CHANNELS</code>,当 TYPE 为 AUDIO,该字段表示音频轨道数。</li><li>语法:<code>#EXT-X-MEDIA:<attribute-list></code>,其中这里的属性列表包括:</li><li>说明:同一组的资源都有同样的 GROUP-ID 和同样的 TYPE,同一组的不同路流必须对应的是统一的内容,否则播放可能会出错。一个播放列表的所有 EXT-X-MEDIA 的 NAME 属性都必须各不相同。同一组中只能有一个 DEFAULT 属性为 YES 的 EXT-X-MEDIA。AUTOSELECT 为 YES 的不同 EXT-X-MEDIA 必须能通过 LANGUAGE、ASSOC-LANGUAGE、FORCED、CHARACTERISTICS 属性组做出区分。</li></ul></li><li><code>EXT-X-STREAM-INF</code>,该标签用于指定媒体资源的具体信息。 <ul><li><code>BANDWIDTH</code>,表示流的最高码率(Peak Segment Bit Rate),包含了所有需要播放的媒体资源的码率加和。必填字段。</li><li><code>AVERAGE-BANDWIDTH</code>,表示流的平均码率。可选字段。</li><li><code>CODECS</code>,表示编码器。应该尽量包含该字段。</li><li><code>RESOLUTION</code>,表示分辨率。可选字段。</li><li><code>FRAME-RATE</code>,表示帧率。可选字段。但是包含视频的资源都应该尽量包含该信息。</li><li><code>HDCP-LEVEL</code>,表示数字内容保护。可选字段。</li><li><code>AUDIO</code>,对应某个 TYPE 为 AUDIO 的 EXT-X-MEDIA 标签的 GROUP-ID 字段。表示音频应该使用对应组的资源。可选字段。</li><li><code>VIDEO</code>,对应某个 TYPE 为 VIDEO 的 EXT-X-MEDIA 标签的 GROUP-ID 字段。表示视频应该使用对应组的资源。可选字段。</li><li><code>SUBTITLES</code>,对应某个 TYPE 为 SUBTITLES 的 EXT-X-MEDIA 标签的 GROUP-ID 字段。表示字幕应该使用对应组的资源。可选字段。</li><li><code>CLOSED-CAPTIONS</code>,对应某个 TYPE 为 CLOSED-CAPTIONS 的 EXT-X-MEDIA 标签的 GROUP-ID 字段。表示隐藏字幕应该使用对应组的资源。可选字段。</li><li>语法:<code>#EXT-X-STREAM-INF:<attribute-list> <URI></code>,URI 是换行。这里的属性列表包括:</li></ul></li><li><code>EXT-X-I-FRAME-STREAM-INF</code>,表示一个包含 I 帧的媒体播放列表。这个标签是独立的,不作用于主播放列表里的其他资源。该标签主要服务于播放时的快进和快退功能。 <ul><li><code>URI</code>,对应一个只包含 I 帧的媒体播放列表。该列表中必须包含 EXT-X-I-FRAMES-ONLY 标签。</li><li>语法:<code>#EXT-X-I-FRAME-STREAM-INF:<attribute-list></code>,属性列表包含了上文所讲的 EXT-X-STREAM-INF 标签除了 FRAME-RATE、AUDIO、SUBTITLES、CLOSED-CAPTIONS 外的各属性,同时再增加下列属性:</li><li>说明:每个 EXT-X-I-FRAME-STREAM-INF 必须包含 BANDWIDTH 和 URI 属性。对于主列表中包含的多路流,则应该对应多路 I 帧媒体播放列表,且为它们设置同样的 NAME 和 LANGUAGE 属性。</li></ul></li><li><code>EXT-X-SESSION-DATA</code>,该标签允许在主播放列表中携带任意的会话数据。 <ul><li><code>DATA-ID</code>,ID 最好遵循类似 <code>com.example.movie.title</code> 格式。必填字段。</li><li><code>VALUE</code>,数据值。VALUE 字段和 URI 字段二选一。</li><li><code>URI</code>,数据地址,应该指向一个 JSON 文件。VALUE 字段和 URI 字段二选一。</li><li><code>LANGUAGE</code>,语言。可选字段。</li><li>语法:<code>#EXT-X-SESSION-DATA:<attribute-list></code>,属性列表包括:</li><li>说明:一个主播放列表可以包含多个有同样 DATA-ID 的 EXT-X-SESSION-DATA 标签,但是不能包含一个以上的有同样 DATA-ID 和 LANGUAGE 的 EXT-X-SESSION-DATA 标签。</li></ul></li><li><code>EXT-X-SESSION-KEY</code>,该标签允许将加密秘钥放在主播放列表中,这样客户端可以预先加载主播放列表类提取获取到加密秘钥,而不用非要加载媒体播放列表来获取。 <ul><li>语法:<code>#EXT-X-SESSION-KEY:<attribute-list></code></li></ul></li></ul> <p><strong>2.3.5、播放列表共用标签(Media or Master Playlist Tags)</strong></p> <p>有一些标签是媒体播放列表和主播放列表中都可以出现的,但是一般一个标签出现在主播放列表,那么就不要再在该主播放列表索引的媒体播放列表中出现了。如果一定要两边都出现,那么标签对应的值必须相同,否则客户端应该忽略媒体播放列表的值,采用主播放列表的值。在同一个播放列表中,这些标签一定不能出现多次。</p> <ul><li><code>EXT-X-INDEPENDENT-SEGMENTS</code>,表明列表中的所有切片都可以独立解码,无需依赖其他切片的信息。 <ul><li>语法:<code>#EXT-X-INDEPENDENT-SEGMENTS</code>。</li><li>说明:如果该标签出现在主播放列表,则适用于主播放列表包含的所有媒体播放列表。</li></ul></li><li><code>EXT-X-START</code>,表明倾向于从哪个时间点开始播放。 <ul><li><code>TIME-OFFSET</code>,表示开始时间偏移,必填字段。如果是正数,则表示距离播放开始时间的偏移,此时如果绝对值超过了视频总时长则表示偏移到结束时间;如果是负数,则表示是距离播放结束时间的偏移,此时如果绝对值超过了视频总时长则表示偏移到开始时间。如果播放列表不包含 EXT-X-ENDLIST 标签,则 TIME-OFFSET 的值不应该在播放列表末尾的 3 个切片的时长之内。</li><li><code>PRECISE</code>,表示是否精确,可选字段。默认是 NO。如果设置该值为 YES,则客户端应该播放时间包含 TIME-OFFSET 的切片,并且不要渲染该切片内时间在 TIME-OFFSET 之前的采样;如果该值为 NO,则渲染切片内所有的采样。</li><li>语法:<code>#EXT-X-START:<attribute-list></code>,属性列表包括:</li></ul></li></ul> <h2 id="3%E3%80%81%E5%AE%9E%E6%88%98%E8%A7%A3%E6%9E%90"><a name="t8"></a><strong>3、实战解析</strong></h2> <p><strong>1)一个点播媒体播放列表:</strong></p> <pre data-index="2"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-PLAYLIST-TYPE:VOD</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-TARGETDURATION:10</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-VERSION:3</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:9.009,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/media.example.com/first</span>.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:9.009,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/media.example.com/second</span>.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:3.003,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/media.example.com/third</span>.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-ENDLIST</span></div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p> M3U8 文件支持绝对路径,也支持相对路径,所以上面的格式等效于:</p> <pre data-index="3"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-PLAYLIST-TYPE:VOD</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-TARGETDURATION:10</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-VERSION:3</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:9.009,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">first.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:9.009,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">second.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:3.003,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">third.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-ENDLIST</span></div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>上面的示例是一个典型的点播媒体播放列表,主要特征是:</p> <ul><li>文件包含 <code>EXT-X-ENDLIST</code> 标签。</li><li><code>EXT-X-PLAYLIST-TYPE</code> 标签(可选)值为 VOD,表示播放列表不可变。</li></ul> <p><strong>2)一个 EVENT 播放列表:</strong></p> <p>刚开始时,对应的 M3U8 文件内容如下所示:</p> <pre data-index="4"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-PLAYLIST-TYPE:EVENT</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-TARGETDURATION:10</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-MEDIA-SEQUENCE:0</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">fileSequence0.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">fileSequence1.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">fileSequence2.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">fileSequence3.ts</div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>EVENT 播放列表的主要特征是:</p> <ul><li><code>EXT-X-PLAYLIST-TYPE</code> 标签值为 EVENT,表示播放列表内容可变,不过只能在文件末尾改变。</li></ul> <p>结束时,M3U8 文件内容如下所示:</p> <pre data-index="5" class="set-code-hide" name="code"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-PLAYLIST-TYPE:EVENT</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-TARGETDURATION:10</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-MEDIA-SEQUENCE:0</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">fileSequence0.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">fileSequence1.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">fileSequence2.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">fileSequence3.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">...</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">fileSequence120.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">fileSequence121.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="18"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-ENDLIST</span></div></div></li></ol></code><div class="hide-preCode-box"><span class="hide-preCode-bt" data-report-view="{"spm":"1001.2101.3001.7365"}"><img class="look-more-preCode contentImg-no-view" src="https://1000bd.com/contentImg/2022/06/27/191644837.png" alt="" title=""></span></div><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>EVENT 播放列表可以用在直播中,通常用于晚会和体育赛事场景,用户一方面可以观看直播,一方面还能做 seek 操作回退到之前的时间点去回放。</p> <p><strong>3)一个直播播放列表:</strong></p> <p>直播过程中某个时间点的 M3U8 文件内容:</p> <pre data-index="6"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-VERSION:3</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-TARGETDURATION:8</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-MEDIA-SEQUENCE:2680</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:7.975,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/priv.example.com/file</span>Sequence2680.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:7.941,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/priv.example.com/file</span>Sequence2681.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:7.975,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/priv.example.com/file</span>Sequence2682.ts</div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>M3U8 文件可以使用 HTTP,也可以使用 HTTPS。</p> <p>直播播放列表的主要特征:</p> <ul><li>不包含 <code>EXT-X-ENDLIST</code> 标签。</li><li>不包含 <code>EXT-X-PLAYLIST-TYPE</code> 标签。</li></ul> <p>直播播放列表是一个会动态更新的 M3U8 文件,服务端会对直播流进行实时转码生成直播流切片,并定期更新 M3U8 文件。这个 M3U8 文件一般为会包括 3-5 个切片。</p> <p>直播播放列表中的任意一个切片的 URI 被移除时,都需要更新 <code>EXT-X-MEDIA-SEQUENCE</code> 标签的值(+1)。移除切片 URI 时必须按顺序,以保证客户端通过更新的 M3U8 文件拿到的是连续的切片数据。</p> <p>当上面的实例更新一个切片后,M3U8 文件内容更新为:</p> <pre data-index="7"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-VERSION:3</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-TARGETDURATION:8</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-MEDIA-SEQUENCE:2681</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:7.941,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/priv.example.com/file</span>Sequence2681.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:7.975,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/priv.example.com/file</span>Sequence2682.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:7.971,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/priv.example.com/file</span>Sequence2683.ts</div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p><strong>4)一个加密的媒体播放列表:</strong></p> <pre data-index="8" class="set-code-hide" name="code"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-VERSION:3</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-MEDIA-SEQUENCE:7794</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-TARGETDURATION:15</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:2.833,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/media.example.com/file</span>Sequence52-A.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:15.0,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/media.example.com/file</span>Sequence52-B.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:13.333,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/media.example.com/file</span>Sequence52-C.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=53"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:15.0,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="18"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/media.example.com/file</span>Sequence53-A.ts</div></div></li></ol></code><div class="hide-preCode-box"><span class="hide-preCode-bt" data-report-view="{"spm":"1001.2101.3001.7365"}"><img class="look-more-preCode contentImg-no-view" src="https://1000bd.com/contentImg/2022/06/27/191644837.png" alt="" title=""></span></div><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>主要特征:</p> <ul><li>包含 <code>EXT-X-KEY</code> 标签。</li></ul> <p>上面示例中的 <code>#EXT-X-KEY:METHOD=AES-128,URI="https://priv.example.com/key.php?r=52"</code> 加密信息作用于 <code>fileSequence52-A.ts</code>、<code>fileSequence52-B.ts</code>、<code>fileSequence52-C.ts</code> 这 3 个切片。</p> <p><strong>5)一个 BYTERANGE 播放列表:</strong></p> <pre data-index="9"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-PLAYLIST-TYPE:VOD</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-TARGETDURATION:10</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-VERSION:4</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:9.009,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-BYTERANGE:752320</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">media.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:9.009,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-BYTERANGE:82112@752321</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">media.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:3.003,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-BYTERANGE:69864</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">media.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-ENDLIST</span></div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>主要特征:</p> <ul><li><code>EXT-X-VERSION</code> 标签的值为 4 以上,确保 HLS 支持。</li><li>通过 <code>EXT-X-BYTERANGE</code> 来指定切片偏移量。语法是:<code>#EXT-X-BYTERANGE:length[@offset]</code></li></ul> <p>使用 BYTERANGE 播放列表可以不用在服务端存储大量的小切片文件,只通过一个文件再加上文件偏移量信息就可以支持分片。</p> <p>比如,上面示例的 BYTERANGE 播放列表等价于下面简单的播放列表:</p> <pre data-index="10"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-PLAYLIST-TYPE:VOD</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-TARGETDURATION:10</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-VERSION:3</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:9.009,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">first.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:9.009,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">second.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:3.003,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">third.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-ENDLIST</span></div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p><strong>6)一个插播不同格式内容的播放列表:</strong></p> <pre data-index="11"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-TARGETDURATION:10</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-VERSION:3</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-MEDIA-SEQUENCE:0</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10.0,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">ad0.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:8.0,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">ad1.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-DISCONTINUITY</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10.0,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">movieA.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:10.0,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">movieB.ts</div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>主要特征:</p> <ul><li>包含 <code>EXT-X-DISCONTINUITY</code> 标签。</li></ul> <p>在一些场景下,我们需要在点播或直播中插入其他内容,比如广告,这时候可能这段广告内容的编码格式与原视频的编码格式存在差异,这种差异可能造成客户端播放出问题,这时候就需要告知客户端。这就需要用到 EXT-X-DISCONTINUITY 标签。</p> <p><strong>7)一个主播放列表:</strong></p> <pre data-index="12"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-STREAM-INF:BANDWIDTH=1280000,AVERAGE-BANDWIDTH=1000000</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/example.com/low</span>.m3u8</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-STREAM-INF:BANDWIDTH=2560000,AVERAGE-BANDWIDTH=2000000</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/example.com/mid</span>.m3u8</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-STREAM-INF:BANDWIDTH=7680000,AVERAGE-BANDWIDTH=6000000</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/example.com/hi</span>.m3u8</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS="mp4a.40.5"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/example.com/audio</span>-only.m3u8</div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>主要特征:</p> <ul><li>包含 <code>EXT-X-STREAM-INF</code> 标签。</li></ul> <p>上面示例中,通过 3 个不同码率的视频流和 1 个音频流来描述一个内容。</p> <p><strong>8)I 帧播放列表:</strong></p> <pre data-index="13"><code class="hljs language-bash"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-STREAM-INF:BANDWIDTH=1280000</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">low/audio-video.m3u8</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=86000,URI="low/iframe.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-STREAM-INF:BANDWIDTH=2560000</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">mid/audio-video.m3u8</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=150000,URI="mid/iframe.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-STREAM-INF:BANDWIDTH=7680000</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">hi/audio-video.m3u8</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=550000,URI="hi/iframe.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-STREAM-INF:BANDWIDTH=65000,CODECS="mp4a.40.5"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">audio-only.m3u8</div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>主要特征:</p> <ul><li>包含 <code>EXT-X-I-FRAME-STREAM-INF</code> 标签。</li></ul> <p>HLS 是通过主播放列表标签 EXT-X-I-FRAME-STREAM-INF 和媒体播放列表标签 EXT-X-I-FRAMES-ONLY 配合来实现 I 帧播放列表,从而支持视频播放常用的快进和快退功能。</p> <p>上面的示例是在主播放列表中通过 EXT-X-I-FRAME-STREAM-INF 标签指定 I 帧播放列表,那么对应的 I 帧播放列表内容示例如下:</p> <pre data-index="14"><code class="hljs language-crystal"><ol class="hljs-ln" style="width:100%"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTM3U</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-VERSION:4</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-I-FRAMES-ONLY</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">...</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:4.12,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-BYTERANGE:9400@376</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">segment1.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:3.56,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-BYTERANGE:7144@47000</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">segment1.ts</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXTINF:3.82,</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-comment">#EXT-X-BYTERANGE:10340@1880</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">segment2.ts</div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>主要特征:</p> <ul><li><code>EXT-X-VERSION</code> 标签的值为 4 以上,确保 HLS 支持。</li><li>包含 <code>EXT-X-I-FRAMES-ONLY</code> 标签。</li></ul> <p>上面的示例是用 EXT-X-BYTERANGE 来指定每个 I 帧对应的数据。这里需要注意的是 EXTINF 表示的时长是当前 I 帧到下一个 I 帧的时长。</p> <p><strong>9)Alternate Media 主播放列表:</strong></p> <p>包含多路音频的主播放列表:</p> <pre data-index="15"><code class="hljs language-sql"><ol class="hljs-ln" style="width:1098px"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXTM3U</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT<span class="hljs-operator">-</span>X<span class="hljs-operator">-</span>MEDIA:TYPE<span class="hljs-operator">=</span>AUDIO,<span class="hljs-keyword">GROUP</span><span class="hljs-operator">-</span>ID<span class="hljs-operator">=</span>"aac",NAME<span class="hljs-operator">=</span>"English",<span class="hljs-keyword">DEFAULT</span><span class="hljs-operator">=</span>YES,AUTOSELECT<span class="hljs-operator">=</span>YES,<span class="hljs-keyword">LANGUAGE</span><span class="hljs-operator">=</span>"en",URI<span class="hljs-operator">=</span>"main/english-audio.m3u8"</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT<span class="hljs-operator">-</span>X<span class="hljs-operator">-</span>MEDIA:TYPE<span class="hljs-operator">=</span>AUDIO,<span class="hljs-keyword">GROUP</span><span class="hljs-operator">-</span>ID<span class="hljs-operator">=</span>"aac",NAME<span class="hljs-operator">=</span>"Deutsch",<span class="hljs-keyword">DEFAULT</span><span class="hljs-operator">=</span><span class="hljs-keyword">NO</span>,AUTOSELECT<span class="hljs-operator">=</span>YES,<span class="hljs-keyword">LANGUAGE</span><span class="hljs-operator">=</span>"de",URI<span class="hljs-operator">=</span>"main/german-audio.m3u8"</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT<span class="hljs-operator">-</span>X<span class="hljs-operator">-</span>MEDIA:TYPE<span class="hljs-operator">=</span>AUDIO,<span class="hljs-keyword">GROUP</span><span class="hljs-operator">-</span>ID<span class="hljs-operator">=</span>"aac",NAME<span class="hljs-operator">=</span>"Commentary",<span class="hljs-keyword">DEFAULT</span><span class="hljs-operator">=</span><span class="hljs-keyword">NO</span>,AUTOSELECT<span class="hljs-operator">=</span><span class="hljs-keyword">NO</span>,<span class="hljs-keyword">LANGUAGE</span><span class="hljs-operator">=</span>"en",URI<span class="hljs-operator">=</span>"commentary/audio-only.m3u8"</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT<span class="hljs-operator">-</span>X<span class="hljs-operator">-</span>STREAM<span class="hljs-operator">-</span>INF:BANDWIDTH<span class="hljs-operator">=</span><span class="hljs-number">1280000</span>,CODECS<span class="hljs-operator">=</span>"...",AUDIO<span class="hljs-operator">=</span>"aac"</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">low<span class="hljs-operator">/</span>video<span class="hljs-operator">-</span>only.m3u8</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT<span class="hljs-operator">-</span>X<span class="hljs-operator">-</span>STREAM<span class="hljs-operator">-</span>INF:BANDWIDTH<span class="hljs-operator">=</span><span class="hljs-number">2560000</span>,CODECS<span class="hljs-operator">=</span>"...",AUDIO<span class="hljs-operator">=</span>"aac"</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">mid<span class="hljs-operator">/</span>video<span class="hljs-operator">-</span>only.m3u8</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT<span class="hljs-operator">-</span>X<span class="hljs-operator">-</span>STREAM<span class="hljs-operator">-</span>INF:BANDWIDTH<span class="hljs-operator">=</span><span class="hljs-number">7680000</span>,CODECS<span class="hljs-operator">=</span>"...",AUDIO<span class="hljs-operator">=</span>"aac"</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">hi<span class="hljs-operator">/</span>video<span class="hljs-operator">-</span>only.m3u8</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT<span class="hljs-operator">-</span>X<span class="hljs-operator">-</span>STREAM<span class="hljs-operator">-</span>INF:BANDWIDTH<span class="hljs-operator">=</span><span class="hljs-number">65000</span>,CODECS<span class="hljs-operator">=</span>"mp4a.40.5",AUDIO<span class="hljs-operator">=</span>"aac"</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">main<span class="hljs-operator">/</span>english<span class="hljs-operator">-</span>audio.m3u8</div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>包含多路视频的主播放列表:</p> <pre data-index="16" class="set-code-hide" name="code"><code class="hljs language-vbnet"><ol class="hljs-ln" style="width:930px"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXTM3U</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-MEDIA:TYPE=VIDEO,<span class="hljs-keyword">GROUP</span>-ID=<span class="hljs-string">"low"</span>,NAME=<span class="hljs-string">"Main"</span>,<span class="hljs-keyword">DEFAULT</span>=YES,URI=<span class="hljs-string">"low/main/audio-video.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-MEDIA:TYPE=VIDEO,<span class="hljs-keyword">GROUP</span>-ID=<span class="hljs-string">"low"</span>,NAME=<span class="hljs-string">"Centerfield"</span>,<span class="hljs-keyword">DEFAULT</span>=NO,URI=<span class="hljs-string">"low/centerfield/audio-video.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-MEDIA:TYPE=VIDEO,<span class="hljs-keyword">GROUP</span>-ID=<span class="hljs-string">"low"</span>,NAME=<span class="hljs-string">"Dugout"</span>,<span class="hljs-keyword">DEFAULT</span>=NO,URI=<span class="hljs-string">"low/dugout/audio-video.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-STREAM-INF:BANDWIDTH=<span class="hljs-number">1280000</span>,CODECS=<span class="hljs-string">"..."</span>,VIDEO=<span class="hljs-string">"low"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">low/main/audio-video.m3u8</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-MEDIA:TYPE=VIDEO,<span class="hljs-keyword">GROUP</span>-ID=<span class="hljs-string">"mid"</span>,NAME=<span class="hljs-string">"Main"</span>,<span class="hljs-keyword">DEFAULT</span>=YES,URI=<span class="hljs-string">"mid/main/audio-video.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-MEDIA:TYPE=VIDEO,<span class="hljs-keyword">GROUP</span>-ID=<span class="hljs-string">"mid"</span>,NAME=<span class="hljs-string">"Centerfield"</span>,<span class="hljs-keyword">DEFAULT</span>=NO,URI=<span class="hljs-string">"mid/centerfield/audio-video.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-MEDIA:TYPE=VIDEO,<span class="hljs-keyword">GROUP</span>-ID=<span class="hljs-string">"mid"</span>,NAME=<span class="hljs-string">"Dugout"</span>,<span class="hljs-keyword">DEFAULT</span>=NO,URI=<span class="hljs-string">"mid/dugout/audio-video.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-STREAM-INF:BANDWIDTH=<span class="hljs-number">2560000</span>,CODECS=<span class="hljs-string">"..."</span>,VIDEO=<span class="hljs-string">"mid"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">mid</span>/main/audio-video.m3u8</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="16"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-MEDIA:TYPE=VIDEO,<span class="hljs-keyword">GROUP</span>-ID=<span class="hljs-string">"hi"</span>,NAME=<span class="hljs-string">"Main"</span>,<span class="hljs-keyword">DEFAULT</span>=YES,URI=<span class="hljs-string">"hi/main/audio-video.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="17"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-MEDIA:TYPE=VIDEO,<span class="hljs-keyword">GROUP</span>-ID=<span class="hljs-string">"hi"</span>,NAME=<span class="hljs-string">"Centerfield"</span>,<span class="hljs-keyword">DEFAULT</span>=NO,URI=<span class="hljs-string">"hi/centerfield/audio-video.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="18"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-MEDIA:TYPE=VIDEO,<span class="hljs-keyword">GROUP</span>-ID=<span class="hljs-string">"hi"</span>,NAME=<span class="hljs-string">"Dugout"</span>,<span class="hljs-keyword">DEFAULT</span>=NO,URI=<span class="hljs-string">"hi/dugout/audio-video.m3u8"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="19"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="20"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT-X-STREAM-INF:BANDWIDTH=<span class="hljs-number">7680000</span>,CODECS=<span class="hljs-string">"..."</span>,VIDEO=<span class="hljs-string">"hi"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="21"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">hi/main/audio-video.m3u8</div></div></li></ol></code><div class="hide-preCode-box"><span class="hide-preCode-bt" data-report-view="{"spm":"1001.2101.3001.7365"}"><img class="look-more-preCode contentImg-no-view" src="https://1000bd.com/contentImg/2022/06/27/191644837.png" alt="" title=""></span></div><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <p>为了节省空间,其中 CODECS 字段被省略了。</p> <p>主要特征:</p> <ul><li>包含 EXT-X-MEDIA 标签,来对描述相同资源的流进行分组。</li><li>EXT-X-STREAM-INF 增加了 VIDEO/AUDIO 属性来实现关联分组。</li></ul> <p>Alternate Media 为 M3U8 提供外挂音频、视频、字幕的能力,可以在不改动已经存在的媒体切片的情况下,为客户端提供新的可选媒体信息。使用 EXT-X-MEDIA 中的 GROUP-ID 字段与 EXT-X-STREAM-INF 中的 AUDIO、VIDEO、SUBTITLES 关联,实现多码率、多音频、多字幕、多视角的视频播放。</p> <p><strong>10)主播放列表中的会话数据示例:</strong></p> <pre data-index="17"><code class="hljs language-sql"><ol class="hljs-ln" style="width:778px"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT<span class="hljs-operator">-</span>X<span class="hljs-operator">-</span>SESSION<span class="hljs-operator">-</span>DATA:DATA<span class="hljs-operator">-</span>ID<span class="hljs-operator">=</span>"com.example.lyrics",URI<span class="hljs-operator">=</span>"lyrics.json"</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT<span class="hljs-operator">-</span>X<span class="hljs-operator">-</span>SESSION<span class="hljs-operator">-</span>DATA:DATA<span class="hljs-operator">-</span>ID<span class="hljs-operator">=</span>"com.example.title",<span class="hljs-keyword">LANGUAGE</span><span class="hljs-operator">=</span>"en",<span class="hljs-keyword">VALUE</span><span class="hljs-operator">=</span>"This is an example"</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">#EXT<span class="hljs-operator">-</span>X<span class="hljs-operator">-</span>SESSION<span class="hljs-operator">-</span>DATA:DATA<span class="hljs-operator">-</span>ID<span class="hljs-operator">=</span>"com.example.title",<span class="hljs-keyword">LANGUAGE</span><span class="hljs-operator">=</span>"es",<span class="hljs-keyword">VALUE</span><span class="hljs-operator">=</span>"Este es un ejemplo"</div></div></li></ol></code><div class="hljs-button signin" data-title="登录后复制" data-report-click="{"spm":"1001.2101.3001.4334"}" onclick="hljs.signin(event)"></div></pre> <h2 id="%E6%9C%AC%E6%96%87%E5%8F%82%E8%80%83"><a name="t9"></a><strong>本文参考</strong></h2> <p>1)M3U8 文件示例</p> <p>https://developer.apple.com/library/archive/technotes/tn2288/_index.html</p> <p>2)M3U8 文件标准 https://tools.ietf.org/html/rfc8216</p> <p>3)HLS 协议 https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/HTTPStreamingArchitecture/HTTPStreamingArchitecture.html</p> <p>通过上文的介绍,我们了解了 M3U8 媒体封装格式,这是 HLS 协议的基础,在直播和直播回放场景都有应用。我们将在后面继续探讨其他常见的媒体封装格式</p> </div> </div> </li> <li class="list-group-item ul-li"> <b>相关阅读:</b><br> <nobr> <a href="/Article/Index/639225">< 今日份知识点:浅述对 “ Vue 插槽 (slot) ” 的理解 以及 插槽的应用场景 ></a> <br /> <a href="/Article/Index/1005428">React 中的语法高亮指南</a> <br /> <a href="/Article/Index/722184">Go语言 接口与类型</a> <br /> <a href="/Article/Index/729064">Pandas数据的导入与导出</a> <br /> <a href="/Article/Index/886867">vue 模板、组件</a> <br /> <a href="/Article/Index/743912">络达开发---串口日志&日志过滤</a> <br /> <a href="/Article/Index/1185523">Kotlin高仿微信-第35篇-支付-二维码收款(二维码)</a> <br /> <a href="/Article/Index/1144805">接口设计与优化</a> <br /> <a href="/Article/Index/638970">PMP考试多少分算通过?</a> <br /> <a href="/Article/Index/1247873">QT转型Visual Studio(qmake项目到cmake项目的移植)</a> <br /> </nobr> </li> <li class="list-group-item from-a mb-2"> 原文地址:https://blog.csdn.net/yinshipin007/article/details/126374290 </li> </ul> </div> <div class="col-lg-4 col-sm-12"> <ul class="list-group" style="word-break:break-all;"> <li class="list-group-item ul-li-bg" aria-current="true"> 最新文章 </li> <li class="list-group-item ul-li"> <nobr> <a href="/Article/Index/1484446">攻防演习之三天拿下官网站群</a> <br /> <a href="/Article/Index/1515268">数据安全治理学习——前期安全规划和安全管理体系建设</a> <br /> <a href="/Article/Index/1759065">企业安全 | 企业内一次钓鱼演练准备过程</a> <br /> <a href="/Article/Index/1485036">内网渗透测试 | Kerberos协议及其部分攻击手法</a> <br /> <a href="/Article/Index/1877332">0day的产生 | 不懂代码的"代码审计"</a> <br /> <a href="/Article/Index/1887576">安装scrcpy-client模块av模块异常,环境问题解决方案</a> <br /> <a href="/Article/Index/1887578">leetcode hot100【LeetCode 279. 完全平方数】java实现</a> <br /> <a href="/Article/Index/1887512">OpenWrt下安装Mosquitto</a> <br /> <a href="/Article/Index/1887520">AnatoMask论文汇总</a> <br /> <a href="/Article/Index/1887496">【AI日记】24.11.01 LangChain、openai api和github copilot</a> <br /> </nobr> </li> </ul> <ul class="list-group pt-2" style="word-break:break-all;"> <li class="list-group-item ul-li-bg" aria-current="true"> 热门文章 </li> <li class="list-group-item ul-li"> <nobr> <a href="/Article/Index/888177">十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!</a> <br /> <a href="/Article/Index/797680">奉劝各位学弟学妹们,该打造你的技术影响力了!</a> <br /> <a href="/Article/Index/888183">五年了,我在 CSDN 的两个一百万。</a> <br /> <a href="/Article/Index/888179">Java俄罗斯方块,老程序员花了一个周末,连接中学年代!</a> <br /> <a href="/Article/Index/797730">面试官都震惊,你这网络基础可以啊!</a> <br /> <a href="/Article/Index/797725">你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法</a> <br /> <a href="/Article/Index/797702">心情不好的时候,用 Python 画棵樱花树送给自己吧</a> <br /> <a href="/Article/Index/797709">通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!</a> <br /> <a href="/Article/Index/797716">13 万字 C 语言从入门到精通保姆级教程2021 年版</a> <br /> <a href="/Article/Index/888192">10行代码集2000张美女图,Python爬虫120例,再上征途</a> <br /> </nobr> </li> </ul> </div> </div> </div> <!-- 主体 --> <!--body结束--> <!--这里是footer模板--> <!--footer--> <nav class="navbar navbar-inverse navbar-fixed-bottom"> <div class="container"> <div class="row"> <div class="col-md-12"> <div class="text-muted center foot-height"> Copyright © 2022 侵权请联系<a href="mailto:2656653265@qq.com">2656653265@qq.com</a>    <a href="https://beian.miit.gov.cn/" target="_blank">京ICP备2022015340号-1</a> </div> <div style="width:300px;margin:0 auto; padding:0px 5px;"> <a href="/regex.html">正则表达式工具</a> <a href="/cron.html">cron表达式工具</a> <a href="/pwdcreator.html">密码生成工具</a> </div> <div style="width:300px;margin:0 auto; padding:5px 0;"> <a target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=11010502049817" style="display:inline-block;text-decoration:none;height:20px;line-height:20px;"> <img src="" style="float:left;" /><p style="float:left;height:20px;line-height:20px;margin: 0px 0px 0px 5px; color:#939393;">京公网安备 11010502049817号</p></a> </div> </div> </div> </div> </nav> <!--footer--> <!--footer模板结束--> <script src="/js/plugins/jquery/jquery.js"></script> <script src="/js/bootstrap.min.js"></script> <!--这里是scripts模板--> <!--scripts模板结束--> </body> </html>