关于大视频video播放的问题以及解决方案(m3u8的播放)

时间:2022-02-04 16:08:17

在HTML5里,提供了<video>标签,可以直接播放视频,video的使用很简单:

<video width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4">
</video>

这基本上能满足大部分用户的需求,但是还是有几个问题需要解决:

(1)大视频的问题。

(2)字幕的问题

(3)清晰度的问题

(4)视频保密问题。

本文将简单的探讨上面几个问题并给出简单的解决方案。

备注:这些问题也是我在制作启明星视频系统时遇到的(演示  http://demo.dotnetcms.org/video ),所以,如果你在开发视频播放,那么本文应该对你有用。

1.大视频问题

当使用video播放视频时,对于大视频最好是分片存储,例如一个500M的视频,以10M为一个视频段,那么可以分为50个片段。播放时,按需加载所需要的视频片段(例如用户拖动滚动条直接到一个部分)。

这里又遇到2个问题:

1.1大文件的上传

大文件上传,这里使用的百度的 WebUploader,百度很好的一个上传组件,可惜已经不再维护,当然国外也有很多开源的大文件上传组件,所以,这个问题不大。

大文件上传的原理也比较简单:HTML5里提供了JS 的 FileReader类,Blob类,利用这个类可以在本地直接读取视频的大小,例如要上传500M的视频,以10M为一个分块,把视频分割为一个为50份,对于每一份利用JQuery的AJAX分别上传到服务器上,等50份上传完后,服务器再把这50分视频合并成一个大文件即可。

在上传时通常需要给每个视频一个编号,例如 file0,file1,file2... file49, 上传完毕后,利用.NET提供的System.IO.File.ReadAllBytes读取这些文件然后合并起来。

                    foreach (var part in files.OrderBy(x => x.Length).ThenBy(x => x))//排一下序,保证从0-N Write
{
var bytes = System.IO.File.ReadAllBytes(part);
fs.Write(bytes, 0, bytes.Length);
bytes = null;
System.IO.File.Delete(part);//删除分块
}

这样,就把本地的500M视频,原封不动的加速上传到服务器暂且命名为 video1.mp4。

1.2大文件分割

当视频播放时,利用的是m3u8进行列表播放(下述),在这里使用了ffmpeg.exe组件,ffmpeg提供了如下命令:

ffmpeg.exe -i a.mp4 -hls_time 30 -hls_list_size 0 -f hls  a.m3u8;

上面代码段里, -i 表示输入(input)  a.mp4,   -hls_time 30 表示每个分块断是30秒, hls_list_size 表示序号是从0开始。  a.m3u8 表示最终生成的文件名。

上面代表的是意思是:用ffmpeg把a.mp4进行分割,每个分段长为30秒,并把分割后的信息存放在a.m3u8里。

执行上述命令后,就可以得到 一些列的 *.ts 文件和一个a.m3u8文件

关于大视频video播放的问题以及解决方案(m3u8的播放)

利用.NET可以通过服务器执行合并操作。

1.3 m3u8

m3u8用来存储视频播放的列表,他的内容类似如下:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:35232
#EXT-X-TARGETDURATION:10
#EXTINF:10.000,
cctv6hd-1549272376000.ts
#EXTINF:10.000,
cctv6hd-1549272386000.ts
#EXTINF:10.000,
cctv6hd-1549272396000.ts
#EXTINF:10.000,
cctv6hd-1549272406000.ts
#EXTINF:10.000,
cctv6hd-1549272416000.ts
#EXTINF:10.000,
cctv6hd-1549272426000.ts

简单的说,m3u8存放的是播放列表,视频以.ts格式存储, ts即"Transport Stream"的缩写。 全称为MPEG2-TS,MPEG2-TS,格式的特点就是要求从视频流的任一片段开始都是可以独立解码的。

不用mp4是因为,如果用mp4,那么在2个分块直接播放时,会出现卡顿。而ts格式可以无缝对接。

你甚至可以设定客户端存储的数量,例如设置为3,当使用手机看到5.ts时,手机开始缓存6.ts ,7.ts, 8.ts, 只有这3个都下载完毕后,才播放,而不用等到整个下完才播放,这样增加了播放的流畅度。(有时候我们看视频时,卡顿时,手机会显示一直在缓冲中,来缓存片段。。。)

m3u8不是<video> 标签的支持的标准格式。换句话说,你使用如下代码是无法播放的

<video width="320" height="240" controls>
<source src="a.m3u8" type=application/x-mpegURL>
</video>

目前国内的有 腾讯的 tcplayerlite和百度的cyberplayer 可以播放m3u8,不过,他们其实都使用videojs这个开源内容,外加一层皮肤。

在我自己开发里,因为不想引入太多的JS,所以直接使用 HLS.JS(HTTP Live Streaming )

当引入hls后,播放视频变的非常简单:

      <video          width="100%"      id="video2"     >     </video> 

                <script>
if (Hls.isSupported()) {
var video2 = document.getElementById('video2');
var hls = new Hls();
hls.loadSource('a.m3u8');
hls.attachMedia(video2);
hls.on(Hls.Events.MANIFEST_PARSED, function () {
video2.play();
});
}
</script>

直接使用       hls.loadSource('a.m3u8');  即可加载播放列表。

1.4 播放清晰度

m3u8指向的是播放列表,他本身不提供多清晰度的问题,通常,你需要利用 ffmpeg.exe 生成不同的清晰度,例如

对于video1.mp3, 你可以生成 video-360.mp4, video-720.mp4和 video-1080.mp4 并生产 多个m3u8

 video-360.m3u8
video-720.m3u8
video-1080.m3u8

当视频播放时,如果用户选择不同的清晰度,加载不同的m3u8.

你也可以根据用户的网速,加载不同的m3u8.

2.字幕问题

(以下内容主要来自张鑫旭的文章)HTML5 Video视频支持支持外挂字幕,文件后缀名是.vtt,称为WebVTT格式,专门的web字幕格式。使用很简单,用一个<track>元素即可,例如:

<video id="video">
<source src="example.mp4" type="video/mp4">
<track src="example.vtt" default>
</video>

只要src属性地址OK,同时有default属性,字幕就会生效。

字幕格式是纯文本格式

WEBVTT
00:00:00.001 --> 00:00:01.000
请把你的锅 00:00:01.001 --> 00:00:03.500
带回你的虾 00:00:03.501 --> 00:00:07.000
请把你的微笑留下…… 00:00:07.501 --> 00:00:10.000
请把你的锅 00:00:10.001 --> 00:00:12.000
带回你的虾 00:00:12.001 --> 00:00:15.000
请把你的微笑留下

<video>标签外挂<track>

<track src="example.vtt" kind="subtitles" label="中文字幕" srclang="zh" default>

而track支持多个字幕,例如:

<track src="example.vtt" kind="subtitles" label="中文字幕" srclang="zh" default>
<track src="example2.vtt" kind="subtitles" label="中文字幕(修正)" srclang="zh">

关于大视频video播放的问题以及解决方案(m3u8的播放)

如果你的视频希望提供中文/英文/日文等多语言版本,利用这个方法,可以解决视频字幕多语言版本的问题。

在youtube上,我们有时候会看到一个视频会提供很多语言版本,如上所述,vtt是一个纯文本格式,利用机器翻译,例如百度翻译,把 vtt翻译上百个版本,挂在在track上,这样

瞬间,让你的视频支持几百个语言,立刻就会高大上。

关于大视频video播放的问题以及解决方案(m3u8的播放)

最后,说一下视频加密,无论你用何种技术,视频最终是要在用户端显示的,所以,视频本身是无法加密的,而作为简单加密主要有2个方法:

(1)createObjectURL

当我们查看部分网站得出视频或者部分图片时,你会发现网址网址是用blob:src开头,这其实是 createObjectURL搞的鬼

有兴趣的朋友可以看看其文档介绍,简单说,他就是把真实的地址隐藏了,当你看video的src看到的是一个虚拟地址。

关于大视频video播放的问题以及解决方案(m3u8的播放)

(3)m3u8 加密

如上所述,m3u8里存放的是一个个 *.ts,对于普通用户来说,就算看到*.ts文件,让他一个个下载ts,估计想死的心都有。所以,我们保护m3u8最核心的是防止工具下载。

一个简单的解决方法是:m3u8加参数或者利用session,例如  a.m3u8?key=xxxxx-xxx-xxx

当使用工具下载视频时,工具因为无法获取key参数,那么就无法获取到a.m3u8。

当然,如果真正想下载m3u8也不是完全没办法,

ffmpeg.exe 这个工具既然提供了video分割为ts功能,自然也提供ts合并为一个完整的video功能。只是对普通人来说比较繁琐罢了。

当然,如果你不想搞这么复杂,使用下面代码就可以了, controlslist="nodownload" 让视频不出现下载,而contextmenu不允许使用右键播放,这应付一般的小白应该足够了。

      <video
id="video2"
controlslist="nodownload"
>
</video> <script>
$('#video').bind('contextmenu',function() { return false; });
</script>

以上内容是我做启明星视频遇到的,你可以查看demo当然还有很多细节要考虑,但是大部分问题都已经解决。