为什么要用流媒体
在一个春光明媚的上午。你正哼着小曲,逛着掘金,突然PM跑过来跟你说,我们网站要酷炫,要有很多动效果,最亮眼的地方就是一个视频 banner。很常见的一个场景对吧,然后就甩给你了一个附件,50mb.mp4,你一脸愁容的跟PM解释这个太大了会大大影响用户体验,能不能小一点,得到的回答 "这个是业务老大指名要的,我也没有办法"。怎么办呢,那只能靠技术来解决问题啦。
什么是HLS(HTTP Live Streaming)
- 它最初是苹果公司针对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。
ffmpeg安装
ffmpeg就是我们要用的视频编辑器(流媒体制作工具)
进入官网,选择需要下载的文件,官方网址:
ffmpeg.org/download.ht…
windows系统下需要下载二进制文件,我选择通过红色框选出进入新的页面下载。
下载完成以后,用winRAR或者任意解压工具解压,然后进入bin文件夹
复制这个路径
然后在电脑搜索里搜"编辑系统环境变量",选择环境变量-系统变量-Path-编辑,添加进去,确定即可。该设置是win10设置,其他的系统可能需要通过";"分割。
检验是否添加成功
win+R 然后输入ffmpeg,就会显示一下内容
如果显示找不到,可以尝试以下方法:
- 将命令行全关掉,重启开启。
- echo %PATH% 查看
- 如果重启命令行也出不来,打印的path也有配置上没有问题,那么可以尝试重启电脑
ffmpeg使用
查看视频文件的元信息,比如编码格式和比特率,可以只使用-i参数。
ffmpeg -i input.mp4
上面命令会输出很多冗余信息,加上-hide_banner参数,可以只显示元信息。
ffmpeg -i input.mp4 -hide_banner
ffmpeg如何控制码率。 ffmpg控制码率有3种选择,-minrate -b:v -maxrate ffmpeg官方比较建议,设置b:v时,同时加上 -bufsize -bufsize 用于设置码率控制缓冲器的大小,设置的好处是,让整体的码率更趋近于希望的值,减少波动。(简单来说,比如1 2的平均值是1.5, 1.49 1.51 也是1.5, 当然是第二种比较好) -minrate -maxrate 在线视频有时候,希望码率波动,不要超过一个阈值,可以设置maxrate。
ffmpeg -i input.mp4 -b:v 2000k -bufsize 2000k -maxrate 2500k output.mp4
视频切割, hls_time为时间,比如我选择10s切一个视频,总共45s就是5个
ffmpeg -v verbose -i output.mp4 -vf scale=1920:1080 -c:a aac -c:v libx264 -hls_time 10 -hls_playlist_type vod -b:v 2000k -maxrate 2500k -bufsize 2000k -b:a 96k -hls_segment_filename 1920p_%03d.ts -f hls 1920p.m3u8
然后引用hls工具,就可以直接在页面上播放你的视频流啦
<!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>
<div>播放视频测试</div>
<video id="video" controls></video>
</body>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
var video = document.getElementById('video');
var m3u8 = "./video/1920p.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>
network也可以看到你的视频流获取啦
参考参数
| 参数 | 说明 |
|---|---|
| -v verbose | 与log有关 |
| -i mv.mp4 | 指定输入文件名 |
| scale 简写 -s | 分辨率 |
| -c:a | 指定音频编码器 |
| -c:v | 指定视频编码器 |
| -b:v | 主要控制视频平均码率 (ffmpg控制码率有3种选择,-minrate -b:v -maxrate) |
| -b:a | 音频码率 |
| -bufsize | 码率控制缓冲器的大小 |
| -hls_time | 切割时间 |
react里使用
react里面使用也很简单,只要安装hls.js,然后
import Hls from 'hls.js';
import { useEffect, useRef } from 'react';
const Video = () => {
const video = useRef<HTMLVideoElement>(null);
useEffect(() => {
if (!video.current) return;
const m3u8 = '/public/1920p.m3u8';
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(m3u8);
hls.attachMedia(video.current);
hls.on(Hls.Events.MANIFEST_PARSED, handleVideoPlay);
} else if (video.current.canPlayType('application/vnd.apple.mpegurl')) {
video.current.src = m3u8;
video.current.addEventListener('loadedmetadata', handleVideoPlay);
}
}, []);
const handleVideoPlay = async () => {
video.current.play();
};
return (
<section
>
<video src="" ref={video}></video>
</section>
);
};
export default Video;