流媒体分发之HLS
什么是流媒体
流媒体(Streaming Media)技术是指将一连串的媒体数据压缩后,以流的方式在网络中分段传送,实现在网络上实时传输影音的一种技术。
以上是网上对于流媒体的定义,其实简单来说,流媒体就是将媒体文件(音频、视频、图片、文本、动画)压缩之后分段从服务器分发到客户端。
采用流媒体技术的优势有哪些
- 实时流传输,可以用来实现直播、点播等功能。
- 节省流量(客户端与服务端),尤其是在播放音视频文件时,不需要下载整个文件,当获取到首片文件即可开始播放,并且分片文件的体积往往是非常小的。
- 适用文件类型广,支持的服务器多。
流媒体的分发协议 RTMP与HLS
RTMP
RMP协议是Real Time Message Protocol(实时信息传输协议)的缩写,它是由Adobe公司提出的一种应用层的协议,用来解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题。RTMP协议是应用层协议,是要靠底层可靠的传输层协议(通常是TCP)来保证信息传输的可靠性的。在基于传输层协议的链接建立完成后,RTMP协议也要客户端和服务器通过“握手”来建立基于传输层链接之上的RTMP Connection链接,在Connection链接上会传输一些控制信息,如SetChunkSize,SetACKWindowSize。
HLS
HTTP Live Streaming(缩写是HLS)是一个由Apple提出的基于HTTP的流媒体网络传输协议。是苹果公司QuickTime X和iPhone软件系统的一部分。它的工作原理是把整个流分成一个个小的基于HTTP的文件来下载,每次只下载一些。当媒体流正在播放时,客户端可以选择从许多不同的备用源中以不同的速率下载同样的资源,允许流媒体会话适应不同的数据速率。在开始一个流媒体会话时,客户端会下载一个包含元数据的extended M3U (m3u8)playlist文件,用于寻找可用的媒体流。
HLS协议的文件系统:
- 视频的封装格式是TS。
- 视频的编码格式为H264,音频编码格式为MP3、AAC或者AC-3。
- 除了TS视频文件本身,还定义了用来控制播放的m3u8文件(文本文件,可以理解为索引文件或目录)
RTMP与HLS的对比
- RTMP将一整条数据流封装成FLV进行传输,在服务器不会有落地文件
- RTMP基于TCP长连接,不需要多次建连,实时性好,延时通常为 1-3s
- RTMP协议比起HTTP复杂很多,导致性能下降
- HLS提前将媒体文件压缩、分片、存储在服务器上,并生成M3U8索引文件
- HLS需要拉取M3U8文件中的分片文件,实时性差,延时通常在10S以内
- HLS内容发布服务更简单,对系统设备要求较低,更容易实现负载均衡,并且HLS是无状态协议的HTTP,客户端只需要下载即可
总结一下: 直播建议用RTMP,点播建议用HLS
HLS文件分片
我们使用目前使用较为普遍的ffmpeg工具包进行文件的分片操作。
ffmpeg分片
1.hls方式
ffmpeg -i input_file -c:a aac -hls_time 10 -hls_list_size 0 -strict -2 -f hls out.m3u8
示例:
ffmpeg -i NUMB.flac -c:a aac -hls_time 10 -hls_list_size 0 -strict -2 -f hls NUMB.m3u8
2.segment方式
ffmpeg -i input_file -map 0 -codec:v libx264 -codec:a aac -f ssegment -segment_list out.m3u8 -segment_time 10 out%03d.ts
示例:
ffmpeg -i NUMB.flac -map 0 -codec:v libx264 -codec:a aac -f ssegment -segment_list NUMB.m3u8 -segment_time 10 NUMB%03d.ts
M3U8文件
我们使用文本编辑器打开一个M3U8文件,里面包含了索引文件的声明、版本、切片文件的时长控制、切片文件列表、切片长度等信息
- #EXTM3U:每个M3U文件第一行必须是这个tag。
- #EXT-X-VERSION此属性可用可不用。
- #EXT-X-TARGETDURATION定义每个TS的最大duration。
- #EXT-X-ALLOW-CACHE是否允许cache。
- #EXT-X-MEDIA-SEQUENCE定义当前M3U8文件中第一个文件的序列号,每个ts文件在M3U8文件中都- 有固定唯一的序列号,该序列号用于在MBR时切换码率进行对齐。
- #EXT-X-KEY定义加密方式,用来加密的密钥文件key的URL,加密方法(例如AES-128),以及IV加密向量。
- #EXT-X-DISCONTINUITY当遇到该tag的时候说明这些属性发生了变化,例如file format,加密方式等。
- #EXTINF:指定每个媒体段(ts文件)的持续时间,这个仅对其后面的TS链接有效,每两个媒体段(ts文件)间被这个tag分隔开。其格式可以是#EXTINF:,duration表示持续的时间(秒),如果协议版本小于3则duration必须为整数,否则可以是浮点数。
- #EXT-X-ENDLIST表明M3U8文件的结束。live m3u8没有此tag。
- #EXT-X-STREAM-INF不同带宽适配的不同码率的视频列表路径。其有一个主要参数BANDWIDTH表示每个媒体文件比特速率的上限,单位为每秒bit数。
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.007800,
index0.ts
#EXTINF:10.007800,
index1.ts
#EXTINF:9.984589,
index2.ts
#EXTINF:10.007800,
index3.ts
#EXTINF:10.007800,
index4.ts
#EXTINF:9.984578,
index5.ts
#EXTINF:10.007800,
index6.ts
#EXTINF:10.007800,
index7.ts
#EXTINF:9.984578,
index8.ts
#EXTINF:10.007800,
index9.ts
#EXTINF:10.007800,
index10.ts
#EXTINF:9.984589,
index11.ts
#EXTINF:10.007800,
index12.ts
#EXTINF:10.007800,
index13.ts
#EXTINF:9.984578,
index14.ts
#EXTINF:10.007800,
index15.ts
#EXTINF:10.007800,
index16.ts
#EXTINF:9.984578,
index17.ts
#EXTINF:10.007800,
index18.ts
#EXTINF:10.007800,
index19.ts
#EXTINF:9.984578,
index20.ts
#EXTINF:10.007811,
index21.ts
#EXTINF:10.007800,
index22.ts
#EXTINF:9.984578,
index23.ts
#EXTINF:10.007800,
index24.ts
#EXTINF:10.007800,
index25.ts
#EXTINF:9.984578,
index26.ts
#EXTINF:10.007800,
index27.ts
#EXTINF:4.229844,
index28.ts
#EXT-X-ENDLIST
M3U8文件播放
1.本地播放
可以选择相应的视频音频播放器直接打开m3u8文件即可,这里因为电脑上恰好有PotPlayer播放器,因此以PotPlayer播放器为例。
2.网络播放
使用支持m3u8流的播放器、在线播放器、甚至浏览器地址栏可以直接播放m3u8文件链接。
HLS由Apple开发,所以apple的设备原生支持,之后Android等平台也陆续进行了支持。
示例:
这里将一个mp4视频文件切片后,将m3u8与ts文件上传到我的七牛云,之后获取远程地址通过浏览器在线播放。
第一个文件是m3u8文件,以下为ts切片文件。
①在safari中可以直接播放
②在网络播放器播放(可以很明显看到只加载了第一段视频即可播放)
③在本地浏览器直接播放
拓展: 实现自己的m3u8浏览器播放器
这里使用video来进行实现,新版本的video.js 7之后版本不需要依赖hls组件也可以支持m3u8文件
附上DEMO源码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="/css/video-js.min.css" rel="stylesheet">
<script src="/js/video.min.js"></script>
<title>M3U8在线播放器</title>
<style type="text/css">
#videoDiv {
text-align: center;
}
</style>
</head>
<body>
<div id="videoDiv">
<video id="myVideo" class="video-js" controls autoplay preload="auto" width="848" height="480" data-setup="{}">
<source
src="http://image.xxxxxxxxx.com/00C26348C70BF56886B1809A16157003/00C26348C70BF56886B1809A16157003.m3u8"
type="application/x-mpegURL" />
</video>
</div>
</body>
</html>
运行效果:
PS: 有兴趣的同学可以到ffmpeg详细了解https://www.ffmpeg.org/ffmpeg-formats.html#Options-10