偶然间接触到直播,才得以了解以 m3u8 后缀的文件格式,用一句话来说,刚入门 web 开发的同学做视频网站可能会误用 video 标签,就好像下面的代码。
<video src="https://xxxx.mp4"></video>
为什么说是误用呢?因为当 mp4 格式的文件一大,我们必须要在前端加载完整个文件才能进行下一步的播放。
其实我们能发现,所有视频网站都不是这么整的,如果打开 F12 调试窗口去几个视频网站,我们会发现许多都是使以 m3u8 形式的后缀链接。
这大概是个什么情况呢?我后续直接动手一探究竟。
先来看看 m3u8 文件中的内容,如下所示

我们可以看红色方框圈出来的部分,会发现这里有很多为 out00x.ts 形式的内容。
其实这 .ts 是大视频切分出来的视频分片。
这是一条 linux 命令展示的图片

图中我们将 1.mp4 这个文件使用工具拆分成 out000.ts - out012.ts 的分片,最后用 out.m3u8 文件去索引这些分片。这么说你可能就稍微有点理解了吧?
假设该视频的长度为 2 分钟,那么这12个.ts后缀的分片,每一个分片占据的视频长度就是 2*60/12=10秒。
而我们在 video 标签中使用的 m3u8 就代表着这12个文件的索引(如下图所示)

当视频播放时,他会自动取请求该视频分片。如下图所示

但是怎么将mp4转换成m3u8呢?此时就引出了 ffmpeg 软件
在 linux 下安装该转换软件,并执行以下命令
ffmpeg -i 这里填写MP4文件名.mp4 -c:v libx264 -c:a aac -strict -2 -f hls -hls_list_size 2 -hls_time 15 填写输出的m3u8名字可自行更改.m3u8
他就将文件转成了 m3u8 格式的
例如我是这样执行的
ffmpeg -i 1.mp4 -c:v libx264 -c:a aac -strict -2 -f hls -hls_list_size 0 -hls_time 15 out.m3u8
所以在文件下就生成了

最后启动 Web 服务,挂载静态目录即可。
还有要提的是,浏览器自带的 video 标签本身不支持 .m3u8 文件的播放,因此一般情况下我们都是用第三方的 video.js 库。
前端测试代码如下
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>前端播放m3u8格式视频</title>
<!--https://www.bootcdn.cn/video.js/-->
<link href="https://cdn.bootcss.com/video.js/7.6.5/alt/video-js-cdn.min.css" rel="stylesheet">
<script src="https://cdn.bootcss.com/video.js/6.6.2/video.js"></script>
<!--https://www.bootcdn.cn/videojs-contrib-hls/-->
<script src="https://cdn.bootcss.com/videojs-contrib-hls/5.15.0/videojs-contrib-hls.min.js"></script>
</head>
<body>
<video id="myVideo" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto" width="1080" height="708" data-setup='{}'>
<source id="source" src="http://121.5.62.93:9090/out.m3u8" type="application/x-mpegURL">
</video>
</body>
<script>
// videojs 简单使用
var myVideo = videojs('myVideo',{
bigPlayButton : true,
textTrackDisplay : false,
posterImage: false,
errorDisplay : false,
})
myVideo.play() // 视频播放
myVideo.pause() // 视频暂停
</script>
</html>
后端Go web 服务代码如下
func main () {
// 挂载目录
const dir = "/usr/local/workspace/test/oss"
const port = 9090
http.Handle( "/" , addHeaders(http.FileServer(http.Dir(dir))))
// 启动服务
log.Fatal(http.ListenAndServe(fmt.Sprintf( ":%v" , port), nil ))
}
// addHeaders 解决跨域
func addHeaders (h http.Handler) http.HandlerFunc {
return func (w http.ResponseWriter, r *http.Request) {
w.Header().Set( "Access-Control-Allow-Origin" , "*" )
h.ServeHTTP(w, r)
}
}
© 著作权归作者所有
文章评论(0)