参考链接: juejin.cn/post/684490… juejin.cn/post/685003… segmentfault.com/a/119000002…
- 常见的流媒体协议主要有HTTP渐进下载和基于RTSP/RTP的实时流媒体协议,这两种基本是完全不同的东西。
- 对于视频的在线播放,按视频内容的实时性可以分为点播(VOD)和直播(Live Streaming)。
HLS(HTTP Live Streaming)
HLS是什么?
- 它最初是苹果公司针对iPhone、iPod、iTouch和iPad等移动设备而开发的流,现在在很多桌面也有很多应用,HTML5就直接支持这个。
- HLS 是苹果公司提出的基于HTTP的流媒体网络传输协议。类似于MPEG-DASH,但是HLS更加简洁。
基本原理
-
服务端把文件或者媒体流按照不同的码率切分成一个个小片段进行传输,客户端在播放码流时,可以根据自身的带宽及性能限制,在同一视频内容的不同码率的备用源,选择合适码率的码流进行下载播放。
-
在传输会话开始时,客户端首先需要下载描述不同码流元数据的M3U8索引文件(类似于DASH中的MPD文件)。
-
与基于UDP的RTP协议不同,HLS请求仅使用HTTP传输,因此可以穿过任何允许HTTP数据通过的防火墙或代理服务器。
缺点
- HLS协议的小切片(.ts)方式会生成大量的文件,存储或处理这些文件会造成大量资源浪费。因此,HLS协议对存储I/O要求相当苛刻。
-
新型点播服务器系统,独创了内存缓存数据实时切片技术,颠覆了这种传统实现方法,从根本上解决了大量切片的碎片问题,是的单台服务器的切片与打包能力不再是瓶颈。使用这种技术,使得终端请求数据时直接从服务器的内存中获取,极大提高了对终端数据请求的反应速度,优化了视频观看体验。其基本原理如下:
不将TS切片文件存到磁盘,而是存在内存中。
- 采用HLS直播的视频流延时一般在10秒以上,使用推荐配置时延迟大概在30S,而RTMP直播的延迟最低可达到3/4秒,因此,在对实时性要求较高的场合,如互动直播,就要慎用HLS。
延迟详解
-
HLS并不是一个真正实时的流媒体系统,这是因为对应于媒体分段的大小和持续时间有一定潜在的时间延迟。在客户端,至少在一个分段媒体文件被完全下载后才能够开始播放。而通常要求下载完两个媒体文件之后才开始播放以保证不同分段音视频之间的无缝连接。
-
此外,在客户端开始下载之前,必须等待服务器端的编码器和流分割器至少生成一个TS文件,这也会带来潜在的延迟。
实现方式
- 利用ffmpeg对视频进行压缩和分段处理
- FFmpeg生成m3u8文件对这些分段文件描述和索引
HLS playlist
- 点播(VOD,Video On Demand)playlist
- Event playlist
- 直播playlist(滑动窗口)
- byte-range playlist
- 包含密钥的playlist
- 内嵌广告的playlist
- master playlist
- 包含alternate media的playlist
- l-frame playlist
- 包含session的master playlist
码率控制
码率控制对于在线视频比较重要。因为在线视频需要考虑其能提供的带宽。
- 什么是码率?
bitrate = file size / duration
比如一个文件20.8M,时长1分钟,那么,码率就是:
biterate = 20.8M bit/60s = 20.8*1024*1024*8 bit/60s= 2831Kbps
一般音频的码率只有固定几种,比如是128Kbps,那么,video的就是
video biterate = 2831Kbps -128Kbps = 2703Kbps
- ffmpeg如何控制码率。 ffmpg控制码率有3种选择,-minrate -b:v -maxrate
- -b:v主要是控制平均码率。 比如一个视频源的码率太高了,有10Mbps,文件太大,想把文件弄小一点,但是又不破坏分辨率。
ffmpeg -i input.mp4 -b:v 2000k output.mp4
上面把码率从原码率转成2Mbps码率,这样其实也间接让文件变小了。目测接近一半。 不过,ffmpeg官方wiki比较建议,设置b:v时,同时加上 -bufsize -bufsize 用于设置码率控制缓冲器的大小,设置的好处是,让整体的码率更趋近于希望的值,减少波动。(简单来说,比如1 2的平均值是1.5, 1.49 1.51 也是1.5, 当然是第二种比较好) f
fmpeg -i input.mp4 -b:v 2000k -bufsize 2000k output.mp4
- -minrate -maxrate 在线视频有时候,希望码率波动,不要超过一个阈值,可以设置maxrate。
ffmpeg -i input.mp4 -b:v 2000k -bufsize 2000k -maxrate 2500k output.mp4
参考链接:gist.githubusercontent.com/hsiaosiyuan…
ffmpeg -v verbose -i mv.mp4 -vf scale=640:360 -c:a aac -c:v libx264 -hls_time 10 -hls_playlist_type vod -b:v 400k -maxrate 400k -bufsize 400k -b:a 96k -hls_segment_filename 360p_%03d.ts -f hls 360p.m3u8
上面的命令1G视频(时长约13分钟)切片时间约15分钟, 太慢了,需要优化下,优化如下
# 执行两次命令,比一次命令效率高
# 转换为ts文件
ffmpeg -i 4.mp4 -c copy -bsf:v h264_mp4toannexb 4.ts
# 将ts切片
ffmpeg -i 4.ts -c copy -map 0 -f segment -segment_time 10 -segment_list 4.m3u8 4_%05d.ts
| 参数 | 说明 |
|---|---|
| -v verbose | 与log有关 |
| -i mv.mp4 | 指定输入文件名 |
| scale 简写 -s | 分辨率 |
| -c:a | 指定音频编码器 |
| -c:v | 指定视频编码器 |
| -b:v | 主要控制视频平均码率 (ffmpg控制码率有3种选择,-minrate -b:v -maxrate) |
| -b:a | 音频码率 |
| -bufsize | 码率控制缓冲器的大小 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>hls-demo</title>
<style>
#video {
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<video id="video" width="500" controls></video>
</body>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
var video = document.getElementById('video');
var m3u8 = "http://10.200.137.53:8080/sources/videos/360p.m3u8";
if (Hls.isSupported()) {
var hls = new Hls();
hls.loadSource(m3u8);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, function() {
video.play();
});
} else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = m3u8;
video.addEventListener('loadedmetadata', function() {
video.play();
});
}
</script>
</html>
开源插件
说明:有了m3u8就可以播放了;如果是边切割边播放,当播放超出了目前切割的范围,就呈现视频加载的状态。
数据分段加载的关键
-
以什么策略对数据进行分段 通常情况下会选择将视频按照相同的播放时间分割成一个个小段,比如上面的例子中将视频按10s来分割每一段。
-
对分段的结果进行描述和索引 在HLS协议中,通过m3u8文件对分段的内容进行描述和索引。就如同上面的例子一样,视频的制作者除了需要将视频进行分段以外,还需要生成对这些分段进行描述的m3u8文件,而视频的消费者,只需要得到m3u8文件,就可以灵活的选择分段的加载形式了。
DASH
HTTP Ranges + MP4 + MSE
- 分段加载一段视频数据的能力由HTTP Ranges实现;