本文对 HLS 协议进行了详细的讲解,由浅入深,一点儿点儿揭开其神秘面纱。
首先我们先使用 ffmepg 对一段视频文件进行切片,视频所在路径:D:\Work\test
切片命令行如下:
ffmpeg -i SampleVideo_1280x720_20mb.mp4 -fflags flush_packets -max_delay 2 -flags -global_header -hls_time 5 -hls_list_size 0 -vcodec libx264 -acodec aac -r 30 -g 60 -y index.m3u8
这个命令是使用FFmpeg工具进行视频转码和分段处理的操作。下面是对每个参数的详细解释:
ffmpeg
: FFmpeg命令行工具的名称,用于处理音视频文件。-i SampleVideo_1280x720_20mb.mp4
: 指定输入文件的路径和文件名。这里的输入文件是名为 “SampleVideo_1280x720_20mb.mp4” 的视频文件。-fflags flush_packets
: 强制立即刷新输出文件的数据包。-max_delay 2
: 设置最大延迟时间为2秒,以确保尽可能快地输出数据。-flags -global_header
: 禁用全局文件头,不将文件头写入每个分段文件。-hls_time 5
: 设置HLS(HTTP Live Streaming)分段的时长为5秒。这将影响生成的.m3u8文件中每个.ts分段文件的时长。-hls_list_size 0
: 设置.m3u8文件中包含的分段列表大小为0,表示将所有分段都包含在.m3u8文件中,而不生成分段列表文件。-vcodec libx264
: 指定使用libx264编码器进行视频编码。-acodec aac
: 指定使用AAC编码器进行音频编码。-r 30
: 设置输出视频的帧率为30帧/秒。-g 60
: 设置关键帧(I帧)之间的间隔为60帧。关键帧是视频编码中的重要帧,可以独立解码,而其他帧则依赖于关键帧进行解码。-y index.m3u8
: 将输出保存为名为"index.m3u8"的文件。这是HLS流的主索引文件,包含了指向各个分段文件的链接。通过执行这个命令,FFmpeg将会对输入的视频文件进行转码和分段处理,并生成一个HLS流的主索引文件(index.m3u8)和一系列分段文件(.ts文件),用于实现视频的流式传输和播放。
在切片过程中,CPU 利用率飙升,这属于正常现象
切片后,可以在目录下看到下面的文件,ffmpeg 将源视频文件切成了 23 个子文件和一个 index.m3u8 文件
上面先有个基本的概念,下面开始我们的主题:HLS
HLS 全称为 HTTP Live Streaming,是苹果公司提出的基于 HTTP 的流媒体网络传输协议。它的工作原理是把整个媒体流分成一个个小的基于 HTTP 的媒体分片来下载,每次只下载一些分片。在开始一个流媒体会话时,客户端会下载一个包含媒体分片的索引文件,即 extended M3U playlist 文件(m3u8),用于寻找可用的媒体分片。
HLS 中,索引文件可以嵌套,一般只有一级索引和二级索引; 媒体流封分片装格式只支持 MPEG-2 传输流(ts)、WebVTT[WebVTT]文件或 Packed Audio 文件。
下图为索引文件(m3u8)和媒体分片(ts)之间的关系图:一级 m3u8 套二级 m3u8,二级 m3u8 描述 ts 分片。
客户端与服务器通过 HTTP 协议进行交互,以两级 m3u8 嵌套为例,客户端先 GET 请求到一级 m3u8,一级 m3u8 里面包含了服务器端可以用于传播的一个或多个不同带宽的 URL,这 URL 可以获取到二级 m3u8;二级 m3u8 包含了多个 ts 分片的 duration 及其 URL, 最后通过这个 URL 下载 ts 分片。
优势:
劣势:
总之,SRS 支持 HLS 主要是作为输出的分发协议,直播以 RTMP+HLS 分发,满总各种应用场景。点播以 HLS 为主。
HLS 协议很大一部分内容即是对 M3U8 文本协议的描述。
M3U8 即播放索引文件,也称为 Playlist,是由多个独立行组成的文本文件,必须通过 URI(.m3u8 或 .m3u)或者 HTTP Content-Type 来识别(application/vnd.apple.mpegurl 或 audio/mpegurl)。
每行由用 \n 或者 \r\n 来标识换行。每一行可以是一个 URI、空白行或是一个 以 # 号开头的字符串。
以 # 开头的是 tag 或者注释,以 #EXT 开头的是 tag, 其余的为注释, 在解析时应该忽略。URI 表示一个 ts 分片地址或是 Playlist 地址。 URI 可以用绝对地址或者相对地址,如果使用相对地址,那么是相对于当前 Playlist 的地址。有些 tag 带有属性值,多个属性用逗号分隔。
常见的 m3u8 文件如下所示:
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=700,000
http://xxx.itv.cmvideo.cn/low.m3u8?channel-id=bstvod&Contentid=4007432528
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1300,000
http://xxx.itv.cmvideo.cn/mid.m3u8?channel-id=bstvod&Contentid=4007432527
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2300,000
http://xxx.itv.cmvideo.cn/high.m3u8?channel-id=bstvod&Contentid=4007432526
bandwidth 指 定 视 频 流 的 比 特 率 , PROGRAM-ID 无 用 无 需 关 注 , 每 一 个 #EXT-X-STREAM-INF 的下一行是二级 index 文件的路径, 可以用相对路径也可以用绝对路径。
例子中用的是相对路径。这个文件中记录了不同比特率视频流的二级 index 文件路径,客户端可以自己判断自己的现行网络带宽,来决定播放哪一个视频流。
也可以在网络带宽变化的时候平滑切换到和带宽匹配的视频流。
#EXTM3U
#EXT-X-VERSION:1
#EXT-X-TARGETDURATION:11
#EXT-X-MEDIA-SEQUENCE:19674922
#EXT-X-PROGRAM-DATE-TIME:2019-03-28T04:33:40Z
#EXTINF:10,
19674922.ts?
#EXT-X-PROGRAM-DATE-TIME:2019-03-28T04:33:50Z
#EXTINF:10,
19674923.ts?
#EXT-X-PROGRAM-DATE-TIME:2019-03-28T04:34:00Z
#EXTINF:10,
19674924.ts?
Attribute Lists :
tag 以 #EXT 开头,主要分为以下几类:
Basic Tags 可以用在 Media Playlist 和 Master Playlist 里面。
每一个 Media Segment 通过一系列的 Media Segment tags 跟一个 URI 来指定。有的 Media Segment tags 只应用于下一个 segment,有的则是应用所有下面的 segments。一个 Media Segment tag 只能出现在 Media Playlist 里面。
Media Playlist tags 描述 Media Playlist 的全局参数。同样地,Media Playlist tags 只能出现在 Media Playlist 里面。
Master Playlist tags 定义 Variant Streams,Renditions 和其他显示的全局参数。Master Playlist tags 只能出现在 Master Playlist 中。
这里的 tags 可以出现在 Media Playlist 或者 Master Playlist 中。但是如果同时出现在同一个 Master Playlist 和 Media Playlist 中时,必须为相同值。
HLS 是提供一个 m3u8 地址:
Apple 的 Safari 浏览器直接就能打开 m3u8 地址, 譬如:http://demo.srs.com/live/livestream.m3u8
Android 不能直接打开, 需要使用 html5 的 video 标签, 然后在浏览器中打开这个页面即可,
譬如:
<video width="640" height="360"
autoplay controls autobuffer
src="http://demo.srs.com/live/livestream.m3u8"
type="application/vnd.apple.mpegurl">
video>
PC:video.js
视频的封装格式是 TS。
视频的编码格式为 H264,音频编码格式为 MP3、 AAC 或者 AC-3。
除了 TS 视频文件本身, 还定义了用来控制播放的 m3u8 文件(文本文件) 。
HLS 的 m3u8,是一个 ts 的列表,也就是告诉客户端或浏览器可以播放这些 ts 文件, 譬如:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:13
#EXT-X-MEDIA-SEQUENCE:430
#EXT-X-PLAYLIST-TYPE:VOD
#EXTINF:11.800
news-430.ts
#EXTINF:10.120
news-431.ts
#EXT-X-DISCONTINUITY
#EXTINF:11.952
news-430.ts
#EXTINF:12.640
news-431.ts
#EXTINF:11.160
news-432.ts
#EXT-X-DISCONTINUITY
#EXTINF:11.751
news-430.ts
#EXTINF:2.040
news-431.ts
#EXT-X-ENDLIST
#EXT-X-PLAYLIST-TYPE:VOD 的意思是当前的视频流并不是一个直播流,而是点播流,换句话说就是该视频的全部的 ts 文件已经被生成好了,#EXT-X-ENDLIST 这个表示视频结束,有这个标志同时也说明当前的流是一个非直播流。
点播 VOD 的特点就是当前时间点可以获取到所有 index 文件和 ts 文件,二级 index 文件中记录了所有 ts 文件的地址。这种模式允许客户端访问全部内容。上面的例子中就是一个点播模式下的 m3u8 的结构。
Live 模式就是实时生成 M3u8 和 ts 文件。它的索引文件一直处于动态变化的,播放的时候需要不断下载二级 index 文件,以获得最新生成的 ts 文件播放视频。如果一个二级 index文件的末尾没有#EXT-X-ENDLIST 标志, 说明它是一个 Live 视频流。
- 客户端在播放 VOD 模式的视频时其实只需要下载一次一级 index 文件和二级 index 文件就可以得到所有 ts 文件的下载地址,除非客户端进行比特率切换,否则无需再下载任何 index文件,只需顺序下载 ts 文件并播放就可以了。
- 但是 Live 模式下略有不同,因为播放的同时,新 ts 文件也在被生成中,所以客户端实际上是下载一次二级 index 文件,然后下载 ts 文件,再下载二级 index 文件(这个时候这个二级 index 文件已经被重写,记录了新生成的 ts 文件的下载地址),再下载新 ts 文件,如此反复进行播放。
ts 文件为传输流文件(MPEG2 - tranport stream),视频编码主要格式 h264/mpeg4,音频为 acc/MP3。
ts 文件分为三层: ts 层(Transport Stream)、 pes 层(Packet Elemental Stream)、 es 层(Elementary Stream)
es 层就是音视频压缩数据,pes 层是在音视频数据 es 上加了时间戳(pts,dts)等对数据帧的说明信息,ts 层就是在 pes 层加入数据流的识别和传输必须的信息。
h.264 视频:打包 h.264 数据我们必须给视频数据加上一个 nalu(Network Abstraction Layer unit),nalu 包括 nalu header 和 nalu type,nalu header 固定为 0x00000001(帧开始)或 0x000001(帧中)。
h.264 的数据是由 slice 组成的, slice 的内容包括:视频、sps、pps 等。
我的qq:2442391036,欢迎交流!